Flash/Flex学习笔记(44):万有引力与粒子系统

万有引用公式:

其中G为万有引力常数

show sourceview source

print?

001
var numParticles:uint=50;//粒子总数

002
var G:Number=0.03;//万有引力常数

003
var particles:Array=new Array(numParticles);

004
var bounce:Number=-0.4;//边界反弹系统

005

006
//初始化

007
function init():void {

008
particles = new Array();

009
for (var i:uint = 0; i < numParticles; i++) {

010
var size:Number=Math.random()*12+3;

011
var particle:Ball=new Ball(size,Math.random()*0xffffff);

012
particle.x=Math.random()*stage.stageWidth;

013
particle.y=Math.random()*stage.stageHeight;

014
particle.mass=Math.PI * size * size;//质量与球截面积关联,即从视觉效果上看,个头越大,越重

015
addChild(particle);

016
particles.push(particle);

017
}

018
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

019
}

020

021

022
function EnterFrameHandler(event:Event):void {

023
for (var i:uint = 0; i < numParticles; i++) {

024
var particle:Ball=particles[i];

025
particle.x+=particle.vx;

026
particle.y+=particle.vy;

027
}

028
for (i=0; i < numParticles - 1; i++) {

029
var partA:Ball=particles[i];

030
for (var j:uint = i + 1; j < numParticles; j++) {

031
var partB:Ball=particles[j];

032
checkCollision(partA,partB);//检测碰撞

033
gravitate(partA, partB);//万有引力处理

034
}

035
checkWalls(partA);//边界检测

036
}

037
}

038

039
//万有引力处理

040
function gravitate(partA:Ball, partB:Ball):void {

041
var dx:Number=partB.x-partA.x;

042
var dy:Number=partB.y-partA.y;

043
var distSQ:Number=dx*dx+dy*dy;

044
var dist:Number=Math.sqrt(distSQ);

045
var force:Number=G*partA.mass*partB.mass/distSQ;//计算partA与partB的万有引力

046
var forceX:Number=force*dx/dist;//即:force * cos(a) --万有引力在x方向上的分量

047
var forceY:Number=force*dy/dist;//即:force * sin(a) --万有引力在y方向上的分量

048
partA.vx+=forceX/partA.mass;//牛顿定律a = F/m 在这里得到体现

049
partA.vy+=forceY/partA.mass;

050
partB.vx-=forceX/partB.mass;

051
partB.vy-=forceY/partB.mass;

052
}

053

054
//动量守恒的碰撞检测

055
function checkCollision(ball0:Ball, ball1:Ball):void {

056
var dx:Number=ball1.x-ball0.x;

057
var dy:Number=ball1.y-ball0.y;

058
var dist:Number=Math.sqrt(dx*dx+dy*dy);

059
if (dist<ball0.radius+ball1.radius) {

060
var angle:Number=Math.atan2(dy,dx);

061
var sin:Number=Math.sin(angle);

062
var cos:Number=Math.cos(angle);

063
var pos0:Point=new Point(0,0);

064
var pos1:Point=rotate(dx,dy,sin,cos,true);

065
var vel0:Point=rotate(ball0.vx,ball0.vy,sin,cos,true);

066
var vel1:Point=rotate(ball1.vx,ball1.vy,sin,cos,true);

067
var vxTotal:Number=vel0.x-vel1.x;

068
vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) / (ball0.mass + ball1.mass);

069
vel1.x=vxTotal+vel0.x;

070
var sumRadius:Number=ball0.radius+ball1.radius;

071
var overlap:Number=sumRadius-Math.abs(pos0.x-pos1.x);

072
var aRadio:Number=ball0.radius/sumRadius;

073
var bRadio:Number=ball1.radius/sumRadius;

074
if (overlap>0) {

075
if (pos0.x>pos1.x) {

076
pos0.x+=overlap*aRadio;

077
pos1.x-=overlap*bRadio;

078
} else {

079
pos0.x-=overlap*aRadio;

080
pos1.x+=overlap*bRadio;

081
}

082
}

083
var pos0F:Object=rotate(pos0.x,pos0.y,sin,cos,false);

084
var pos1F:Object=rotate(pos1.x,pos1.y,sin,cos,false);

085
ball1.x=ball0.x+pos1F.x;

086
ball1.y=ball0.y+pos1F.y;

087
ball0.x=ball0.x+pos0F.x;

088
ball0.y=ball0.y+pos0F.y;

089
var vel0F:Object=rotate(vel0.x,vel0.y,sin,cos,false);

090
var vel1F:Object=rotate(vel1.x,vel1.y,sin,cos,false);

091
ball0.vx=vel0F.x;

092
ball0.vy=vel0F.y;

093
ball1.vx=vel1F.x;

094
ball1.vy=vel1F.y;

095
}

096
}

097

098
//坐标旋转辅助方法

099
function rotate(x:Number, y:Number, sin:Number, cos:Number, reverse:Boolean):Point {

100
var result:Point = new Point();

101
if (reverse) {

102
result.x=x*cos+y*sin;

103
result.y=y*cos-x*sin;

104
} else {

105
result.x=x*cos-y*sin;

106
result.y=y*cos+x*sin;

107
}

108
return result;

109
}

110

111

112
//舞台边界检测  

113
function checkWalls(b:Ball) {

114
if (b.x<b.radius) {

115
b.x=b.radius;

116
b.vx*=bounce;

117
} else if (b.x>stage.stageWidth-b.radius) {

118
b.x=stage.stageWidth-b.radius;

119
b.vx*=bounce;

120
}

121
if (b.y<b.radius) {

122
b.y=b.radius;

123
b.vy*=bounce;

124
} else if (b.y>stage.stageHeight-b.radius) {

125
b.y=stage.stageHeight-b.radius;

126
b.vy*=bounce;

127
}

128
}

129

130

131
init();

132

133
btnReset.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);

134

135
function MouseDownHandler(e:MouseEvent):void {

136
removeEventListener(Event.ENTER_FRAME, EnterFrameHandler);

137
for (var i:uint = 0; i < numParticles; i++) {

138
var particle:Ball=particles[i];

139
particle.x=Math.random()*stage.stageWidth;

140
particle.y=Math.random()*stage.stageHeight;

141
particle.vx=0;

142
particle.vy=0;

143
}

144
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

145
}

代码虽然很长,但是其中有很多都是上一篇里封装好的方法直接复制过来的,应该不难理解

再来模拟一下地球绕着太阳转:

show sourceview source

print?

01
var numParticles:uint=2;//粒子总数

02
var G:Number=0.03;//万有引力常数

03
var particles:Array=new Array(numParticles);

04
var i:Number=0;

05

06

07
//初始化

08
function init():void {

09
particles = new Array(); 

10
var sun:Ball = new Ball(30, 0xff0000); 

11
sun.x = stage.stageWidth / 2

12
sun.y = stage.stageHeight / 2

13
sun.mass = 900000

14
addChild(sun); 

15
particles.push(sun); 

16
var planet:Ball = new Ball(10, 0x0000ff); 

17
planet.x = stage.stageWidth / 2 + 200

18
planet.y = stage.stageHeight / 2

19
planet.vy = 8

20
planet.mass = 1

21
addChild(planet); 

22
particles.push(planet); 

23
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

24
graphics.lineStyle(1,0xdddddd);

25
graphics.moveTo(planet.x,planet.y);

26
}

27

28

29
function EnterFrameHandler(event:Event):void {

30
for (var i:uint = 0; i < numParticles; i++) {

31
var particle:Ball=particles[i];

32
particle.x+=particle.vx;

33
particle.y+=particle.vy;

34
}

35
for (i=0; i < numParticles - 1; i++) {

36
var partA:Ball=particles[i];

37
for (var j:uint = i + 1; j < numParticles; j++) {

38
var partB:Ball=particles[j];            

39
gravitate(partA, partB);//万有引力处理

40
}       

41
}

42
}

43

44
//万有引力处理

45
function gravitate(partA:Ball, partB:Ball):void {   

46

47
var dx:Number=partB.x-partA.x;

48
var dy:Number=partB.y-partA.y;

49
var distSQ:Number=dx*dx+dy*dy;

50
var dist:Number=Math.sqrt(distSQ);

51
var force:Number=G*partA.mass*partB.mass/distSQ;//计算partA与partB的万有引力

52
var forceX:Number=force*dx/dist;//即:force * cos(a) --万有引力在x方向上的分量

53
var forceY:Number=force*dy/dist;//即:force * sin(a) --万有引力在y方向上的分量

54
/*

55
partA.vx+=forceX/partA.mass;//牛顿定律a = F/m 在这里得到体现

56
partA.vy+=forceY/partA.mass;

57
*/

58
partB.vx-=forceX/partB.mass;

59
partB.vy-=forceY/partB.mass;

60
trace(i);

61
if (i<=1000){

62
graphics.lineTo(partB.x,partB.y);

63
i++;        

64
}

65
else{

66
graphics.clear();

67
graphics.lineStyle(1,0xdddddd);

68
graphics.moveTo(partB.x,partB.y);

69
i=0;

70
}

71

72
}

73

74
init();

代码就是在第一段的基础上修改的,可以看到在"远日点"速度较慢(因为距离越远,万有引力越小,对应的加速度也较小),在"近日点"速度较快(距离越近,万有引力越大,对应的加速度也较大)

节点花园NodeGarden:

为啥叫这个名字,我也说不上来,反正ActionScript3.0 in Animation一书的作者是这么叫的。

show sourceview source

print?

01
var particles:Array;

02
var numParticles:uint=60;

03
var minDist:Number=100;

04
var springAmount:Number=0.0004;

05
var friction:Number = 0.9995;

06

07
function init():void {

08
stage.scaleMode=StageScaleMode.NO_SCALE;

09
stage.align=StageAlign.TOP_LEFT;

10
particles = new Array();

11
for (var i:uint = 0; i < numParticles; i++) {

12
var particle:Ball=new Ball(Math.random()*3+2,0xffffff);

13
particle.x=Math.random()*stage.stageWidth;

14
particle.y=Math.random()*stage.stageHeight;

15
particle.vx=Math.random()*6-3;

16
particle.vy=Math.random()*6-3;

17
addChild(particle);

18
particles.push(particle);

19
}

20
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

21
}

22

23
function EnterFrameHandler(event:Event):void {

24
graphics.clear();

25
for (var i:uint = 0; i < numParticles; i++) {

26
var particle:Ball=particles[i];

27
particle.x+=particle.vx;

28
particle.y+=particle.vy;

29

30
//屏幕环绕处理

31
if (particle.x>stage.stageWidth) {

32
particle.x=0;

33
} else if (particle.x < 0) {

34
particle.x=stage.stageWidth;

35
}

36
if (particle.y>stage.stageHeight) {

37
particle.y=0;

38
} else if (particle.y < 0) {

39
particle.y=stage.stageHeight;

40
}

41
}

42
for (i=0; i < numParticles - 1; i++) {

43
var partA:Ball=particles[i];

44
for (var j:uint = i + 1; j < numParticles; j++) {

45
var partB:Ball=particles[j];

46
spring(partA, partB);//每个粒子均与其它粒子进行弹性运动处理

47
}   

48

49
partA.vx *= friction;

50
partA.vy *= friction;

51
}

52
}

53

54
function spring(partA:Ball, partB:Ball):void {

55
var dx:Number=partB.x-partA.x;

56
var dy:Number=partB.y-partA.y;

57
var dist:Number=Math.sqrt(dx*dx+dy*dy);

58
if (dist<minDist) {      

59
graphics.lineStyle(1, 0x00ff00, 1 - dist / minDist);//注意这里的透明度设置:二球越来越近时,线条越来越明显,距离越来越远时,线条越来越淡

60
graphics.moveTo(partA.x, partA.y);

61
graphics.lineTo(partB.x, partB.y);

62
//类似弹性运动处理

63
var ax:Number=dx*springAmount;

64
var ay:Number=dy*springAmount;

65
//A球加速

66
partA.vx+=ax;

67
partA.vy+=ay;

68
//B球减速

69
partB.vx-=ax;

70
partB.vy-=ay;

71
//一个球越来越快,一个球越来越慢,所以会不断拉近(当然:前提是在有效距离内)

72

73

74
}

75

76
}

77

78
init();

关于这个效果,建议初次接触的同学们,先回顾一下弹性运动:Flash/Flex学习笔记(40):弹性运动续--弹簧

可以稍加改进,加入质量因素:

show sourceview source

print?

01
var particles:Array;

02
var numParticles:uint=30;

03
var minDist:Number=120;

04
var springAmount:Number=0.03;

05
var friction:Number = 0.998;

06
var stageHeight:Number = stage.stageHeight;

07
var stageWidth:Number = stage.stageWidth;

08

09
function init():void {

10
stage.scaleMode=StageScaleMode.NO_SCALE;

11
stage.align=StageAlign.TOP_LEFT;

12
particles = new Array();

13
for (var i:uint = 0; i < numParticles; i++) {

14
var particle:Ball=new Ball(Math.random()*5+2,0xffffff);

15
particle.x=Math.random()*stageWidth;

16
particle.y=Math.random()*stageHeight;

17
particle.vx=Math.random()*6-3;

18
particle.vy=Math.random()*6-3;

19
particle.mass = Math.PI*particle.radius*particle.radius;//加入质量

20
addChild(particle);

21
particles.push(particle);

22
}

23
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

24
stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);

25
}

26

27
//鼠标互动

28
function MouseMoveHandler(e:MouseEvent):void{   

29
var dx:Number = mouseX - stageWidth/2;

30
var dy:Number = mouseY - stageHeight/2;     

31
for (var i:uint = 0; i < numParticles; i++) {

32
var b:Ball=particles[i];        

33
b.x -= dx/b.mass;

34
b.y -= dy/b.mass;

35
}   

36
}

37

38
function EnterFrameHandler(e:Event):void {

39
graphics.clear();

40
for (var i:uint = 0; i < numParticles; i++) {

41
var particle:Ball=particles[i];

42
particle.x+=particle.vx;

43
particle.y+=particle.vy;        

44
//屏幕环绕处理

45
if (particle.x>stageWidth) {

46
particle.x=0;

47
} else if (particle.x < 0) {

48
particle.x=stageWidth;

49
}

50
if (particle.y>stageHeight) {

51
particle.y=0;

52
} else if (particle.y < 0) {

53
particle.y=stageHeight;

54
}

55
}

56
for (i=0; i < numParticles - 1; i++) {

57
var partA:Ball=particles[i];

58
for (var j:uint = i + 1; j < numParticles; j++) {

59
var partB:Ball=particles[j];

60
spring(partA, partB);//每个粒子均与其它粒子进行弹性运动处理

61
}   

62

63
partA.vx *= friction;

64
partA.vy *= friction;

65
}

66
}

67

68
function spring(partA:Ball, partB:Ball):void {

69
var dx:Number=partB.x-partA.x;

70
var dy:Number=partB.y-partA.y;

71
var dist:Number=Math.sqrt(dx*dx+dy*dy);

72
if (dist<minDist) {      

73
graphics.lineStyle(1, 0x00ff00, 1 - dist / minDist);//注意这里的透明度设置:二球越来越近时,线条越来越明显,距离越来越远时,线条越来越淡

74
graphics.moveTo(partA.x, partA.y);

75
graphics.lineTo(partB.x, partB.y);

76
//类似弹性运动处理

77
var ax:Number=dx*springAmount;

78
var ay:Number=dy*springAmount;

79
//A球加速

80
partA.vx+=ax/partA.mass;

81
partA.vy+=ay/partA.mass;

82
//B球减速

83
partB.vx-=ax/partB.mass;

84
partB.vy-=ay/partB.mass;

85
//一个球越来越快,一个球越来越慢,所以会不断拉近(当然:前提是在有效距离内)     

86
}   

87
}

88

89
init();

下面这种效果也是很多Flash网站上都有的,效果还不错,而且原理也很简单:

show sourceview source

print?

01
var ballCount:uint = 100;

02
var friction:Number = 0.95;

03
var massRadio = 0.005;

04
var arrBall:Array = new Array(ballCount);

05
var stageWidth:Number = stage.stageWidth;

06
var stageHeight:Number = stage.stageHeight;

07

08
for(var i:uint=0;i<ballCount;i++){

09
arrBall[i] = new Ball(Math.random()*10+3,Math.random()*0xffffff);

10
arrBall[i].x = Math.random()*stageWidth;

11
arrBall[i].y = Math.random()*stageHeight;

12
arrBall[i].mass = massRadio * arrBall[i].radius;

13
addChild(arrBall[i]);

14
}

15

16

17
stage.addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

18
stage.addEventListener(MouseEvent.MOUSE_MOVE,MouseMoveHandler);

19

20
function EnterFrameHandler(e:Event):void{       

21
for(var i:uint=0;i<ballCount;i++){

22
var b:Ball = arrBall[i];        

23
b.vx *=friction;

24
b.vy *=friction;

25
b.x += b.vx;

26
b.y += b.vy;

27

28
//屏幕环绕处理

29
if (b.x>stageWidth+b.radius){

30
b.x=-b.radius;

31
}

32
else if (b.x<-b.radius){

33
b.x = stageWidth+b.radius;

34
}       

35
if (b.y>stageHeight+b.radius){

36
b.y=-b.radius;

37
}

38
else if (b.y<-b.radius){

39
b.y = stageHeight+b.radius;

40
}

41
}       

42
}

43

44
function MouseMoveHandler(e:MouseEvent):void{   

45
var CenterX:Number = 0.5*stageWidth;

46
var CenterY:Number = 0.5*stageHeight;

47
var dx:Number = mouseX - CenterX;

48
var dy:Number = mouseY - CenterY;   

49
for(var i:uint=0;i<ballCount;i++){

50
var b:Ball = arrBall[i];

51
//设置速度

52
b.vx = -dx*b.mass;

53
b.vy = -dy*b.mass;      

54
}       

55
}

下面这个是它的变种:

show sourceview source

print?

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