Flash/Flex学习笔记(24):粒子效果

粒子爆炸:

仍然要用到以前的小球类,不过稍加改造

view source

print?

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事件中不断检测,一旦有对象跑出边界了,就将其清除,不再理会了.

view source

print?

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轴位置模拟了风力影响。(在水平方向移动鼠标可看到喷射方向略有变化)

view source

print?

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
}

粒子跟随:

除了利用边界检测移除粒子外,在实际开发中也经常利用时间来判断,比如一个对象在舞台上存活几秒后,便将其干掉。

view source

print?

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帧对应的时间就寿终正寝

模拟布朗运动:

view source

print?

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
}

posted @ 2010-11-22 16:52  模西的哥哥  阅读(380)  评论(0编辑  收藏  举报