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)
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运动:
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个边界面(上,下,左,右,前,后)
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
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反弹:
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 数组的排序
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内部"舞台上的每个物体"都对应一个索引值,随着物体不断被添加到舞台上,其对应的索引值也不断增加,我们可以通过调整索引值来改变物体的显示顺序.
基本测试:
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反弹
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粒子喷射:
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轴的坐标达到某一限定值时,重新将其设置为相反值,通俗点讲:物体太远(接近看不见时),重新将其放在无限近的地方(通常是观察者背后),物体太近(甚至跑到观察者背后时),重新将其放在无限远处.
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,代码如下:
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轴加速度,空格键整体下落)
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缓动:
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做一些改造:
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弹性运动:
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;
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个轴的同时旋转:
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碰撞检测:
基本原理仍然可以套用前面讲过的“基于距离的检测”,当二个球之间的距离小于二球的半径合时,即认为发生了碰撞,至于碰撞检测出来以后再如何处理,就要发挥想象了
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三个轴的速度大小以及方向,运算量是比较大的,各位有兴趣可自行尝试)
浙公网安备 33010602011771号