多边回弹效果

View Code
package cn.d
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.geom.Rectangle;

public class ballBounce extends Sprite
{
private var ball:Ball;
private var line:Sprite;

private var bounce:Number=-.93;

public function ballBounce()
{
super();
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;

init();
}

private function init():void
{
ball=new Ball;
ball.x=250;
ball.y=450;
this.addChild(ball);

line=new Sprite;
line.graphics.lineStyle(1);
line.graphics.moveTo(0, 0);
line.graphics.lineTo(1200, 0);

this.addChild(line);

line.y=500;
line.x=20;
line.rotation=10;

this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function onEnterFrame(e:Event):void
{
ball.vy+=2;
ball.x+=ball.vx;
ball.y+=ball.vy;

var rec:Rectangle=line.getBounds(this);

if (ball.x > rec.left && ball.x < rec.right)
{
var angle:Number=line.rotation * (Math.PI / 180);

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

var dx:Number=ball.x - line.x;
var dy:Number=ball.y - line.y;

var x1:Number=cos * dx + sin * dy;
var y1:Number=cos * dy - sin * dx;

var vx1:Number=cos * ball.vx + sin * ball.vy;
var vy1:Number=cos * ball.vy - sin * ball.vx;

if (y1 > -ball.height / 2)
{
y1=-ball.height / 2;
vy1*=bounce;

dx=cos * x1 - sin * y1;
dy=cos * y1 + sin * x1;

ball.vx=cos * vx1 - sin * vy1;
ball.vy=cos * vy1 + sin * vx1;

ball.x=line.x + dx;
ball.y=line.y + dy;
}
}

}

}
}
View Code
  1 package cn.d
2 {
3 import flash.display.Sprite;
4 import flash.display.StageAlign;
5 import flash.display.StageScaleMode;
6 import flash.events.Event;
7 import flash.geom.Rectangle;
8
9 public class MulBounce extends Sprite
10 {
11 private var ball:Ball;
12 private var lines:Array=[];
13
14 private var numhandle:int=5;
15 private var g:Number=.3;
16 private var bounce:Number=-.6;
17
18 public function MulBounce()
19 {
20 super();
21 stage.scaleMode=StageScaleMode.NO_SCALE;
22 stage.align=StageAlign.TOP_LEFT;
23
24 init();
25 }
26
27 private function init():void
28 {
29 ball=new Ball;
30 ball.x=100;
31 ball.y=20;
32
33 this.addChild(ball);
34
35 for (var i:int=0; i < numhandle; i++)
36 {
37 var line:Sprite=new Sprite;
38 this.addChild(line);
39
40 line.graphics.lineStyle(1);
41 line.graphics.moveTo(-50, 0);
42 line.graphics.lineTo(50, 0);
43
44 lines.push(line);
45 }
46
47 lines[0].x=100;
48 lines[0].y=100;
49 lines[0].rotation=30;
50
51 lines[1].x=100;
52 lines[1].y=230;
53 lines[1].rotation=45;
54
55 lines[2].x=250;
56 lines[2].y=180;
57 lines[2].rotation=-30;
58
59 lines[3].x=150;
60 lines[3].y=330;
61 lines[3].rotation=10;
62
63 lines[4].x=230;
64 lines[4].y=250;
65 lines[4].rotation=-30;
66
67 addEventListener(Event.ENTER_FRAME, onEnterFrame);
68 }
69
70 private function onEnterFrame(e:Event):void
71 {
72 ball.vy+=g;
73 ball.x+=ball.vx;
74 ball.y+=ball.vy;
75
76 if (ball.x + ball.radius < 0)
77 {
78 ball.x=ball.radius;
79 ball.vx*=bounce;
80 }
81 else if (ball.x + ball.radius > stage.stageWidth)
82 {
83 ball.x=stage.stageWidth - ball.radius;
84 ball.vx*=bounce;
85 }
86
87 if (ball.y + ball.radius < 0)
88 {
89 ball.y=ball.radius;
90 ball.vy*=bounce;
91 }
92 else if (ball.y + ball.radius > stage.stageHeight)
93 {
94 ball.y=stage.stageHeight-ball.radius;
95 ball.vy*=bounce;
96 }
97
98 for(var i:int=0;i<numhandle;i++)
99 {
100 checkBounds(lines[i]);
101 }
102 }
103
104 private function checkBounds(line:Sprite):void
105 {
106 var rec:Rectangle=line.getBounds(this);
107 if(ball.x>rec.left && ball.x<rec.right)
108 {
109 var angle:Number=line.rotation*(Math.PI/180);
110
111 var cos:Number=Math.cos(angle);
112 var sin:Number=Math.sin(angle);
113
114 var dx:Number=ball.x-line.x;
115 var dy:Number=ball.y-line.y;
116
117 var x1:Number=cos*dx+sin*dy;
118 var y1:Number=cos*dy-sin*dx;
119
120 var vx:Number=cos*ball.vx+sin*ball.vy;
121 var vy:Number=cos*ball.vy-sin*ball.vx;
122
123 if(y1>-ball.height/2 && y1<vy)
124 {
125 y1=-ball.height/2;
126 vy*=bounce;
127
128 dx=cos*x1-sin*y1;
129 dy=cos*y1+sin*x1;
130
131 ball.vx=cos*vx-sin*vy;
132 ball.vy=cos*vy+sin*vx;
133
134 ball.x=line.x+dx;
135 ball.y=line.y+dy;
136 }
137
138 }
139
140 }
141
142
143 }
144 }

我还记得在我刚刚开始痴迷于 Flash,数学和物体时,我就解决了物体撞墙地面、天花板后反弹的效果。如果这些障碍物只是水平和垂直的,我就知道该怎么去做。但是渐渐地仅知道这些已经不能满足需求了。在现实情况下,障碍物不仅仅只是水平或垂直的,而是带有一定角度的。这时就没法在 Flash 中模拟反弹效果了。于是,我就去各个 Flash 论坛问了一圈,发现我不是第一个问这个问题的人。在论坛里分别有三个帖子,讨论的题目都是“角度反弹”。 一些精通数学的版主试着回答这些问题。比如说反射角等于入射角。记得有个非常简单的公式告诉我们运动物体在碰撞到有角度的平面时,角度的变化。看起来不错,但也只是解决了一部分问题。我们回忆一下物体碰撞在障碍物后反弹的问题,总结出如下几步:

1.确实何时越过边界。

2.直接在边界上重置物体的位置。
3.改变碰撞轴上的速度。

知道最终的角度只解决了步骤 3 中一半的问题。但是并不能知道何时物体与斜面发生碰撞,也不知道物体碰撞前停止在斜面上的位置。似乎没人能回答这些问题。我试着用学过的所有知识来回答,画的图稿可以放满整个仓库,写的程序装满整个硬盘,可最后还是失败了。如果物体与平面碰撞那就太简单了,如果与斜面碰撞就太难了。但是为什么要在本章讨论这个内容呢。

那时,www.illogicz.com 的 Stuart Schoneveld 已经制作出超强的在线物理引擎,并且可以实现这种平滑干净的碰撞。

后来,我求他给我一些参考信息,他没有给我任何代码,只用了一两句话说明了整体思想,让我茅塞顿开。

他是这样说的“斜面反弹吗?先把斜面旋转成平面,然后执行反弹,最后再把它旋转回去。” 哇!这正是我想要的。我们只需要旋转坐标系,让斜面像平面一样。

这就意味着旋转斜面,旋转物体坐标,再旋转物体速度向量。 现在考虑一下旋转速度向量的问题,我们把速度向量保存到 vx 和 vy 中,变量中简单地定义一个向量(角度与速度)。如果知道角度,可以直接进行旋转。但是如果只知道 vx 和 vy,就可以使用高级坐标旋转公式实现。 用图解释一下也许效果比文字要好些。



posted @ 2012-03-06 15:27  ndljava  阅读(204)  评论(0编辑  收藏  举报