zoukankan      html  css  js  c++  java
  • 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三个轴的速度大小以及方向,运算量是比较大的,各位有兴趣可自行尝试)

  • 相关阅读:
    jQuery中的一些操作
    laravel使用消息队列
    Laravel的开发环境Homestead的搭建与配置
    python爬虫学习
    配置文件
    sql根据时间差查询数据
    Oracle根据连接字符串获取库下的表列表、获取表结构
    Sql根据连接字符串获取库下的表列表、获取表结构
    判断网络连接
    线程锁,解决多线程并发问题
  • 原文地址:https://www.cnblogs.com/happysky97/p/1884605.html
Copyright © 2011-2022 走看看