嗨,兄弟们,许久不见都在干嘛呢?啥?你问我怎么那么久没发帖?哦,我上周在学驾照啊,那狗教练就会骂人搞得我心情低落。不过好在这周总算有点时间续写我们的教程了,想了好几天不晓得给大家讲点什么,就讲讲老生常谈的一个话题——粒子效果吧,在论坛里有蛮多帖子在讲这个东西,不过有些人没有看懂,因为那些帖子里只说了个大概(传送门),对于漂亮的粒子效果,相信很多人会不厌其烦地看各种类型的例子,今天给列位仙家带来个简单的烟花效果供大家把玩。
在线预览:http://www.iamsevent.com/upload/fireworks.swf
<ignore_js_op>
当前做粒子效果的主流思想就是bitmapData的setPixel方法,这个方法可以在一个位置设置此位置像素点的颜色。它的前两个参数供我们设置位置的x,y坐标,第三个参数是欲设置像素的颜色值。让我们边看代码边讲会更有feel一些:
为了能记录每个粒子的当前位置以及移动速度,需要创建一个valueObject,即数据对象VO:
PixelVO.as
- package
- {
- public class PixelVO
- {
- public var xpos:Number;
- public var ypos:Number;
- public var speedX:Number;
- public var speedY:Number;
- }
- }
OK,接下来建立我们的主类,请允许我省略一些列的import语句:
- [SWF(width="500",height="450")]
- public class MyColorPicker extends Sprite
- {
- private var pixelNum:int = 500;
- private var bm:Bitmap;
- private var bmd:BitmapData;
- private var container:Sprite;
- private var pixelList:Array = new Array();
- private var gravity:Number = 0.1;
- public function MyColorPicker()
- {
- init();
- }
- private function init():void{
- container = new Sprite();
- container.x = 50;
- container.y = 0;
- addChild(container);
- bmd = new BitmapData(400,400,true,0xff000000);
- bm = new Bitmap( bmd );
- container.addChild( bm );
- container.addEventListener(MouseEvent.CLICK, onClick);
- }
- private function onClick(event:MouseEvent):void{
- fire(container.mouseX, container.mouseY);
- }
- private function fire( toX:Number, toY:Number ):void{
- for( var i:int=0; i<pixelNum; i++)
- {
- var vo:PixelVO = new PixelVO();
- vo.xpos = toX;
- vo.ypos = toY;
- vo.speedX = 2 - Math.random() * 4;
- vo.speedY = 1 - Math.random() * 4;
- pixelList.push(vo);
- }
- if( !this.hasEventListener(Event.ENTER_FRAME) )
- {
- this.addEventListener(Event.ENTER_FRAME, onEF);
- }
- }
- private function onEF(event:Event):void{
- bmd.lock();
- for ( var i:int=0; i<pixelList.length; i++ )
- {
- var item:PixelVO = pixelList[i] as PixelVO;
- item.xpos += item.speedX;
- item.ypos += item.speedY;
- item.speedY += gravity;
- bmd.setPixel( item.xpos, item.ypos, 0xffffff );
- if( item.ypos > 400 ){
- pixelList.splice( i, 1 );
- i--;
- item = null;
- }
- }
- bmd.unlock()
- }
在init()函数中我本来想直接放一个bitmap到舞台上去的,无奈bitmap不能监听鼠标点击事件,只能在它外面加一层Sprite的容器,此容器不需要设置它的宽与高,因为Sprite可以根据其内部的子对象大小来调整自己的长与宽。我之后创建了一个用于显示烟花的bitmap,它的bitmapData在new的时候我设置了它的全部四个参数,前两个是它的大小,第三个是设置指定位图图像是否支持每个像素具有不同的透明度,保持默认值true,第四个是用于填充位图图像区域的 32 位 ARGB 颜色值,即类似0xffffffff格式,一般我们用的颜色值在0x后面都只有6位,这里多了2位Alpha值用来设置透明度,这里我设置的值是0xff000000,表示透明度为最大,即完全不透明的黑色。
之后我们设置了点击后执行fire函数,fire函数就是用来产生烟花的,一听函数名字就知道很有杀气,里面的代码也很容易理解,创建了pixelNum个烟花粒子并给每个粒子设置了初始位置为鼠标点击点和随机的一个速度,这个速度可上可下可左可右。
最后我们来看,主要的难点就在于enterFrame处理函数中。对于
- bmd.lock();
- bmd.unlock();
这样的标签对的使用会直接影响运行效率,在对粒子进行数据处理之前先锁定,待数据处理完成后再进行渲染。为了提高运行效率,当别人问你为什么要用这两句时你可以果断回答之“不解释”。在标签对中我们遍历粒子数组对每个粒子进行数据处理,更新粒子位置并让y轴上的速度受到重力加速度的影响。之后再执行setPixel()方法设置粒子对应位置的颜色,这里我统一设成了白色。这样的话每一帧到来时粒子位置的变化都会显式地表现出来。最后我们把掉落出烟花容器底部的粒子从数组里移去。运行一下,我们发现烟花是放出了,但是每个粒子移动过的路径都还留着:
<ignore_js_op>
哦,这可不是我们想要的效果,不过仔细想想,之前我们用setPixel在设置过一个像素点的颜色后就没再设置他回原先的颜色了,出现这种情况是理所当然的。那咋办呢?我们找到一个类叫做ColorTransform,它可以设置一个对象的颜色值,看看他的参数先:
ColorTransform(redMultiplier:Number = 1.0, greenMultiplier:Number = 1.0, blueMultiplier:Number = 1.0, alphaMultiplier:Number = 1.0, redOffset:Number = 0, greenOffset:Number = 0, blueOffset:Number = 0, alphaOffset:Number = 0)
靠,这参数真TMD的多,不过我们一般这里只用到前三个,它们分别代表红色、绿色以及蓝色乘数的值,在 0 到 1 范围内。 设置了这三个参数之后可以把需要设置颜色的对象的红、绿、蓝颜色值乘以这三个乘数形成一个新的颜色。那我们为了让每一帧到来时削减粒子运动路径上的颜色值,就把这三个参数设置成小于1的一个小数。
在声明语句中加上一句:
- private var ctf:ColorTransform = new ColorTransform(0.9, 0.96, 0.96);
之后去onEF函数中在bmd.lock之后加上:
- bmd.lock();
- bmd.colorTransform( bmd.rect, ctf );
在bitMapData中的colorTransform属性可以让我们使用 ColorTransform 对象调整位图图像的指定区域中的颜色值。我们每一帧都将一个红绿蓝三色颜色乘数都小于1的ColorTransform 对象传值给bmd后就可以达到每一帧削减bmd范围内所有像素的颜色为原来的0.9, 0.96, 0.96,这样的话我们就能够看到粒子当前所在位置是正常的颜色,因为他的颜色是新设置的,而它运动过的路径颜色就在不断变淡,最后和背景色融为一体,因为他们都被设置成了黑色0x000000。
为了视觉效果更加美观,再加上个模糊滤镜:
- private var bf:BlurFilter = new BlurFilter(6, 6, 2);
- ……
- private function onEF(event:Event):void{
- bmd.lock();
- bmd.colorTransform( bmd.rect, ctf );
- bmd.applyFilter(bmd, bmd.rect, new Point(), bf);
- ……
这样就漂亮了,不过我们觉得烟花应该是彩色的,不应该只有白色,好吧好吧,我提供给各位一个颜色选择器,虽然在CS工具里有ColorPicker的组件,不过很遗憾,这个组件所在的fl包在FB或者FD中不可用,所以只能自己写的一个了。至于此组件的代码我会和源码一起放出,具体原理的解释的话这里就不多占篇幅了,感兴趣的童鞋在看代码过程中遇到不懂的地方可以留言给我哈^_^。若是觉得我做的这个颜色选择器好,你可以下载源码来存着,要用的时候把代码copy过去即可。
最后放出主类全部代码:
- [SWF(width="500",height="450")]
- public class MyColorPicker extends Sprite
- {
- private var colorPicker:SimpleColorPicker;
- ……
- private function init():void{
- ……
- colorPicker = new SimpleColorPicker();
- colorPicker.x = 10;
- colorPicker.y = 10;
- addChild( colorPicker );
- container.addEventListener(MouseEvent.CLICK, onClick);
- }
- ……
- private function onEF(event:Event):void{
- bmd.lock();
- bmd.colorTransform( bmd.rect, ctf );
- bmd.applyFilter(bmd, bmd.rect, new Point(), bf);
- for ( var i:int=0; i<pixelList.length; i++ )
- {
- var item:PixelVO = pixelList[i] as PixelVO;
- item.xpos += item.speedX;
- item.ypos += item.speedY;
- item.speedY += gravity;
- bmd.setPixel( item.xpos, item.ypos, colorPicker.chooseColor );
- if( item.ypos > 400 ){
- pixelList.splice( i, 1 );
- i--;
- item = null;
- }
- }
- bmd.unlock()
- }
运行效果就看我一开始发的那图吧,提供源码下载:
<ignore_js_op> src.rar (6.09 KB, 下载次数: 761)