Another special effect created with Actionscript 3.0 , specifically with the BitmapData and DisplacementMapFilter classes.
The effect re-creates an environment with 2 camping tents on a lake's shore in a full moon night.
Nice is the effect of moving water.
Let's see the classes used:
Acqua.as :
Code:
package
{
import flash.display.MovieClip;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.*;
import flash.net.URLRequest;
import flash.filters.DisplacementMapFilter;
import flash.utils.Timer;
import flash.geom.Point;
public class Acqua extends MovieClip
{
private var filtri_array:Array;
private var stelle_array:Array;
private var timer:Timer;
private var bit_data:BitmapData;
private var spostamento:DisplacementMapFilter;
private var z:Number=1;
private var numStelle:int=150;
private var frizione:Number=.95;
private var immagine:Immagine;
private var loader:Loader;
private var bird_1:MovieClip;
private var bird_2:MovieClip;
public function Acqua()
{
init();
initStelle();
attachImmagine();
initLoader();
initWaterEffect();
}
private function init():void
{
stage.frameRate=31;
bit_data=new BitmapData(726,370,false,0);
spostamento=new DisplacementMapFilter(bit_data,null,1,2,10,30);
filtri_array=new Array();
filtri_array.push(spostamento);
targetClip_mc.filters=filtri_array;
}
private function initStelle():void
{
stelle_array=new Array();
for(var i:int=0;istage.stageHeight/2&&stella.x<150)
stella.y-=100;
stella.alpha=.3+Math.random()*.7;
stella.width=stella.height=1+Math.random()*2.5;
stella.vx=0;
stella.vy=0;
stelle_array.push(stella);
}
}
private function attachImmagine():void
{
immagine=new Immagine();
addChild(immagine);
immagine.x=stage.stageWidth-immagine.width-20;
immagine.y=+5;
}
private function initLoader():void
{
for(var i:int=0;i<2;i++)
{
var url='bird.swf';
var request:URLRequest=new URLRequest(url);
loader=new Loader();
if(i==0)
initListener(loader.contentLoaderInfo);
else
initListener2(loader.contentLoaderInfo);
loader.load(request);
}
}
private function initListener(dispatcher:IEventDispatcher):void
{
dispatcher.addEventListener(Event.COMPLETE,completato);
}
private function initListener2(dispatcher:IEventDispatcher):void
{
dispatcher.addEventListener(Event.COMPLETE,completato2);
}
private function completato(e:Event):void
{
var c:*=e.target.content;
bird_1=c;
bird_1.y=-65;
addChild(bird_1);
startTimer();
}
private function completato2(e:Event):void
{
var c:*=e.target.content;
bird_2=c;
bird_2.y=400;
bird_2.alpha=.5;
bird_2.scaleY=-1;
addChild(bird_2);
}
private function startTimer():void
{
timer=new Timer(10000,0);
timer.addEventListener(TimerEvent.TIMER,go1);
timer.start();
function go1(t:TimerEvent):void
{
bird_1.play();
bird_2.play();
}
}
private function initWaterEffect():void
{
this.addEventListener(Event.ENTER_FRAME,goEffect);
}
private function goEffect(e:Event):void
{
for(var i:int=0; i stage.stageWidth)
stelle_array[i].x=0;
else if(stelle_array[i].x<0)
stelle_array[i].x=stage.stageWidth;
if(stelle_array[i].y>stage.stageHeight)
stelle_array[i].y=stage.stageHeight/2+55;
else if(stelle_array[i].y<0)
stelle_array[i].y=stage.stageHeight;
if(stelle_array[i].y>stage.stageHeight/2+55)
{
stelle_array[i].vx+=Math.random()*.1-.05;
stelle_array[i].vy+=Math.random()*.1-.05;
stelle_array[i].x+=stelle_array[i].vx;
stelle_array[i].y+=stelle_array[i].vy;
stelle_array[i].vx*=frizione;
stelle_array[i].vy*=frizione;
stelle_array[i].alpha=.35;
}
}
var point:Point=new Point(z,z/2);
bit_data.perlinNoise(100,10,2,523,true,false,7,true,[point,point]);
targetClip_mc.filters.mapBitmap=bit_data;
z++;
targetClip_mc.filters=targetClip_mc.filters;
}
}
}
Immagine.as :
Code:
package
{
import flash.display.MovieClip;
public class Immagine extends MovieClip
{
public function Immagine(){}
}
}
Stella.as :
Code:
package
{
import flash.display.MovieClip;
public class Stella extends MovieClip
{
public var vx:Number;
public var vy:Number;
public function Stella(){}
}
}
Let's analyze the code
One of the new things in this script is the use of the class DisplacementMapFilter, which is not available among the classes in the properties panel of Flash.
Basically, with this class, you can select some image pixels to move while the others stay still.
This class is used a lot to elaborate/deform images and create special effects that dramatically change the morphology of the image they're applied to.
DisplacementMapFilter uses a sort of mapping to tell Flash which pixels will be involved in the effect and which won't. Usually this map is the same size as the image to animate, thus contains the same number of pixels.
In the map, the darker the colour of the pixel the stronger our effect will be. Therefore a map completely white would leave the image as it is ( no effect ).
In order to create a new instance of DisplacementMapFilter you need to take a look at what parameters it needs:
mapBitmap: (BitmapData) the BitmapData containing the pixel mapping.
mapPoint: (Point) gives the upper left most point where the effect will begin.
componentX: (unit) which colours to use to move the pixels along the X axis (remember, the darker the colour the stronger the effect).
componentY: (unit) which colours to use to move the pixels along the Y axis.
scaleX: (Number) how much we want to scale the X axis by.
scaleY: (Number) how much we want to scale the Y axis by.
mode: (String) the desired effect ( we have 4 available: clamp, color, ignore, wrap)
color: (unit) specifies which colour to use only if the mode is set to 'color'
alpha: (Number) specifies the transparency to use only if the mode is set to 'color'
Obviously, in my example, this class is used under an interval ENTER_FRAME and the values passed in are always different for each iteration of the interval.
So:
I create the MovieClip to take the effect, having a clearly traced boundary inside of it ( in this case I called it targetClip_mc ).
I create a BitmapData
bit_data=new BitmapData(726,370,false,0);
I create a point
point=new Point(0,0);
I create the DisplacementMapFilter
spostamento=new DisplacementMapFilter(bit_data,point,1,2,10,30);
then, as all filters, I insert it in an Array, which I feed to the filters property of the MovieClip
filtri_array=new Array();
filtri_array.push(spostamento);
targetClip_mc.filters=filtri_array;
PS: I haven't forgotten the data type, but they are simply variable that I've already declared at the top. As usual, let's remember we're working on .as files, therefore the data type is fundamental and compulsory.
Every other bit of code relates to the loading of an external SWF ( the flying bird ), the positioning of the stars and other small things I won't talk about.
The last lines of the goEffect method are the most important part, method called within the ENTER_FRAME interval:
I create a point every time ( the variable z had already been declared )
var point:Point=new Point(z,z/2);
I use the perlinNoise method of our bit_data variable to which we'd applied the filter DisplacementMapFilter
bit_data.perlinNoise(100,10,2,523,true,false,7,tru e,[point,point]);
I tell DisplacementMapFilter ( which is now targetClip_mc.filters ) to map the BitmapData ( bit_data )
targetClip_mc.filters.mapBitmap=bit_data;
I increase the value of the variable z:
z++;
I finally pass the newly mapped filter to the filters property of the MovieClip:
targetClip_mc.filters=targetClip_mc.filters;
Hi - great effect- I am having an issue where the z index just keeps increasing and the water image I am using is basically shrinking instead of just morphing in place- does this make sense?
I have just used it as a script on a frame instead of importing a class...
is this the problem?
here is what I am using
Code:
var bit_data=new BitmapData(726,370,false,0);
var point=new Point(0,0);
var spostamento=new DisplacementMapFilter(bit_data,point,1,2,10,30);
var filtri_array=new Array();
filtri_array.push(spostamento);
targetClip_mc.filters=filtri_array;
FUCK();
function FUCK():void{
this.addEventListener(Event.ENTER_FRAME,goEffect);
}
function goEffect(e:Event):void{
var point:Point=new Point(z,z/2);
bit_data.perlinNoise(100,7,2,523,true,false,7,true,[point,point]);
targetClip_mc.filters.mapBitmap=bit_data;
z++;
targetClip_mc.filters=targetClip_mc.filters;
}
Hi,
I think you should change the name of variable point ( you have double variables with same name )
Code:
var bit_data=new BitmapData(726,370,false,0);
var point=new Point(0,0);
var spostamento=new DisplacementMapFilter(bit_data,point,1,2,10,30);
var filtri_array=new Array();
filtri_array.push(spostamento);
targetClip_mc.filters=filtri_array;
FUCK();
function FUCK():void{
this.addEventListener(Event.ENTER_FRAME,goEffect);
}
function goEffect(e:Event):void{
var point2:Point=new Point(z,z/2);
bit_data.perlinNoise(100,7,2,523,true,false,7,true,[point2,point2]);
targetClip_mc.filters.mapBitmap=bit_data;
z++;
targetClip_mc.filters=targetClip_mc.filters;
}
[QUOTE=OrientExpress;28255]Hi,
I think you should change the name of variable point ( you have double variables with same name )
Thanks, Orient-
I don't think that was it- the script is basically taken verbatim out of the demo and the original uses the variable point the same way.
I got this working, but it was necessary to do two things-
a) the demo package instantiated a private var z as a Number type and set it to 1, so I did that.
b) but that wasn't working in flash player v10 so I resaved it as 9. then it worked fine. Unless I am mistaken the use of z as a private var was problematic in Player 10.
Does that make sense to anybody?
I got it working fine for my uses, but I thought I would throw this out in case others are wrestling with it.
Bookmarks