ConvolutionFilter做烟火特效

ConvolutionFilter应用矩阵卷积滤镜效果.卷积将输入图像的像素与相邻的像素合并以生成图像,利用它某一点的颜色跟周围颜色融合,做出好看的烟火效果.

效果图

ActionScript代码

先看下代码,再来分析:

单个烟火特效元件里的代码:

AS Code
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.filters.ConvolutionFilter;
var matrixX:Number = 3;
var matrixY:Number = 3;
var matrix:Array = [1, 1, 1, 1, 30, 1, 1, 1, 1];
var divisor:Number = 38;
var filter:ConvolutionFilter = new ConvolutionFilter (matrixXmatrixYmatrixdivisor);
var _w:Number = 100;
var _h:Number = 200;
var bitsMax:Number = 100;
var bitAry:Array = [];
var rect:Rectangle = new Rectangle (0, 0, _w, _h);
var bmp1:BitmapData = new BitmapData (rect.width, rect.heightfalse, 0x000000);
this.createEmptyMovieClip ("yanhuo", 0).attachBitmap (bmp1, 1);
var sd1:Sound = new Sound(this["yanhuo"])
var sd2:Sound = new Sound(this["yanhuo"])
sd1.attachSound("sound1")
sd2.attachSound("sound2")
var bomy:Number;
function initBit ()
{
	var r:Number = Math.floor (Math.random () * 100) +155;
	var g:Number = Math.floor (Math.random () * 255);
	var b:Number = Math.floor (Math.random () * 255);
	var c:Number = RGB (r, g, b);
	bomy = 20 + Math.random () * 10;
	for (var i = 0; i < bitsMax; i++)
	{
		var d = Math.random () * 6.28;
		var d1 = Math.random ();
		bitAry[i] = {x:rect.width / 2, y:rect.height, vx:Math.sin (d) * d1 / 2, vy:Math.cos (d) * d1 / 2, life:Math.floor (Math.random () * 50) + 100, cc:(Math.random () > 0.9 ? 0xFFFFFF : c), step:1};
	}
	sd1.start(0,1)
	this.onEnterFrame = render;
}
function RGB (r, g, b)
{
	return r << 16 | g << 8 | b;
}
function render ()
{
	var bit:Object;
	var flag:Boolean = false
	var len:Number = bitAry.length;
	if (len == 0)
	{
		delete this.onEnterFrame;
		initBit ();
		return;
	}
	for (var i = 0; i < len; i++)
	{
		bit = bitAry[i];
		if (bit.step == 1)
		{
			// 上升中
			bit.y -= 5;
			if (bit.y <= bomy)
			{
				bit.step = 2;
				flag = true
			}
			if (Math.random () > 0.8)
			{
				bmp1.setPixel (Math.floor (bit.x + Math.random () * 2)Math.floor (bit.y + Math.random () * 5), 0xFFFFFF);
			}
		}
		else if (bit.step == 2)
		{
			// 爆炸过程
			bit.vy += Math.random () / 100;
			bit.x += bit.vx;
			bit.y += bit.vy;
			bit.life--;
			if (bit.life == 0 || !rect.contains (bit.x, bit.y))
			{
				bit.cc = 0x000000;
				bitAry.splice (i, 1);
				i--;
				bit.step = 3;
			}
			bmp1.setPixel (Math.round (bit.x)Math.round (bit.y), bit.cc);
		}
	}
	bmp1.applyFilter (bmp1, bmp1.rectanglenew Point (0, 0), filter);
	if(flag)
	{
		sd2.start(0,1)
	}
}

下面我们来分析这段代码

首先是导入必须的类,包括BitmapData,Rectangle和ConvolutionFilter.然后定义了滤镜filter,如果不明白ConvolutionFilter类构造函数参数的意义,去看下Flash的帮助,这里的divisor是矩阵中所有元素之和,会调平总体色彩的强度.

接下来是定义BitmapData,定义粒子数组,以及定义声音.

函数initBit()完成的工作是要初始化粒子数组bitAry,每次放烟火时,指定了一种颜色,用变量c表示,为了让效果明显,r值取的都是大于155的.每个例子元素用一个Object对象表示,它含有x,y,vx,vy,life,cc,step几个属性,分别表示x,y坐标,爆炸后的水平速度,爆炸后的 垂直速度,生命值,颜色值和目前是第几步.其中step的可能值是1,2,3.其中1表示上升过程,2表示爆炸过程,3表示死亡了.定义完bitAry后,就会播放升空声音和指定onEnterFrame来渲染画面.

函数render()用来渲染画面的.如果粒子在上升过程中,则只在粒子周围随机绘制一些白点.在爆炸过程中,则会让每个粒子沿x,y方向以vx,vy的速度飞行,并且vy会一直增大,模拟加速下降的现象.如果粒子的生命期结束,或者超出了范围则把会从bitAry里删除掉它,否则会在bmp1里绘制这个点.当bitAry里没有元素后,会重新调用initBit(),演示下一次烟火效果.

主场景帧上的代码:

AS Code
stop()
var no:Number = 0
var id:Number
var root:MovieClip = this
function playMotion()
{
	no++
	root["yh" + no].initBit()
	if(no == 5)
	{
		clearInterval(id)
	}
}
id = setInterval(playMotion,100)

这段代码主要是为了让舞台上的5个元件播放烟火的效果有个时间差而已.

源文件下载

  1. FLA文件:yanhuo.fla
  2. SWF文件:yanhuo.swf