Flash/Flex学习笔记(49):3D基础

之前我们所做的动画都是基于x,y二维坐标轴的,在三维动画中我们还需要增加一个垂直于屏幕“向里”或“向外”的Z轴,那么z轴到底是应该向外,还是向里呢?这个其实无所谓,不过为了统一,习惯上通常把z轴约定为向里,即所谓的“右手坐标系”

右手坐标系的得名:伸出右手,让食指、中指、大拇指相互垂直;然后 食指指向x轴正向,中指指向y轴正向,则大拇指所指方向即为z轴正向。(事实上这个姿势酷似周杰伦周董的招牌动作)

三维透视的基本规则:

物体在Z轴上的坐标越大(越远),则看起来越小(将上图坐标系旋转,把z轴转到x轴方向后,得到下图),如果距离足够远,则物体将消失于屏幕上的某个特定点(通常称为“消失点”)

技术上的主要处理:动态调整物体的scaleX与scaleY(同时因为物体的大小改变后,相应的x,y坐标值通常也会改变,所以x,y坐标也要做相应调整以符合透视规则),基本公式如下:

scale = fl/(fl+z)

show sourceview source

print?

01
var ball:Ball = new Ball();

02
addChild(ball);

03

04
//观察点 相对于 消失点的坐标

05
var xPos:Number=0;

06
var yPos:Number=0;

07
var zPos:Number=0;

08
var fl:Number=250;//焦距

09
//消失点

10
var vpX:Number=stage.stageWidth/2;

11
var vpY:Number=stage.stageHeight/2;

12

13
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

14
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);

15
stage.addEventListener(MouseEvent.MOUSE_WHEEL,MouseWheelHandler);

16

17
//鼠标滚轮事件(注:必须让stage获取焦点时-即用鼠标在动画上点击一下,该事件才会触发,另外还要注意:嵌入网页时,浏览器也会响应鼠标滚轮)

18
function MouseWheelHandler(e:MouseEvent):void {

19
zPos += (e.delta*5);

20
}

21

22
function EnterFrameHandler(event:Event):void {

23
if (zPos> -fl) {

24
ball.visible=true;

25
xPos=mouseX-vpX;

26
yPos=mouseY-vpY;

27
var scale:Number = fl / (fl + zPos);

28
ball.scaleX=ball.scaleY=scale;

29
ball.x=vpX+xPos*scale;

30
ball.y=vpY+yPos*scale;

31
} else {

32
ball.visible=false;

33
}

34

35
//辅助线

36
graphics.clear();

37
graphics.lineStyle(1,0xcccccc);

38
graphics.moveTo(vpX,vpY);   

39
graphics.lineTo(vpX,ball.y);

40
graphics.moveTo(vpX,vpY);

41
graphics.lineTo(ball.x,vpY);

42

43

44
graphics.lineStyle(1,0x0000ff,0.5);

45
graphics.moveTo(vpX,vpY);

46
graphics.lineTo(ball.x,ball.y);

47

48
graphics.lineStyle(1,0xff0000,0.5);

49
graphics.moveTo(ball.x,ball.y);

50
graphics.lineTo(mouseX,mouseY); 

51
}

52

53
//键盘事件

54
function KeyDownHandler(e:KeyboardEvent):void {

55
if (e.keyCode==Keyboard.UP) {

56
zPos+=5;

57
} else if (e.keyCode == Keyboard.DOWN) {

58
zPos-=5;

59
}

60
}

这个示例中,"鼠标所在位置"充当了"观察点"(即前面示意图中的"人眼"位置),电脑屏幕所在平面即物体的成像面,用键盘上下键可调整小球在Z轴上的位置,然后移动鼠标位置,通过辅助线观察变化。

基本的3D运动:

show sourceview source

print?

001
package {

002
import flash.display.Sprite;

003
import flash.events.Event;

004
import flash.events.KeyboardEvent;

005
import flash.ui.Keyboard;

006
import flash.display.StageAlign;

007
import flash.display.StageScaleMode;

008

009
public class Velocity3D extends Sprite {

010
private var ball:Ball;

011

012
//相当于消失点的坐标

013
private var xpos:Number=0;

014
private var ypos:Number=0;

015
private var zpos:Number=0;

016

017
//x,y,z三轴上的速度分量

018
private var vx:Number=0;

019
private var vy:Number=0;

020
private var vz:Number=0;

021

022
private var friction:Number=0.98;

023
private var fl:Number=250;

024

025
//消失点

026
private var vpX:Number=stage.stageWidth/2;

027
private var vpY:Number=stage.stageHeight/2;

028

029
public function Velocity3D() {

030
init();

031
}

032
private function init():void {

033
stage.align = StageAlign.TOP_LEFT;  

034
stage.scaleMode = StageScaleMode.NO_SCALE;

035
ball = new Ball(20);

036
addChild(ball);

037
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

038
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);

039
}

040
private function EnterFrameHandler(event:Event):void {

041
vpX =stage.stageWidth/2;

042
vpY =stage.stageHeight/2;

043

044
xpos+=vx;

045
ypos+=vy;

046
zpos+=vz;

047
vx*=friction;

048
vy*=friction;

049
vz*=friction;

050

051
if (zpos>-fl) {

052
var scale:Number = fl / (fl + zpos);

053
ball.scaleX=ball.scaleY=scale;

054
ball.x=vpX+xpos*scale;

055
ball.y=vpY+ypos*scale;

056
ball.visible=true;

057
} else {

058
ball.visible=false;

059
}

060

061
//辅助线

062
graphics.clear();

063
graphics.lineStyle(1,0xefefef);

064
graphics.moveTo(0,stage.stageHeight/2);

065
graphics.lineTo(stage.stageWidth,stage.stageHeight/2);

066
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2-8);

067
graphics.moveTo(stage.stageWidth,stage.stageHeight/2);

068
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2+8);

069

070
graphics.moveTo(stage.stageWidth/2,0);

071
graphics.lineTo(stage.stageWidth/2,stage.stageHeight);

072
graphics.lineTo(stage.stageWidth/2-8,stage.stageHeight-15);

073
graphics.moveTo(stage.stageWidth/2,stage.stageHeight);

074
graphics.lineTo(stage.stageWidth/2+8,stage.stageHeight-15);

075
graphics.lineStyle(1,0xdadada);

076
graphics.moveTo(vpX,vpY);

077
graphics.lineTo(ball.x,ball.y);

078

079

080
}

081
private function KeyDownHandler(e:KeyboardEvent):void {

082
switch (e.keyCode) {

083
case Keyboard.UP :

084
vy-=1;

085
break;

086
case Keyboard.DOWN :

087
vy+=1;

088
break;

089
case Keyboard.LEFT :

090
vx-=1;

091
break;

092
case Keyboard.RIGHT :

093
vx+=1;

094
break;

095
case Keyboard.SHIFT :

096
vz+=0.5;

097
break;

098
case Keyboard.CONTROL :

099
vz-=0.5;

100
break;

101
default :

102
break;

103
}

104
}

105
}

106
}

上下左右键控制x,y轴方向速度,shift/ctrl键控制z轴速度(当然这个示例还没考虑到3D环境中的边界反弹,下面就要谈到这个问题)

3维运动反弹:

这个需要一点想象力,二维情况下,通常只要把舞台的四个边当作边界就足够了,但是试想一下:在一个立体的空间里,要限制一个物体的活动范围,得要有6个边界面(上,下,左,右,前,后)

show sourceview source

print?

001
package {

002
import flash.display.Sprite;

003
import flash.events.Event;

004
import flash.display.StageAlign;

005
import flash.display.StageScaleMode;

006

007
public class Bounce3D extends Sprite {

008
private var ball:Ball;

009
private var xpos:Number=0;

010
private var ypos:Number=0;

011
private var zpos:Number=0;

012
private var vx:Number=Math.random()*12-6;

013
private var vy:Number=Math.random()*12-6;

014
private var vz:Number=Math.random()*12-6;

015
private var fl:Number=250;

016

017
//消失点

018
private var vpX:Number=stage.stageWidth/2;

019
private var vpY:Number=stage.stageHeight/2;

020

021
//相对于消失点的六个边界面(上,下,左,右,前,后)

022
private var top:Number=-100;

023
private var bottom:Number=100;

024
private var left:Number=-100;

025
private var right:Number=100;

026
private var front:Number=100;

027
private var back:Number=-100;

028

029
public function Bounce3D() {

030
init();

031
}

032
private function init():void {

033
stage.align = StageAlign.TOP_LEFT;  

034
stage.scaleMode = StageScaleMode.NO_SCALE;

035
ball=new Ball(15);

036
addChild(ball);

037
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

038
}

039
private function EnterFrameHandler(event:Event):void {

040
vpX =stage.stageWidth/2;

041
vpY =stage.stageHeight/2

042

043
xpos+=vx;

044
ypos+=vy;

045
zpos+=vz;

046
var radius:Number=ball.radius;

047
//左右边界

048
if (xpos+radius>right) {

049
xpos=right-radius;

050
vx*=-1;

051
} else if (xpos - radius < left) {

052
xpos=left+radius;

053
vx*=-1;

054
}

055
//上下边界

056
if (ypos+radius>bottom) {                

057
ypos=bottom-radius;

058
vy*=-1;

059
} else if (ypos - radius < top) {

060
ypos=top+radius;

061
vy*=-1;

062
}

063
//前后边界

064
if (zpos+radius>front) {

065
zpos=front-radius;

066
vz*=-1;

067
} else if (zpos - radius < back) {

068
zpos=back+radius;

069
vz*=-1;

070
}

071

072
//换算成平面二维坐标及缩放比率

073
if (zpos>- fl) {

074
var scale:Number = fl / (fl + zpos);

075
ball.scaleX=ball.scaleY=scale;

076
ball.x=vpX+xpos*scale;

077
ball.y=vpY+ypos*scale;

078
ball.visible=true;

079
} else {

080
ball.visible=false;

081
}

082

083
//辅助线

084
graphics.clear();

085
graphics.lineStyle(1,0xccccff);

086
graphics.moveTo(0,stage.stageHeight/2);

087
graphics.lineTo(stage.stageWidth,stage.stageHeight/2);

088
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2-8);

089
graphics.moveTo(stage.stageWidth,stage.stageHeight/2);

090
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2+8);

091

092
graphics.moveTo(0,stage.stageHeight);

093
graphics.lineTo(stage.stageWidth,0);

094
graphics.lineTo(stage.stageWidth-15,2);

095
graphics.moveTo(stage.stageWidth,0);

096
graphics.lineTo(stage.stageWidth-6,13);

097

098
graphics.moveTo(stage.stageWidth/2,0);

099
graphics.lineTo(stage.stageWidth/2,stage.stageHeight);

100
graphics.lineTo(stage.stageWidth/2-8,stage.stageHeight-15);

101
graphics.moveTo(stage.stageWidth/2,stage.stageHeight);

102
graphics.lineTo(stage.stageWidth/2+8,stage.stageHeight-15);

103
graphics.lineStyle(1,0xffccff);

104
graphics.moveTo(vpX,vpY);

105
graphics.lineTo(ball.x,ball.y);

106
}

107
}

108
}

也许这样看得并不清楚,再加入更多的小球反弹,可能更容易理解一些,不过为了方便代码处理,先定义一个新的小球类:Ball3D

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
public class Ball3D extends Sprite {

04
public var radius:Number;

05
private var color:uint;

06
public var xpos:Number=0;

07
public var ypos:Number=0;

08
public var zpos:Number=0;

09
public var vx:Number=0;

10
public var vy:Number=0;

11
public var vz:Number=0;

12
public var mass:Number=1;

13
public function Ball3D(radius:Number=40, color:uint=0xff0000) {

14
this.radius=radius;

15
this.color=color;

16
init();

17
}

18
public function init():void {

19
graphics.lineStyle(0);

20
graphics.beginFill(color);

21
graphics.drawCircle(0, 0, radius);

22
graphics.endFill();

23
}

24
}

25
}

多个小球的3D反弹:

show sourceview source

print?

001
package {

002
import flash.display.Sprite;

003
import flash.events.Event;

004
import flash.display.StageAlign;

005
import flash.display.StageScaleMode;

006

007
public class MultiBounce3D extends Sprite {

008
private var balls:Array;

009
private var numBalls:uint=20;

010
private var fl:Number=250;

011
private var vpX:Number=stage.stageWidth/2;

012
private var vpY:Number=stage.stageHeight/2;

013
private var top:Number=-120;

014
private var bottom:Number=120;

015
private var left:Number=-120;

016
private var right:Number=120;

017
private var front:Number=120;

018
private var back:Number=-120;

019
public function MultiBounce3D() {

020
init();

021
}

022
private function init():void {

023
stage.align = StageAlign.TOP_LEFT;  

024
stage.scaleMode = StageScaleMode.NO_SCALE;

025
balls = new Array();

026
for (var i:uint = 0; i < numBalls; i++) {

027
var ball:Ball3D=new Ball3D(15,Math.random()*0xffffff);

028
balls.push(ball);

029
ball.vx=Math.random()*10-5;

030
ball.vy=Math.random()*10-5;

031
ball.vz=Math.random()*10-5;

032
addChild(ball);

033
}

034
addEventListener(Event.ENTER_FRAME, onEnterFrame);

035
}

036
private function onEnterFrame(event:Event):void {

037
vpX =stage.stageWidth/2;

038
vpY =stage.stageHeight/2

039
graphics.clear();

040
for (var i:uint = 0; i < numBalls; i++) {

041
var ball:Ball3D=balls[i];               

042
move(ball);

043
}

044
}

045
private function move(ball:Ball3D):void {

046
var radius:Number=ball.radius;

047
ball.xpos+=ball.vx;

048
ball.ypos+=ball.vy;

049
ball.zpos+=ball.vz;

050

051
//6边界检测

052
if (ball.xpos+radius>right) {

053
ball.xpos=right-radius;

054
ball.vx*=-1;

055
} else if (ball.xpos - radius < left) {

056
ball.xpos=left+radius;

057
ball.vx*=-1;

058
}

059
if (ball.ypos+radius>bottom) {

060
ball.ypos=bottom-radius;

061
ball.vy*=-1;

062
} else if (ball.ypos - radius < top) {

063
ball.ypos=top+radius;

064
ball.vy*=-1;

065
}

066
if (ball.zpos+radius>front) {

067
ball.zpos=front-radius;

068
ball.vz*=-1;

069
} else if (ball.zpos - radius < back) {

070
ball.zpos=back+radius;

071
ball.vz*=-1;

072
}

073

074
//转换化2D坐标

075
if (ball.zpos>- fl) {

076
var scale:Number = fl / (fl + ball.zpos);

077
ball.scaleX=ball.scaleY=scale;

078
ball.x=vpX+ball.xpos*scale;

079
ball.y=vpY+ball.ypos*scale;

080
ball.visible=true;

081
} else {

082
ball.visible=false;

083
}

084

085
//辅助线           

086
graphics.lineStyle(1,0xccccff);

087
graphics.moveTo(0,stage.stageHeight/2);

088
graphics.lineTo(stage.stageWidth,stage.stageHeight/2);

089
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2-8);

090
graphics.moveTo(stage.stageWidth,stage.stageHeight/2);

091
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2+8);

092

093
graphics.moveTo(0,stage.stageHeight);

094
graphics.lineTo(stage.stageWidth,0);

095
graphics.lineTo(stage.stageWidth-15,2);

096
graphics.moveTo(stage.stageWidth,0);

097
graphics.lineTo(stage.stageWidth-6,13);

098

099
graphics.moveTo(stage.stageWidth/2,0);

100
graphics.lineTo(stage.stageWidth/2,stage.stageHeight);

101
graphics.lineTo(stage.stageWidth/2-8,stage.stageHeight-15);

102
graphics.moveTo(stage.stageWidth/2,stage.stageHeight);

103
graphics.lineTo(stage.stageWidth/2+8,stage.stageHeight-15);

104
graphics.lineStyle(1,0xff99ff);

105
graphics.moveTo(vpX,vpY);

106
graphics.lineTo(ball.x,ball.y);

107
}

108
}

109
}

仔细观察一下,相信不少人会发现问题:物体的前后顺序不对,远处的物体居然挡住了近处的物体。(css中可以通过z-Index来调整,silverlight的canvas中也有类似的zIndex,但在As3中如何做呢?)

先跑一下题,来看一个小技巧:Object 数组的排序

view source

print?

1
var arrTest = [{age:20,name:"a"},{age:50,name:"b"},{age:30,name:"c"}]

2
arrTest.sortOn("age",Array.DESCENDING);//按age值倒排

3
for(var i:int=0,j=arrTest.length;i<j;i++){

4
trace(arrTest[i].age ,arrTest[i].name);

5
}

是不是很好用!

ok,问题解决了:Flash的显示列表中,最后被addChild的物体总是显示在上面,在Flash内部"舞台上的每个物体"都对应一个索引值,随着物体不断被添加到舞台上,其对应的索引值也不断增加,我们可以通过调整索引值来改变物体的显示顺序.

基本测试:

show sourceview source

print?

01
var ballA = new Ball(50);

02
ballA.x = stage.stageWidth/2;

03
ballA.y = stage.stageHeight/2;

04
addChild(ballA);

05

06
var ballB = new Ball(45,0x0000ff);

07
ballB.x = ballA.x;

08
ballB.y = ballA.y + 20;

09
addChild(ballB);

10

11
btn1.addEventListener(MouseEvent.MOUSE_DOWN,btn1Click);

12

13
function btn1Click(e:MouseEvent):void{

14
setChildIndex(ballB,0);

15
setChildIndex(ballA,1);

16
}

17

18
btn2.addEventListener(MouseEvent.MOUSE_DOWN,btn2Click);

19

20
function btn2Click(e:MouseEvent):void{

21
setChildIndex(ballB,1);

22
setChildIndex(ballA,0);

23
}

调整后的3D反弹

show sourceview source

print?

001
package {

002
import flash.display.Sprite;

003
import flash.events.Event;

004
import flash.display.StageAlign;

005
import flash.display.StageScaleMode;

006

007
public class MultiBounce3D extends Sprite {

008
private var balls:Array;

009
private var numBalls:uint=20;

010
private var fl:Number=250;

011
private var vpX:Number=stage.stageWidth/2;

012
private var vpY:Number=stage.stageHeight/2;

013
private var top:Number=-120;

014
private var bottom:Number=120;

015
private var left:Number=-120;

016
private var right:Number=120;

017
private var front:Number=120;

018
private var back:Number=-120;

019
public function MultiBounce3D() {

020
init();

021
}

022
private function init():void {

023
stage.align=StageAlign.TOP_LEFT;

024
stage.scaleMode=StageScaleMode.NO_SCALE;

025
balls = new Array();

026
for (var i:uint = 0; i < numBalls; i++) {

027
var ball:Ball3D=new Ball3D(15,Math.random()*0xffffff);

028
balls.push(ball);

029
ball.vx=Math.random()*10-5;

030
ball.vy=Math.random()*10-5;

031
ball.vz=Math.random()*10-5;

032
addChild(ball);

033
}

034
addEventListener(Event.ENTER_FRAME, onEnterFrame);

035
}

036
private function onEnterFrame(event:Event):void {

037
vpX=stage.stageWidth/2;

038
vpY=stage.stageHeight/2;

039
graphics.clear();

040
for (var i:uint = 0; i < numBalls; i++) {

041
var ball:Ball3D=balls[i];

042
move(ball);

043
}

044
sortZ();

045
}

046

047
function sortZ():void {

048
balls.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

049
for (var i:uint = 0; i < numBalls; i++) {

050
var ball:Ball3D=balls[i];

051
setChildIndex(ball, i);

052
}

053
}

054

055
private function move(ball:Ball3D):void {

056
var radius:Number=ball.radius;

057
ball.xpos+=ball.vx;

058
ball.ypos+=ball.vy;

059
ball.zpos+=ball.vz;

060

061
//6边界检测

062
if (ball.xpos+radius>right) {

063
ball.xpos=right-radius;

064
ball.vx*=-1;

065
} else if (ball.xpos - radius < left) {

066
ball.xpos=left+radius;

067
ball.vx*=-1;

068
}

069
if (ball.ypos+radius>bottom) {

070
ball.ypos=bottom-radius;

071
ball.vy*=-1;

072
} else if (ball.ypos - radius < top) {

073
ball.ypos=top+radius;

074
ball.vy*=-1;

075
}

076
if (ball.zpos+radius>front) {

077
ball.zpos=front-radius;

078
ball.vz*=-1;

079
} else if (ball.zpos - radius < back) {

080
ball.zpos=back+radius;

081
ball.vz*=-1;

082
}

083

084
//转换化2D坐标

085
if (ball.zpos>- fl) {

086
var scale:Number = fl / (fl + ball.zpos);

087
ball.scaleX=ball.scaleY=scale;

088
ball.x=vpX+ball.xpos*scale;

089
ball.y=vpY+ball.ypos*scale;

090
ball.visible=true;

091
} else {

092
ball.visible=false;

093
}

094

095
//辅助线

096
graphics.lineStyle(1,0xccccff);

097
graphics.moveTo(0,stage.stageHeight/2);

098
graphics.lineTo(stage.stageWidth,stage.stageHeight/2);

099
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2-8);

100
graphics.moveTo(stage.stageWidth,stage.stageHeight/2);

101
graphics.lineTo(stage.stageWidth-15,stage.stageHeight/2+8);

102

103
graphics.moveTo(0,stage.stageHeight);

104
graphics.lineTo(stage.stageWidth,0);

105
graphics.lineTo(stage.stageWidth-15,2);

106
graphics.moveTo(stage.stageWidth,0);

107
graphics.lineTo(stage.stageWidth-6,13);

108

109
graphics.moveTo(stage.stageWidth/2,0);

110
graphics.lineTo(stage.stageWidth/2,stage.stageHeight);

111
graphics.lineTo(stage.stageWidth/2-8,stage.stageHeight-15);

112
graphics.moveTo(stage.stageWidth/2,stage.stageHeight);

113
graphics.lineTo(stage.stageWidth/2+8,stage.stageHeight-15);

114
graphics.lineStyle(1,0xff99ff);

115
graphics.moveTo(vpX,vpY);

116
graphics.lineTo(ball.x,ball.y);

117
}

118
}

119
}

3D粒子喷射:

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
import flash.events.Event;

04
import flash.display.StageAlign;

05
import flash.display.StageScaleMode;

06

07
//设置动画背景为黑色 

08
[SWF(backgroundColor=0x000000)]//c#中的特性? 哈

09
public class Fireworks extends Sprite {

10
private var balls:Array;

11
private var numBalls:uint=100;

12
private var fl:Number=250;

13
//消失点

14
private var vpX:Number=stage.stageWidth/2;

15
private var vpY:Number=stage.stageHeight/2;

16
private var gravity:Number=0.2;

17
private var floor:Number=50;//y轴反弹的边界(相对消失点而言)

18
private var bounce:Number=-0.6;

19
public function Fireworks() {

20
init();

21
}

22

23
private function init():void {

24
stage.scaleMode = StageScaleMode.NO_SCALE;

25
stage.align = StageAlign.TOP_LEFT;

26
balls = new Array();

27
for (var i:uint = 0; i < numBalls; i++) {

28
var ball:Ball3D=new Ball3D(5,Math.random()*0xffffff);

29
balls.push(ball);               

30
addChild(ball);

31
}

32
initVelocity();

33
addEventListener(Event.ENTER_FRAME, onEnterFrame);

34

35
}

36

37
private function initVelocity():void{

38
for (var i:uint = 0; i < numBalls; i++) {

39
var ball:Ball3D=balls[i];

40
reset(ball);

41
}           

42
}

43

44
private function reset(b:Ball3D):void{

45
b.ypos=-250;

46
b.zpos=200;     

47
b.xpos=0;

48
b.vx=(Math.random()*2-1)*3 //x轴方向速度为-3到+3的随机值(即:看起来有的球向左,有的球向右,在横向扩散)

49
b.vy=(Math.random()-1)*4; //y轴方向为-4到0之间的随机值(即向下掉)

50
b.vz=(Math.random()-1)*3//z轴方向速度为-3到0的随机值(即:所有球从远处向近处喷)

51

52
}

53

54
private function onEnterFrame(event:Event):void {           

55
for (var i:uint = 0; i < numBalls; i++) {

56
var ball:Ball3D=balls[i];

57
move(ball);

58
}

59
sortZ();

60
}

61
private function move(ball:Ball3D):void {

62
ball.vy+=gravity;

63
ball.xpos+=ball.vx;

64
ball.ypos+=ball.vy;

65
ball.zpos+=ball.vz;

66
if (ball.ypos>floor) {

67
ball.ypos=floor;

68
ball.vy*=bounce;

69
}

70
if (ball.zpos>-fl) {

71
var scale:Number = fl / (fl + ball.zpos);

72
ball.scaleX=ball.scaleY=scale;

73
ball.x=vpX+ball.xpos*scale;

74
ball.y=vpY+ball.ypos*scale;

75
ball.alpha = scale;//越远的物体,越淡

76
if (ball.x<0 || ball.x>stage.stageWidth || ball.y>stage.stageHeight || ball.alpha<0.05){

77
reset(ball);

78
}

79
ball.visible=true;

80
} else {

81
ball.visible=false;

82
reset(ball);

83
}

84
}

85
private function sortZ():void {

86
balls.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

87
for (var i:uint = 0; i < numBalls; i++) {

88
var ball:Ball3D=balls[i];

89
setChildIndex(ball, i);

90
}

91
}

92
}

93
}

Z轴上的屏幕环绕:

类似2d中的处理,当物体在z轴的坐标达到某一限定值时,重新将其设置为相反值,通俗点讲:物体太远(接近看不见时),重新将其放在无限近的地方(通常是观察者背后),物体太近(甚至跑到观察者背后时),重新将其放在无限远处.

show sourceview source

print?

01
var trees:Array;

02
var numTrees:uint=100;

03
var fl:Number=250;

04
var vpX:Number=stage.stageWidth/2;

05
var vpY:Number=stage.stageHeight/2;

06
var floor:Number=50;

07
var vz:Number=0;

08
var friction:Number=0.98;

09
var temp:Number=0;

10

11

12
function init():void {

13
trees = new Array();

14
for (var i:uint = 0; i < numTrees; i++) {

15
var tree:Tree = new Tree();

16
trees.push(tree);

17
tree.xpos=Math.random()*2000-1000;

18
tree.ypos=floor;

19
tree.zpos=Math.random()*10000;

20
addChild(tree);

21
}

22
addEventListener(Event.ENTER_FRAME, EnterFrameHandler);

23
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);

24
}

25

26
function EnterFrameHandler(event:Event):void {

27
for (var i:uint = 0; i < numTrees; i++) {

28
var tree:Tree=trees[i];

29
move(tree);

30
}

31
vz*=friction;

32
sortZ();

33

34
//自动播放的处理

35
if (temp>500) {

36
vz-=0.5;        

37
} else {

38
vz+=0.5;

39
}

40
temp++; 

41
if (temp==1000){

42
temp=0;

43
}   

44
trace(temp);

45
}

46

47
//按上下键时的速度处理

48
function KeyDownHandler(event:KeyboardEvent):void {

49
if (event.keyCode==Keyboard.UP) {

50
vz-=1;

51
} else if (event.keyCode == Keyboard.DOWN) {

52
vz+=1;

53
}

54
}

55

56

57
function move(tree:Tree):void {

58
tree.zpos+=vz;

59

60
//如果物体跑到观察点后面了,则重新将其放在无限远处

61
if (tree.zpos<fl*-1) {

62
tree.zpos+=10000;

63
}

64

65
//如果物体跑得太远了,重新将其放在观察点身后

66
if (tree.zpos>10000-fl) {

67
tree.zpos-=10000;

68
}

69

70
var scale:Number = fl / (fl + tree.zpos);

71
tree.scaleX=tree.scaleY=scale;

72
tree.x=vpX+tree.xpos*scale;

73
tree.y=vpY+tree.ypos*scale;

74
tree.alpha=scale*0.8+0.2;

75
}

76

77
//z轴排序

78
function sortZ():void {

79
trees.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

80
for (var i:uint = 0; i < numTrees; i++) {

81
var tree:Tree=trees[i];

82
setChildIndex(tree, i);

83
}

84
}

85

86
init();

这个示例中用到了一个新的类Tree,代码如下:

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
public class Tree extends Sprite {

04
public var xpos:Number=0;

05
public var ypos:Number=0;

06
public var zpos:Number=0;

07
public function Tree() {

08
init();

09
}

10
public function init():void {

11
graphics.lineStyle(0,0xffffff);

12
graphics.lineTo(0,-140-Math.random()*20);

13
graphics.moveTo(0,-30-Math.random()*30);

14
graphics.lineTo(Math.random()*80-40,-100-Math.random()*40);

15
graphics.moveTo(0,-60-Math.random()*40);

16
graphics.lineTo(Math.random()*60-30,-110-Math.random()*20);

17
}

18
}

19
}

上面这个示例的加强版:(左右键控制x轴加速度,上下键控制z轴加速度,空格键整体下落)

show sourceview source

print?

001
package {

002
import flash.display.Sprite;

003
import flash.events.Event;

004
import flash.events.KeyboardEvent;

005
import flash.ui.Keyboard;

006

007
[SWF(backgroundColor=0x000000)]

008
public class Trees2 extends Sprite {

009
private var trees:Array;

010
private var numTrees:uint=100;

011

012
private var fl:Number=250;

013

014
//消失点

015
private var vpX:Number=stage.stageWidth/2;

016
private var vpY:Number=stage.stageHeight/2;

017

018
private var floor:Number=50;

019

020

021
//加速度

022
private var ax:Number=0;

023
private var ay:Number=0;

024
private var az:Number=0;

025

026
//速度

027
private var vx:Number=0;

028
private var vy:Number=0;

029
private var vz:Number=0;

030

031
//重力与摩擦力

032
private var gravity:Number=0.3;

033
private var friction:Number=0.98;

034

035
public function Trees2() {

036
init();

037
}

038

039
private function init():void {

040
trees = new Array();

041
for (var i:uint = 0; i < numTrees; i++) {

042
var tree:Tree = new Tree();

043
trees.push(tree);

044
tree.xpos=Math.random()*2000-1000;

045
tree.ypos=floor;

046
tree.zpos=Math.random()*10000;

047
addChild(tree);

048
}

049
addEventListener(Event.ENTER_FRAME, onEnterFrame);

050
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);

051
stage.addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);

052
}

053

054
private function onEnterFrame(event:Event):void {

055
vx+=ax;

056
vy+=ay;

057
vz+=az;

058
vy-=gravity;//负重力?哈,好好理解一下,这一行结合后面的y轴坐标检测,才保证了所有树在空格键松开时,能在y轴方向上恢复原状

059
for (var i:uint = 0; i < numTrees; i++) {

060
var tree:Tree=trees[i];

061
move(tree);

062
}

063
vx*=friction;

064
vy*=friction;

065
vz*=friction;

066
sortZ();

067
}

068

069
//键盘按下时,处理加速度

070
private function KeyDownHandler(event:KeyboardEvent):void {

071
switch (event.keyCode) {

072
case Keyboard.UP :

073
az=-1;

074
break;

075
case Keyboard.DOWN :

076
az=1;

077
break;

078
case Keyboard.LEFT :

079
ax=1;

080
break;

081
case Keyboard.RIGHT :

082
ax=-1;

083
break;

084
case Keyboard.SPACE :

085
ay=1;

086
break;

087
default :

088
break;

089
}

090
}

091

092
//按键抬起时,加速度置0

093
private function KeyUpHandler(event:KeyboardEvent):void {

094
switch (event.keyCode) {

095
case Keyboard.UP :

096
case Keyboard.DOWN :

097
az=0;

098
break;

099
case Keyboard.LEFT :

100
case Keyboard.RIGHT :

101
ax=0;

102
break;

103
case Keyboard.SPACE :

104
ay=0;

105
break;

106
default :

107
break;

108
}

109
}

110

111

112
private function move(tree:Tree):void {

113
tree.xpos+=vx;

114
tree.ypos+=vy;

115
tree.zpos+=vz;

116

117

118
//y轴上的坐标判断,否则所有树将一直向上跑

119
if (tree.ypos<floor) {

120
tree.ypos=floor;

121
}

122

123
//z轴屏幕环绕

124
if (tree.zpos<fl*-1) {

125
tree.zpos+=10000;

126
}

127
if (tree.zpos>10000-fl) {

128
tree.zpos-=10000;

129
}

130

131
var scale:Number = fl / (fl + tree.zpos);

132
tree.scaleX=tree.scaleY=scale;

133
tree.x=vpX+tree.xpos*scale;

134
tree.y=vpY+tree.ypos*scale;

135
tree.alpha=scale*0.8 + 0.2;

136
}

137

138
//z轴排序

139
private function sortZ():void {

140
trees.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

141
for (var i:uint = 0; i < numTrees; i++) {

142
var tree:Tree=trees[i];

143
setChildIndex(tree, i);

144
}

145
}

146
}

147
}

3D缓动:

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
import flash.events.Event;

04
public class Easing3D extends Sprite {      

05
private var balls:Array;

06
private var ballNum:Number=20;

07
private var easing:Number=.1;

08
private var fl:Number=250;

09
private var vpX:Number=stage.stageWidth/2;

10
private var vpY:Number=stage.stageHeight/2;

11

12
public function Easing3D() {

13
init();

14
}

15
private function init():void {

16
balls=new Array(ballNum);

17
for (var i:int=0; i<ballNum; i++) {

18
balls[i]=new Ball3D(20,Math.random()*0xffffff);

19
balls[i].tx=(Math.random()*2-1)*200;

20
balls[i].ty=(Math.random()*2-1)*200;

21
balls[i].tz=(Math.random()*2-1)*500;

22
addChild(balls[i]);

23
}

24
addEventListener(Event.ENTER_FRAME, onEnterFrame);

25
}

26

27

28
private function onEnterFrame(event:Event):void {

29
for (var i:int=0; i<ballNum; i++) {

30
move(balls[i]);

31
}

32
sortZ();

33
}

34

35
function move(b:Ball3D):void {

36
var dx:Number=b.tx-b.xpos;

37
var dy:Number=b.ty-b.ypos;

38
var dz:Number=b.tz-b.zpos;

39
//缓动公式

40
b.xpos+=dx*easing;

41
b.ypos+=dy*easing;

42
b.zpos+=dz*easing;

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

44
if (dist<1) {

45
b.tx=(Math.random()*2-1)*200;

46
b.ty=(Math.random()*2-1)*200;

47
b.tz=(Math.random()*2-1)*500;

48
}

49
if (b.zpos > -fl) {

50
var scale:Number = fl / (fl + b.zpos);

51
b.scaleX=b.scaleY=scale;

52
b.x=vpX+b.xpos*scale;

53
b.y=vpY+b.ypos*scale;

54
b.alpha=scale*0.7+0.3;

55
b.visible=true;

56
} else {

57
b.visible=false;

58
}

59
}

60

61
//z轴排序  

62
function sortZ():void {

63
balls.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

64
for (var i:uint = 0; i < ballNum; i++) {

65
var b:Ball3D=balls[i];

66
setChildIndex(b, i);

67
}

68

69
}

70

71

72
}

73
}

当然这个示例中,要对Ball3D做一些改造:

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
public class Ball3D extends Sprite {

04
public var radius:Number;

05
private var color:uint;

06

07
public var xpos:Number=0;

08
public var ypos:Number=0;

09
public var zpos:Number=0;

10

11
public var vx:Number=0;

12
public var vy:Number=0;

13
public var vz:Number=0;

14

15
public var tx:Number=0;

16
public var ty:Number=0;

17
public var tz:Number=0;

18

19
public var mass:Number=1;

20

21
public function Ball3D(radius:Number=40, color:uint=0xff0000) {

22
this.radius=radius;

23
this.color=color;

24
init();

25
}

26
public function init():void {

27
graphics.lineStyle(0);

28
graphics.beginFill(color);

29
graphics.drawCircle(0, 0, radius);

30
graphics.endFill();

31
}

32
}

33
}

3D弹性运动:

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
import flash.events.Event;

04
import flash.events.MouseEvent;

05
public class Spring3D extends Sprite {

06

07
private var balls:Array;

08
private var ballNum:Number=20;

09

10
private var spring:Number=.1;

11
private var friction:Number=.94;

12
private var fl:Number=250;

13
private var vpX:Number=stage.stageWidth/2;

14
private var vpY:Number=stage.stageHeight/2;

15

16
var temp:Number = 0;

17

18
public function Spring3D() {

19
init();

20
}

21
private function init():void {

22
balls=new Array(ballNum);

23
for (var i:int=0; i<ballNum; i++) {

24
balls[i]=new Ball3D(20,Math.random()*0xffffff);

25
balls[i].tx=(Math.random()*2-1)*200;

26
balls[i].ty=(Math.random()*2-1)*200;

27
balls[i].tz=(Math.random()*2-1)*300;

28
addChild(balls[i]);

29
}

30
addEventListener(Event.ENTER_FRAME, onEnterFrame);

31

32
}

33
private function onEnterFrame(event:Event):void {

34
for (var i:int=0; i<ballNum; i++) {

35
move(balls[i]);

36
}

37
sortZ();

38

39
temp++;

40
if (temp>=250){

41
reset();

42
temp=0;

43
}

44
//trace(temp);

45
}

46

47
function move(b:Ball3D):void {

48
var dx:Number=b.tx-b.xpos;

49
var dy:Number=b.ty-b.ypos;

50
var dz:Number=b.tz-b.zpos;

51
b.vx+=dx*spring;

52
b.vy+=dy*spring;

53
b.vz+=dz*spring;

54
b.xpos+=b.vx;

55
b.ypos+=b.vy;

56
b.zpos+=b.vz;

57
b.vx*=friction;

58
b.vy*=friction;

59
b.vz*=friction;

60
if (b.zpos>- fl) {

61
var scale:Number = fl / (fl + b.zpos);

62
b.scaleX=b.scaleY=scale;

63
b.x=vpX+b.xpos*scale;

64
b.y=vpY+b.ypos*scale;

65
b.alpha=scale*0.8+0.2;

66
b.visible=true;

67
} else {

68
b.visible=false;

69
}

70
}

71

72
private function reset():void {

73
for (var i:int=0; i<ballNum; i++) {

74
balls[i].tx=(Math.random()*2-1)*200;

75
balls[i].ty=(Math.random()*2-1)*200;

76
balls[i].tz=(Math.random()*2-1)*300;

77
}

78
}

79

80
//z轴排序  

81
function sortZ():void {

82
balls.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

83
for (var i:uint = 0; i < ballNum; i++) {

84
var b:Ball3D=balls[i];

85
setChildIndex(b, i);

86
}

87

88
}

89
}

90
}

3D坐标旋转:

其实跟2D坐标旋转几乎完全相同,只不过要指定绕哪个轴旋转

绕z轴旋转

x1 = cos(angleZ) * x - sin(angleZ) * y;
y1 = cos(angleZ) * y + sin(angleZ) * x;

绕y轴旋转
x1 = cos(angleY) * x - sin(angleY) * z;
z1 = cos(angleY) * z + sin(angleY) * x;

绕x轴旋转
y1 = cos(angleX) * y - sin(angleX) * z;
z1 = cos(angleX) * z + sin(angleX) * y;

show sourceview source

print?

01
package {

02
import flash.display.Sprite;

03
import flash.events.Event;

04
public class RotateY extends Sprite {

05
private var balls:Array;

06
private var numBalls:uint=50;

07

08
private var fl:Number=250;

09
private var vpX:Number=stage.stageWidth/2;

10
private var vpY:Number=stage.stageHeight/2;

11
public function RotateY() {

12
init();

13
}

14
private function init():void {

15
balls = new Array();

16
for (var i:uint = 0; i < numBalls; i++) {

17
var ball:Ball3D=new Ball3D(10,Math.random()*0xffffff);

18
balls.push(ball);

19
ball.xpos=Math.random()*200-100;

20
ball.ypos=Math.random()*200-100;

21
ball.zpos=(Math.random()*2-1)*100;

22
addChild(ball);

23
}

24
addEventListener(Event.ENTER_FRAME, onEnterFrame);

25
}

26
private function onEnterFrame(event:Event):void {

27
var angleY:Number = (mouseX - vpX) * .0004;//旋转的角度与鼠标的水平位置关联

28
for (var i:uint = 0; i < numBalls; i++) {

29
var ball:Ball3D=balls[i];

30
rotateY(ball, angleY);

31
}

32
sortZ();

33
}

34

35
//绕y轴旋转

36
private function rotateY(ball:Ball3D, angleY:Number):void {

37
var cosY:Number=Math.cos(angleY);

38
var sinY:Number=Math.sin(angleY);

39
var x1:Number=ball.xpos*cosY-ball.zpos*sinY;

40
var z1:Number=ball.zpos*cosY+ball.xpos*sinY;

41
ball.xpos=x1;

42
ball.zpos=z1;

43
if (ball.zpos>- fl) {

44
var scale:Number = fl / (fl + ball.zpos);

45
ball.scaleX=ball.scaleY=scale;

46
ball.x=vpX+ball.xpos*scale;

47
ball.y=vpY+ball.ypos*scale;

48
ball.alpha = scale*0.8;

49
ball.visible=true;

50
} else {

51
ball.visible=false;

52
}

53
}

54
private function sortZ():void {

55
balls.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

56
for (var i:uint = 0; i < numBalls; i++) {

57
var ball:Ball3D=balls[i];

58
setChildIndex(ball, i);

59
}

60
}

61
}

62
}

这个示例还可以扩充到3个轴的同时旋转:

show sourceview source

print?

01
var balls:Array;

02
var numBalls:uint=50;

03

04
var fl:Number=250;

05
var vpx:Number=stage.stageWidth/2;

06
var vpy:Number=stage.stageHeight/2;

07

08
function init():void {

09
balls=new Array(numBalls);

10
for (var i:uint=0; i<numBalls; i++) {

11
var ball:Ball3D=new Ball3D(10,Math.random()*0xffffff);

12
balls[i]=ball;

13
ball.xpos = (Math.random()*2-1)*100;

14
ball.ypos = (Math.random()*2-1)*100;

15
ball.zpos = (Math.random()*2-1)*100;

16
addChild(ball);

17
}

18
addEventListener(Event.ENTER_FRAME,EnterFrameHandler);

19
}

20

21
function EnterFrameHandler(e:Event):void {  

22
var dx:Number = mouseX - vpx;

23
var dy:Number = mouseY - vpy;   

24
var angleY:Number =dx*0.0005;

25
var angleX:Number =dy*0.0005;

26
var angleZ:Number = Math.sqrt(dx*dx + dy*dy)*0.0005;

27

28
if (dx>0){angleZ *=-1;}//以鼠标所在点的x坐标相对于消失点的位置为判断依据,左侧z轴正向旋转,右侧z轴反向旋转

29

30
for (var i:uint; i<numBalls; i++) {

31
var b:Ball3D=balls[i];

32
rotateX(b,angleX);

33
rotateY(b,angleY);

34
rotateZ(b,angleZ);

35
doPerspective(b);

36
}

37
sortZ();

38
}

39

40
//x轴的坐标旋转

41
function rotateX(ball:Ball3D, angleX:Number):void {

42
var cosX:Number=Math.cos(angleX);

43
var sinX:Number=Math.sin(angleX);

44
var y1:Number=ball.ypos*cosX-ball.zpos*sinX;

45
var z1:Number=ball.zpos*cosX+ball.ypos*sinX;

46
ball.ypos=y1;

47
ball.zpos=z1;

48
}

49

50
//y轴的坐标旋转

51
function rotateY(ball:Ball3D, angleY:Number):void {

52
var cosY:Number=Math.cos(angleY);

53
var sinY:Number=Math.sin(angleY);

54
var x1:Number=ball.xpos*cosY-ball.zpos*sinY;

55
var z1:Number=ball.zpos*cosY+ball.xpos*sinY;

56
ball.xpos=x1;

57
ball.zpos=z1;

58
}

59

60
//z轴的坐标旋转

61
function rotateZ(ball:Ball3D, angleZ:Number):void {

62
var cosZ:Number=Math.cos(angleZ);

63
var sinZ:Number=Math.sin(angleZ);

64
var x1:Number=ball.xpos*cosZ-ball.ypos*sinZ;

65
var y1:Number=ball.ypos*cosZ+ball.xpos*sinZ;

66
ball.xpos=x1;

67
ball.ypos=y1;

68
}

69

70
//3D透视处理

71
function doPerspective(ball:Ball3D):void {

72
if (ball.zpos>-fl) {

73
var scale:Number = fl / (fl + ball.zpos);

74
ball.scaleX=ball.scaleY=scale;

75
ball.x=vpx+ball.xpos*scale;

76
ball.y=vpy+ball.ypos*scale;

77
//ball.alpha = scale*0.65;

78
ball.visible=true;

79
} else {

80
ball.visible=false;

81
}

82
}

83

84
//z轴排序

85
function sortZ():void {

86
balls.sortOn("zpos",Array.DESCENDING|Array.NUMERIC);

87
for (var i:uint=0; i<numBalls; i++) {

88
setChildIndex(balls[i],i);

89
}

90
}

91

92
init();

3D碰撞检测:

基本原理仍然可以套用前面讲过的“基于距离的检测”,当二个球之间的距离小于二球的半径合时,即认为发生了碰撞,至于碰撞检测出来以后再如何处理,就要发挥想象了

show sourceview source

print?

001
package {

002
import flash.display.Sprite;

003
import flash.events.Event;

004
import flash.geom.ColorTransform;

005
public class Collision3D extends Sprite {

006
private var balls:Array;

007
private var numBalls:uint=8;

008
private var fl:Number=250;

009
private var vpX:Number=stage.stageWidth/2;

010

011
private var vpY:Number=stage.stageHeight/2;

012
private var top:Number=-100;

013
private var bottom:Number=100;

014
private var left:Number=-100;

015
private var right:Number=100;

016
private var front:Number=100;

017
private var back:Number=-100;

018
public function Collision3D() {

019
init();

020
}

021
private function init():void {

022
balls = new Array();

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

024
var ball:Ball3D=new Ball3D(10);

025
balls.push(ball);

026
ball.xpos=Math.random()*400-200;

027
ball.ypos=Math.random()*400-200;

028
ball.zpos=Math.random()*400-200;

029
ball.vx=Math.random()*10-5;

030
ball.vy=Math.random()*10-5;

031
ball.vz=Math.random()*10-5;

032
addChild(ball);

033
}

034
addEventListener(Event.ENTER_FRAME, onEnterFrame);

035
}

036
private function onEnterFrame(event:Event):void {

037
for (var i:uint = 0; i < numBalls; i++) {

038
var ball:Ball3D=balls[i];

039
move(ball);

040
}

041
for (i = 0; i < numBalls - 1; i++) {

042
var ballA:Ball3D=balls[i];

043
for (var j:uint = i + 1; j < numBalls; j++) {

044
var ballB:Ball3D=balls[j];

045
var dx:Number=ballA.xpos-ballB.xpos;

046
var dy:Number=ballA.ypos-ballB.ypos;

047
var dz:Number=ballA.zpos-ballB.zpos;

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

049
if (dist<ballA.radius+ballB.radius) {

050
var newTransform:ColorTransform =

051
new ColorTransform(0, 1, 1, 1, Math.random()*255, Math.random()*255, Math.random()*255, 0);

052
ballA.transform.colorTransform=newTransform;

053
ballB.transform.colorTransform=newTransform;

054
}

055
}

056
}

057
sortZ();

058
}

059
private function move(ball:Ball3D):void {

060

061
var radius:Number=ball.radius;

062
ball.xpos+=ball.vx;

063
ball.ypos+=ball.vy;

064
ball.zpos+=ball.vz;

065
if (ball.xpos+radius>right) {

066
ball.xpos=right-radius;

067
ball.vx*=-1;

068
} else if (ball.xpos - radius < left) {

069
ball.xpos=left+radius;

070
ball.vx*=-1;

071
}

072
if (ball.ypos+radius>bottom) {

073
ball.ypos=bottom-radius;

074
ball.vy*=-1;

075
} else if (ball.ypos - radius < top) {

076
ball.ypos=top+radius;

077
ball.vy*=-1;

078
}

079
if (ball.zpos+radius>front) {

080
ball.zpos=front-radius;

081
ball.vz*=-1;

082
} else if (ball.zpos - radius < back) {

083
ball.zpos=back+radius;

084
ball.vz*=-1;

085
}

086
if (ball.zpos>- fl) {

087
var scale:Number = fl / (fl + ball.zpos);

088
ball.scaleX=ball.scaleY=scale;

089
ball.x=vpX+ball.xpos*scale;

090
ball.y=vpY+ball.ypos*scale;

091
ball.visible=true;

092
} else {

093
ball.visible=false;

094
}

095
}

096
private function sortZ():void {

097
balls.sortOn("zpos", Array.DESCENDING | Array.NUMERIC);

098
for (var i:uint = 0; i < numBalls; i++) {

099
var ball:Ball3D=balls[i];

100
setChildIndex(ball, i);

101
}

102
}

103
}

104
}

上面的示例中,生二球发生碰撞后,颜色变为随机色(当然您可以处理根据前面讲过的动量守恒原理对速度做处理,不过在3D空间中要同时计算x,y,z三个轴的速度大小以及方向,运算量是比较大的,各位有兴趣可自行尝试)

原文地址:https://www.cnblogs.com/happysky97/p/1884605.html