Flash/Flex学习笔记(24):粒子效果
粒子爆炸:
仍然要用到以前的小球类,不过稍加改造
01 package {
02 import flash.display.Sprite;
03
04 //小球 类
05 public class Ball extends Sprite {
06
07 public var radius:uint;//半径
08 public var color:uint;//颜色
09 public var vx:Number=0;//x轴速度
10 public var vy:Number=0;//y轴速度
11
12 public function Ball(r:Number=50,c:uint=0xff0000) {
13 this.radius=r;
14 this.color=c;
15 init();
16 }
17
18 private function init():void {
19 graphics.beginFill(color);
20 graphics.drawCircle(0,0,radius);
21 graphics.endFill();
22 }
23 }
24 }
增加了x,y轴的速度,其它没变
原理:在舞台的某一区域放置大量小球实例,然后在某个时刻让其向四面八方运动即可(即改变每个小球在x,y轴上的坐标)
问题:效率!让CPU在每帧对于大量对象进行重绘是很耗资源的,所以当小球跑出舞台边界时,得想办法通知CPU:这些小球不需要再处理了(反正也看不见)!否则纯属折腾CPU,下面的代码用一个数组存放所有对象实例的引用,然后在EnterFrame事件中不断检测,一旦有对象跑出边界了,就将其清除,不再理会了.
01 import fl.controls.Label;
02 import flash.text.TextFieldAutoSize;
03
04 stage.scaleMode=StageScaleMode.NO_SCALE;
05 stage.align=StageAlign.TOP_LEFT;
06
07 var Count:Number=1500;
08 var Radius:uint=30;
09 var CenterX:uint=stage.stageWidth/2;
10 var CenterY:uint=stage.stageHeight/2;
11
12 var ArrBall:Array=new Array(Count);
13
14 //让小球呈圆形随机分布
15 for (var i=0; i<ArrBall.length; i++) {
16 ArrBall[i]=new Ball(Math.random() * 5,Math.random() * 0xff0000);
17 var angle:Number=Math.random()*Math.PI*2;
18 var RadiusRnd:Number=Math.random()*Radius;
19 ArrBall[i].x=CenterX+Math.cos(angle)*RadiusRnd;
20 ArrBall[i].y=CenterY+Math.sin(angle)*RadiusRnd;
21 addChild(ArrBall[i]);
22 }
23
24 var lbl1:Label = new Label();
25 lbl1.text="点击鼠标引爆这个球";
26 lbl1.autoSize=TextFieldAutoSize.CENTER;
27
28 lbl1.x=stage.stageWidth/2-lbl1.width/2;
29 lbl1.y=50;
30 Mouse.cursor=MouseCursor.BUTTON;
31 addChild(lbl1);
32
33 stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);
34 stage.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
35
36 //文件鼠标跟随
37 function MouseMoveHandler(e:MouseEvent):void {
38 lbl1.x=mouseX+15;
39 lbl1.y=mouseY+15;
40 }
41
42 function MouseDownHandler(e:MouseEvent):void {
43 //点击一次后,取消鼠标跟随,并移除lbl1,同时也取消鼠标点击事件(即本事件仅触发一次)
44 Mouse.cursor=MouseCursor.ARROW;
45 stage.removeEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);
46 lbl1.visible=false;
47 removeChild(lbl1);
48 stage.removeEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
49
50 InitVelocity();//初始化粒子速度
51
52 addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
53 }
54
55 function InitVelocity() {
56 for (var i=0; i<ArrBall.length; i++) {
57 ArrBall[i].vx = (Math.random()*2-1) * 30 ;//注意这里的小技巧: Math.random()*2-1即得到一个在-1到1之间分布的随机小数,即小球随机向左或向右的初始速度,然后再放大N倍,得到x轴最终速度
58 ArrBall[i].vy = (Math.random()*2-1) * 30;
59 }
60
61 }
62
63
64 function EnterFrameHandler(e:Event):void {
65 for (i=ArrBall.length-1; i>=0; i--) {
66 var ball:Ball = ArrBall[i];
67 ball.x += (ball.vx );
68 ball.y += (ball.vy );
69 //检测边界,如果超出屏幕则移除该对象(注:从舞台上移除不再使用的对象,能使CPU占用率有效降低)
70 if (ball.x < -ball.width/2 || ball.x > stage.stageWidth + ball.width/2 || ball.y< -ball.height/2 || ball.y > stage.stageHeight + ball.height/2){
71 removeChild(ball);
72 ArrBall.splice(i,1);
73 }
74
75 //如果数组已经为空,则清除EnterFrame事件
76 if (ArrBall.length==0){
77 removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);
78 }
79
80 //trace(ArrBall.length);
81
82
83 }
84 }
粒子喷射:
如果看过上篇Flash/Flex学习笔记(23):运动学原理 并动手实践过"自由落体运动"的朋友,对于这种粒子效果可能比较容易理解。
原理:将所有粒子聚集于屏幕上某点(本例中为屏幕底部中心点),然后赋给一个随机向上的速度(这样就能向上喷射出),同时为了更效果更自然,还要加入随机的x轴方向速度(以实现喷射过程中的扩散),最后再加入重力加速度,以实现粒子的自由回落。
效率:为了能最大限度的利用现有对象,当粒子跑出舞台边界时,重新用代码将其定位到发射点,以便下次继续喷射。
交互:本例中为增强交互性,用鼠标的x轴位置模拟了风力影响。(在水平方向移动鼠标可看到喷射方向略有变化)
01 package {
02 import flash.display.Sprite;
03 import flash.display.StageAlign;
04 import flash.display.StageScaleMode;
05 import flash.events.Event;
06 public class Fountain extends Sprite {
07 private var count:int=3000;
08 private var wind:Number=0.0;
09
10 private var gravity:Number=0.3;
11 private var balls:Array;
12 public function Fountain() {
13 init();
14 }
15 private function init():void {
16 stage.scaleMode=StageScaleMode.NO_SCALE;
17 stage.align=StageAlign.TOP_LEFT;
18 balls = new Array();
19 for (var i:int = 0; i < count; i++) {
20 var ball:Ball=new Ball(1,0xffffff);
21 ball.x=stage.stageWidth/2;
22 ball.y=stage.stageHeight;
23 ball.vx = (Math.random()*2-1) * 1.5 + wind;
24 ball.vy=-5+Math.random()*-10;
25 addChild(ball);
26 balls.push(ball);
27 }
28 addEventListener(Event.ENTER_FRAME, onEnterFrame);
29 }
30 private function onEnterFrame(event:Event):void {
31 wind = -1*(mouseX - stage.stageWidth/2)/200;
32 for (var i:Number = 0; i < balls.length; i++) {
33 var ball:Ball=Ball(balls[i]);
34 ball.vy+=gravity;
35 ball.x+=ball.vx;
36 ball.y+=ball.vy;
37 if (ball.x > stage.stageWidth + ball.radius || ball.x < -ball.radius || ball.y >stage.stageHeight + ball.radius || ball.y<-ball.radius) {
38 ball.x=stage.stageWidth/2;
39 ball.y=stage.stageHeight;
40 ball.vx = (Math.random()*2-1) * 1.5 + wind;
41 ball.vy=-5+Math.random()*-10;
42 }
43 }
44 }
45 }
46 }
粒子跟随:
除了利用边界检测移除粒子外,在实际开发中也经常利用时间来判断,比如一个对象在舞台上存活几秒后,便将其干掉。
01 stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);
02
03 function MouseMoveHandler(e:MouseEvent):void{
04 var ball:Ball = new Ball(Math.random()*3,0x00ff00);
05 ball.x = mouseX;
06 ball.y = mouseY;
07 ball.vx = (Math.random()*2-1)*3;
08 ball.vy = (Math.random()*2-1)*3;
09 addChild(ball);
10 ball.addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
11 }
12
13 function EnterFrameHandler(e:Event):void{
14 var ball:Ball = e.target as Ball;
15 ball.x += ball.vx;
16 ball.y += ball.vy;
17 ball.count ++;
18 if (ball.count>=50){
19 ball.removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);
20 removeChild(ball);
21 }
22 }
注:需要先在Ball类中增加一个public var count:uint=0;变量(用来辅助计时),上面的代码中用 if ball.count>=50做判断,相当于每个小球只让其播放50帧对应的时间就寿终正寝
模拟布朗运动:
01 var Count:Number=200;
02
03 //初始化
04 for (var i:Number=0; i<=Count; i++) {
05 var ball:Ball=new Ball(Math.random()*3,0x00ff00);
06 ball.x=Math.random()*stage.stageWidth;
07 ball.y=Math.random()*stage.stageHeight;
08 ball.vx=ball.vy=0;
09 addChild(ball);
10 ball.addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
11 }
12
13 function EnterFrameHandler(e:Event):void {
14 var ball:Ball=e.target as Ball;
15 //每一帧让其速度随机变化一点点
16 ball.vx += (Math.random()*2-1)*2;
17 ball.vy += (Math.random()*2-1)*2;
18
19 ball.x+=ball.vx;
20 ball.y+=ball.vy;
21
22 //超出边界后,先让其反向运动一次(即:退回原处),然后速度反向
23 if (ball.x>stage.stageWidth-ball.width/2||ball.x<ball.width/2) {
24 ball.x-=ball.vx;
25 ball.vx*=-1;
26 }
27
28 if (ball.y>stage.stageHeight-ball.height/2||ball.y<ball.height/2) {
29 ball.y-=ball.vy;
30 ball.vy*=-1;
31 }
32
33 //加入摩擦力因子,看起来更自然
34 ball.vx=ball.vx*0.9;
35 ball.vy=ball.vy*0.9;
36 }
浙公网安备 33010602011771号