【ZZ】使用Displacement Map Filter创建静态的扭曲效果
2010-01-27 09:53
330 查看
Create a Static Distortion Effect Using the Displacement Map Filter
I’ma freelance designer specializing in motion graphics and interactive
design. When I’m not working on client projects I make games over at The Pencil Farm
.
Final Result Preview
Let's take a look at the final result we will be working towards:Step 1: About Displacement Mapping
Adisplacement map works by using the color values from one image to
alter the position of pixels in another image. This effect is often
used to make a flat graphic 'wrap' around a dimensional image. We're
going to use it here to distort a button so it looks like it's
receiving static interference.
You can read more about displacement mapping here
.
Step 2: Set up Your Flash File
Createa new Flash file (ActionScript 3).Your movie settings will vary
depending on your game. For this demo I'm setting up my movie as
500x300, black background, and 30 fps.
Step 3: Create a Simple Button
Createa new Button symbol on the stage (Insert > New Symbol). Design the 4
states for your button. The exact design should be something that
matches your game. Something glowy and semi-transparent works well with
this effect.
I used a font called Genetrix Square
for mine, but you should use something that matches the look of your game.
Give your button an instance name of 'button1'.
Step 4: Test
Ifyou save and test your movie (Control > Test Movie) now you should
see your button on the stage responding to the mouse with the rollover
states you designed. Like this:
Step 5: Create the JitteryButton Class
Weneed to add custom functionality to our button. We'll accomplish this
by creating a new custom class and putting our simple button inside it.
Create
a new ActionScript file named 'JitteryButton.as'. Save this file in the
same directory as your main Flash file. Add this code to create the
wrapper for our button:
view plain
copy to clipboard
?
package
{
import
flash.display.Sprite;
import
flash.display.SimpleButton;
public
class
JitteryButton
extends
Sprite {
private
var
myButton:SimpleButton;
// holds the reference to our simple button
// CLASS CONSTRUCTOR
public
function
JitteryButton(button:SimpleButton) {
myButton = button; // the button on the stage gets passed in
}
}
package { import flash.display.Sprite; import flash.display.SimpleButton; public class JitteryButton extends Sprite { private var myButton:SimpleButton; // holds the reference to our simple button // CLASS CONSTRUCTOR public function JitteryButton(button:SimpleButton) { myButton = button; // the button on the stage gets passed in } }
All this code does so far is accept the simple button and store a reference to it. We'll add more functionality later.
Step 6: Create the Game Class
Createa new ActionScript file named 'Game.as'. This will be the document
class for our movie. Save it in the same directory as the main Flash
file.This code will add our custom button wrapper around the button on
the stage:
view plain
copy to clipboard
?
package
{
import
flash.display.MovieClip;
public
class
Game
extends
MovieClip {
private
var
startButton:JitteryButton;
// CLASS CONSTRUCTOR
public
function
Game() {
// create the jittery button from the simple button on the stage
startButton = new
JitteryButton(button1);
// add the new button to the stage
addChild(startButton);
}
}
}
package { import flash.display.MovieClip; public class Game extends MovieClip { private var startButton:JitteryButton; // CLASS CONSTRUCTOR public function Game() { // create the jittery button from the simple button on the stage startButton = new JitteryButton(button1); // add the new button to the stage addChild(startButton); } } }
This code creates a new instance of our custom JitteryButton class and passes it the button on the stage ('button1').
Of
course your document class will end up looking much different since it
will have the code for your game in it. Here we're just concerned with
the code for our button.
Back inside your Flash file set the document class to 'Game'. Remember, you don't include the file extension here.
Step 7: Test Again
Ifyou save and test your movie again at this point you should see exactly
the same thing as when we tested in Step 4. The only difference is that
now our code is set up to be able to add our custom behavior.
Step 8: Create the Displacement Map Image
We'll now create the image of the static pattern that we'll use to distort our button graphic.Open
Photoshop and create a new image filled with neutral grey (#808080).
The image should be slightly wider than your button and about 3 or 4
times as high. My button is 277x56, and my image is 310x220.
We're starting with a neutral grey because that won't effect our image.
Step 9: Add Noise
We'llnow add a little bit of noise to our image. This won't be very
noticeable in our static effect, but it gives it a bit of extra
shimmer. You can skip this step if you like.
Duplicate the
background layer and name the new layer 'Noise'. You should now have 2
layers filled with neutral grey. Select the new Noise layer and choose
Filter > Noise > Add Noise. Set Amount
to 120% and Distribution
to Uniform. Check Monochromatic.
Hit OK.
Set the 'Noise' layer to 10% opacity.
Step 10: Add Lines
Create a new layer called 'Lines'. Now use a 1px pencil brush to add some horizontal black and grey lines to the image.Remember
how these lines will effect our image: anything darker than neutral
will shift our image in one direction and anything lighter will shift
it in the other.
Step 11: Save the Displacement Map Image
Choose File > Save for Web & Devices and save your image as an 8 color gif named 'staticMap.gif'.Step 12:
Backin Flash, import the 'staticMap.gif' to your library (File > Import
> Import to Library...). Open the linkage properties, check Export for ActionScript
, and set the Class name to 'StaticMap'.
We can now reference this image in our code by using the StaticMap class name.
Step 13: Create the Displacement Map Filter
Add this function to your JitteryButton class:view plain
copy to clipboard
?
// create the displacement map filter
private
function
createDMFilter():DisplacementMapFilter {
var
mapBitmap:BitmapData =
new
StaticMap(0,0);
// use the bitmap data from our StaticMap image
var
mapPoint:Point =
new
Point(0, 0);
// position of the StaticMap image in relation to our button
var
channels:uint = BitmapDataChannel.RED;
// which color to use for displacement
var
componentX:uint = channels;
var
componentY:uint = channels;
var
scaleX:Number = 5;
// the amount of horizontal shift
var
scaleY:Number = 1;
// the amount of vertical shift
var
mode:String = DisplacementMapFilterMode.COLOR;
var
color:uint = 0;
var
alpha:Number = 0;
return
new
DisplacementMapFilter(
mapBitmap,
mapPoint,
componentX,
componentY,
scaleX,
scaleY,
mode,
color,
alpha );
}
// create the displacement map filter private function createDMFilter():DisplacementMapFilter { var mapBitmap:BitmapData = new StaticMap(0,0); // use the bitmap data from our StaticMap image var mapPoint:Point = new Point(0, 0); // position of the StaticMap image in relation to our button var channels:uint = BitmapDataChannel.RED; // which color to use for displacement var componentX:uint = channels; var componentY:uint = channels; var scaleX:Number = 5; // the amount of horizontal shift var scaleY:Number = 1; // the amount of vertical shift var mode:String = DisplacementMapFilterMode.COLOR; var color:uint = 0; var alpha:Number = 0; return new DisplacementMapFilter( mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY, mode, color, alpha ); }
This function simply creates the Displacement Map Filter using
the BitmapData from our StaticMap image. This doesn't need to be in
it's own function, I'm just doing it for clarity.
In order for it to work we'll need to import these classes at the top of our JitteryButton class:
view plain
copy to clipboard
?
import
flash.display.BitmapData;
import
flash.display.BitmapDataChannel;
import
flash.filters.DisplacementMapFilter;
import
flash.filters.DisplacementMapFilterMode;
import
flash.geom.Point;
import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.Point;
(You can learn more about the DisplacementMapFilter class in the AS3 documentation
)
Step 14: Apply the Filter
We'llnow create a variable to hold the filter. We apply it to the button by
setting the button's 'filters' property to an array that contains our
filter.
Here's the JitteryButton class so far (lines 18 and 25 are new):
view plain
copy to clipboard
?
package
{
import
flash.display.Sprite;
import
flash.display.SimpleButton;
import
flash.display.BitmapData;
import
flash.display.BitmapDataChannel;
import
flash.filters.DisplacementMapFilter;
import
flash.filters.DisplacementMapFilterMode;
import
flash.geom.Point;
import
caurina.transitions.Tweener;
public
class
JitteryButton
extends
Sprite{
private
var
myButton:SimpleButton;
//create a variable to hold the displacement map filter
private
var
dmFilter:DisplacementMapFilter = createDMFilter();
// CLASS CONSTRUCTOR
public
function
JitteryButton(button:SimpleButton) {
myButton = button;
// apply the filter to the button
myButton.filters = new
Array(dmFilter);
}
// create the displacement map filter
private
function
createDMFilter():DisplacementMapFilter {
var
mapBitmap:BitmapData =
new
StaticMap(0,0);
// use the bitmap data from our StaticMap image
var
mapPoint:Point =
new
Point(0, 0);
// this is the position of the StaticMap image in relation to our button
var
channels:uint = BitmapDataChannel.RED;
// which color to use for displacement
var
componentX:uint = channels;
var
componentY:uint = channels;
var
scaleX:Number = 5;
// the amount of horizontal shift
var
scaleY:Number = 1;
// the amount of vertical shift
var
mode:String = DisplacementMapFilterMode.COLOR;
var
color:uint = 0;
var
alpha:Number = 0;
return
new
DisplacementMapFilter(
mapBitmap,
mapPoint,
componentX,
componentY,
scaleX,
scaleY,
mode,
color,
alpha );
}
}
}
package { import flash.display.Sprite; import flash.display.SimpleButton; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.filters.DisplacementMapFilter; import flash.filters.DisplacementMapFilterMode; import flash.geom.Point; import caurina.transitions.Tweener; public class JitteryButton extends Sprite{ private var myButton:SimpleButton; //create a variable to hold the displacement map filter private var dmFilter:DisplacementMapFilter = createDMFilter(); // CLASS CONSTRUCTOR public function JitteryButton(button:SimpleButton) { myButton = button; // apply the filter to the button myButton.filters = new Array(dmFilter); } // create the displacement map filter private function createDMFilter():DisplacementMapFilter { var mapBitmap:BitmapData = new StaticMap(0,0); // use the bitmap data from our StaticMap image var mapPoint:Point = new Point(0, 0); // this is the position of the StaticMap image in relation to our button var channels:uint = BitmapDataChannel.RED; // which color to use for displacement var componentX:uint = channels; var componentY:uint = channels; var scaleX:Number = 5; // the amount of horizontal shift var scaleY:Number = 1; // the amount of vertical shift var mode:String = DisplacementMapFilterMode.COLOR; var color:uint = 0; var alpha:Number = 0; return new DisplacementMapFilter( mapBitmap, mapPoint, componentX, componentY, scaleX, scaleY, mode, color, alpha ); } } }
Step 15: Test Again
If we save and test the file now we can see the displacement map filter being applied to our button:You
can see how the horizontal lines we drew in the StaticMap are shifting
the pixels in our button left and right. The amount of the shift is
dependent on the darkness of the lines in the image and the scaleX
setting in our Displacement Map Filter.
Unfortunately, the static isn't animating so it looks pretty lame. Let's fix that now...
Step 16: Add the randRange Function
This is a simple function that returns a random integer within a specified range:view plain
copy to clipboard
?
// returns a random number between the specified range (inclusive)
private
function
randRange(min:
int
, max:
int
):
int
{
var
randomNum:
int
= Math.floor(Math.random() * (max - min + 1)) + min;
return
randomNum;
}
// returns a random number between the specified range (inclusive) private function randRange(min:int, max:int):int { var randomNum:int = Math.floor(Math.random() * (max - min + 1)) + min; return randomNum; }
I find it makes it a little easier to generate random values.
We'll be randomizing a few different values for our static effect so it
will come in handy.
Add it to your JitteryButton class.
Step 17: Animate the Displacement Map Filter
Thereare a couple of ways we can animate the static effect. The first will
be to alter the amount of horizontal shift applied to our button. This
is done through the scaleX property of the DisplacementMapFilter.
We
can also animate the position of the StaticMap image in relation to our
button. This will ensure that the same areas of the button aren't
always getting shifted.
To animate the effect we'll add a
function called 'displayStatic' that gets called every frame to update
these two properties of the filter. Add this function to your
JitteryButton class:
view plain
copy to clipboard
?
// called on ENTER_FRAME
private
function
displayStatic(e:Event):
void
{
dmFilter.scaleX = randRange(fuzzMin, fuzzMax);
dmFilter.mapPoint = new
Point(0, randRange(0, -160));
myButton.filters = new
Array(dmFilter);
}
// called on ENTER_FRAME private function displayStatic(e:Event):void { dmFilter.scaleX = randRange(fuzzMin, fuzzMax); dmFilter.mapPoint = new Point(0, randRange(0, -160)); myButton.filters = new Array(dmFilter); }
The first line of this function randomizes the amount of
horizontal shifting to a value between the variables fuzzMin and
fuzzMax. Add these two variables to your JitteryButton class:
view plain
copy to clipboard
?
private
var
fuzzMin:
int
= 0;
private
var
fuzzMax:
int
= 2;
private var fuzzMin:int = 0; private var fuzzMax:int = 2;
The second line of the displayStatic function randomizes the Y
position of the StaticMap in relation to our button. We already told
the filter to use our StaticMap image so we just need to update the
position.
The third line just re-applies the filter to our button.
The
last thing we need to do to get this animating is to add the
ENTER_FRAME event listener. Add this line to the JitteryButton
constructor function:
view plain
copy to clipboard
?
// start displaying the static effect
addEventListener(Event.ENTER_FRAME, displayStatic);
// start displaying the static effect addEventListener(Event.ENTER_FRAME, displayStatic);
And don't forget to import the Event class at the top of the JitteryButton file:
view plain
copy to clipboard
?
import
flash.events.Event;
import flash.events.Event;
Step 18: Test Again
If you save and test the movie now you'll see the effect is making our button shimmer and jump:That's pretty cool, but we want the effect to react to the mouse as well. Onward...
Step 19: Adjust the Intensity of the Effect
We'llnow add two functions to adjust the intensity of the jitter effect.
We'll call the effect we currently have Low intensity so we'll add a
setting for Medium and High intensity. Add these functions to your
JitteryButton class:
view plain
copy to clipboard
?
// increase the intensity of the static to MEDIUM
private
function
setStaticMedium(e:MouseEvent =
null
):
void
{
fuzzMin = 2;
fuzzMax = 6;
staticLength = randRange(8, 12);
}
// increase the intensity of the static to HIGH
private
function
setStaticHigh(e:MouseEvent =
null
):
void
{
fuzzMin = 12;
fuzzMax = 25;
staticLength = 12;
}
// increase the intensity of the static to MEDIUM private function setStaticMedium(e:MouseEvent = null):void { fuzzMin = 2; fuzzMax = 6; staticLength = randRange(8, 12); } // increase the intensity of the static to HIGH private function setStaticHigh(e:MouseEvent = null):void { fuzzMin = 12; fuzzMax = 25; staticLength = 12; }
You can see that we're adjusting the intensity by setting the
values of the fuzzMin and fuzzMax variables. This way our displayStatic
function will use these new values when it sets the horizontal shift of
the filter.
We also added a variable called staticLength. We'll
use this to set how long the more intense effect should last (the
number of frames) before returning to low intensity. Add this variable
to your JitteryButton class and modify your displayStatic function like
so:
view plain
copy to clipboard
?
private
var
staticLength:
int
;
// called on ENTER_FRAME
private
function
displayStatic(e:Event):
void
{
dmFilter.scaleX = randRange(fuzzMin, fuzzMax);
dmFilter.mapPoint = new
Point(0, randRange(0, -160));
myButton.filters = new
Array(dmFilter);
staticLength--;
if
(staticLength <= 0){
fuzzMin = 0;
fuzzMax = 2;
}
}
private var staticLength:int; // called on ENTER_FRAME private function displayStatic(e:Event):void { dmFilter.scaleX = randRange(fuzzMin, fuzzMax); dmFilter.mapPoint = new Point(0, randRange(0, -160)); myButton.filters = new Array(dmFilter); staticLength--; if(staticLength <= 0){ fuzzMin = 0; fuzzMax = 2; } }
This new code decrements the staticLength variable and resets
fuzzMin and fuzzMax to the low intensity values once the value of
staticLength reaches zero.
Step 20: Set up the Button Rollover Handlers
To make our button react to the mouse we need to add two mouse event listeners and an event handler function for each.Add the mouse listeners in the constructor function of your JitteryButton class:
view plain
copy to clipboard
?
// add the rollover event listeners to the button
myButton.addEventListener(MouseEvent.ROLL_OVER, onButtonRollOver);
myButton.addEventListener(MouseEvent.ROLL_OUT, onButtonRollOut);
// add the rollover event listeners to the button myButton.addEventListener(MouseEvent.ROLL_OVER, onButtonRollOver); myButton.addEventListener(MouseEvent.ROLL_OUT, onButtonRollOut);
Now create the two event handlers that are referenced in those two new lines. These also go in the JitteryButton class:
view plain
copy to clipboard
?
// called on button ROLL_OVER
private
function
onButtonRollOver(e:MouseEvent):
void
{
setStaticHigh();
}
// called on button ROLL_OUT
private
function
onButtonRollOut(e:MouseEvent):
void
{
setStaticMedium();
}
// called on button ROLL_OVER private function onButtonRollOver(e:MouseEvent):void { setStaticHigh(); } // called on button ROLL_OUT private function onButtonRollOut(e:MouseEvent):void { setStaticMedium(); }
To make this all work we'll have to import the MouseEvent class at the top of our JitteryButton file:
view plain
copy to clipboard
?
import
flash.events.MouseEvent;
import flash.events.MouseEvent;
Now when our button detects a ROLL_OVER event it will call the
event handler which in turn calls our setStaticHigh function. This
function increases the values of fuzzMin and fuzzMax (used for setting
the horizontal shift) for the duration specified by the staticLength
variable.
Step 21: Add the Scale Effect
We could stophere. Our effect is animating nicely and reacts to the mouse rollovers.
I still feel like something is missing here though. Let's add a little
scaling effect.
You'll need to download the Tweener Library
for this step if you don't already have it. Place the 'caurina' folder
in your project directory and import the Tweener classes at the top of
your JitteryButton file:
view plain
copy to clipboard
?
import
caurina.transitions.Tweener;
import caurina.transitions.Tweener;
Tweener allows us to add some nice scaling effects with only a
couple lines of code. We can add one line to each of our rollover event
handlers:
view plain
copy to clipboard
?
// called on button ROLL_OVER
private
function
onButtonRollOver(e:MouseEvent):
void
{
Tweener.addTween(myButton, {scaleX: 1.1, time: .5, transition: "easeOutElastic"
});
setStaticHigh();
}
// called on button ROLL_OOUT
private
function
onButtonRollOut(e:MouseEvent):
void
{
Tweener.addTween(myButton, {scaleX: 1, time: .5, transition: "easeOutElastic"
});
setStaticMedium();
}
// called on button ROLL_OVER private function onButtonRollOver(e:MouseEvent):void { Tweener.addTween(myButton, {scaleX: 1.1, time: .5, transition: "easeOutElastic"}); setStaticHigh(); } // called on button ROLL_OOUT private function onButtonRollOut(e:MouseEvent):void { Tweener.addTween(myButton, {scaleX: 1, time: .5, transition: "easeOutElastic"}); setStaticMedium(); }
Here we're adding an animation to the rollover handler that
scales the button's scaleX property to 110% over .5 seconds. We're
using an elastic transition type to give it that bouncy feel. In the
rollout handler we're doing the same thing in reverse, scaling it back
to 100%.
You can learn more about how to use Tweener in the Tweener documentation
.
Step 22: Add Sound
Thelast thing we need to do make this effect complete is to add some
sound. I made my sound effect in Garage Band. You can make your own or
try to find one online.
Once you have one you like, import it into your library and set the linkage to export as 'StaticSound'.
To add it to our JitteryButton we first need to import the Sound class:
view plain
copy to clipboard
?
import
flash.media.Sound;
import flash.media.Sound;
Then we'll initialize it (add this line just before the constructor function):
view plain
copy to clipboard
?
private
var
staticSound:Sound =
new
StaticSound();
private var staticSound:Sound = new StaticSound();
Inside the rollover handler we'll tell the sound to play:
view plain
copy to clipboard
?
// called on button ROLL_OVER
private
function
onButtonRollOver(e:MouseEvent):
void
{
Tweener.addTween(myButton, {scaleX: 1.1, time: .5, transition: "easeOutElastic"
});
setStaticHigh();
staticSound.play();
}
// called on button ROLL_OVER private function onButtonRollOver(e:MouseEvent):void { Tweener.addTween(myButton, {scaleX: 1.1, time: .5, transition: "easeOutElastic"}); setStaticHigh(); staticSound.play(); }
Now we're good to go. Test your movie and everything should be
working. If your button or sound isn't working right check the source
files to see my completed JitteryButton class.
Step 23: Add More Buttons
Thecool thing about building this effect as a separate class that wraps
our button is that we can easily reuse it on other buttons.
If
you want to add more buttons to your game menu just create a new button
and add it to the stage. Give it the instance name 'button2'. Then
inside your document class (the 'Game.as' file) create a new
JitteryButton and pass it the new button. Here's how that might look:
view plain
copy to clipboard
?
package
{
import
flash.display.MovieClip;
public
class
Game
extends
MovieClip {
private
var
startButton:JitteryButton;
private
var
menuButton:JitteryButton;
// CLASS CONSTRUCTOR
public
function
Game() {
// create the jittery buttons from the simple buttons on the stage
startButton = new
JitteryButton(button1);
addChild(startButton);
// adding a new button is easy!
menuButton = new
JitteryButton(button2);
addChild(menuButton);
}
}
}
package { import flash.display.MovieClip; public class Game extends MovieClip { private var startButton:JitteryButton; private var menuButton:JitteryButton; // CLASS CONSTRUCTOR public function Game() { // create the jittery buttons from the simple buttons on the stage startButton = new JitteryButton(button1); addChild(startButton); // adding a new button is easy! menuButton = new JitteryButton(button2); addChild(menuButton); } } }
Conclusion
You will almost certainly need to changethis code a bit to get it to fit into the structure of your game.
Hopefully this tutorial will give you a good starting point though.
If
you want to change the look of this effect you can try using different
types of images for your StaticMap graphic, and adjusting the values
for fuzzMin and fuzzMax.
This is my first tutorial so let me know if there's anything I can do better next time. Thanks for reading!
Related Posts
相关文章推荐
- 【js】使用javascript 实现静态网页分页效果
- Google Map API使用详解(十)——使用JavaScript创建地图详解(上)
- 使用Regex实现的为JFileChooser使用的FileFilter对象的创建类
- 使用Filter实现静态HTML缓冲
- 使用EasyUI创建分页对比效果
- 卷积,使用filter2D创建自定义线性滤波器
- 使用Javascript来创建一个响应式的超酷360度全景图片查看幻灯效果
- jquery filter使用""和''效果是一样的
- Linux静态/动态链接库的创建和使用
- 使用桌面窗口管理器创建Aero玻璃效果
- 使用Maven创建Web项目后,jsp引入静态文件提示报错。JSP 报错:javax.servlet.ServletException cannot be resolved to a type
- 使用jQuery创建模态窗口登陆效果
- 【Shader】使用Unity创建水流岩浆等流动效果
- 使用docker swarm创建集群并进行效果验证
- MFC小程序003------MFC使用WebBrowser组件,在对话框中创建滚动视图,动态创建一个静态文本控件并设置鼠标单击的消息响应
- 【spring notes】 使用静态工厂方法创建Bean
- 5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例
- SkylineGlobe 如何使用二次开发接口创建粒子效果
- 使用jquery animate创建平滑滚动效果(可以是到顶部、到底部或指定地方)
- linux 动态链接库的创建和使用--静态连接