?
坐标旋转是个啥概念呢?

如上图,(蓝色)小球 绕某一中心点旋转a角度后,到达(红色)小球的位置,则红色小球相对中心点的坐标为:
x1 = dx * cos(a) - dy * sin(a)
y1 =?dy * cos(a) + dx * sin(a)?
这个就是坐标旋转公式,如果要反向旋转,则公式要修正一下,有二种方法:
?
1.将a变成-a,即:
x1 = dx * cos(-a) - dy * sin(-a)
y1 =?dy * cos(-a) + dx * sin(-a)
?
2.将正向旋转公式中的相减号交换
x1 = dx * cos(a) + dy * sin(a); y1 = dy * cos(a) - dx * sin(a);
?
先来回顾一个经典的小球圆周运动:
show source
view source
print
?
01 |
var ball:Ball = new Ball( 10 );
|
03 |
var centerX: Number = stage.stageWidth/ 2 ;
|
04 |
var centerY: Number = stage.stageHeight/ 2 ;
|
05 |
var radius: Number = 50 ;
|
09 |
addEventListener(Event.ENTER_FRAME,EnterFrameHandler); |
11 |
ball.x = centerX + Math.cos(angle) * radius; |
12 |
ball.y = centerY + Math.sin(angle) * radius; |
13 |
graphics.lineStyle( 1 , 0x999999 );
|
14 |
graphics.moveTo(ball.x,ball.y); |
16 |
function EnterFrameHandler(e:Event): void {???
|
17 |
???? ball.x = centerX + Math.cos(angle) * radius;
|
18 |
???? ball.y = centerY + Math.sin(angle) * radius;
|
20 |
???? if (angle<= 2 *Math.PI+ 0.02 ){
|
21 |
???????? graphics.lineTo(ball.x,ball.y);
|
这个没啥特别的,接下来我们用坐标旋转公式换一种做法验证一下是否有效:
show source
view source
print
?
01 |
var ball:Ball = new Ball( 10 );
|
03 |
var centerX: Number = stage.stageWidth/ 2 ;
|
04 |
var centerY: Number = stage.stageHeight/ 2 ;
|
05 |
var radius: Number = 50 ;
|
09 |
ball.x = centerX + radius; |
12 |
var cos: Number = Math.cos(ball.vr);
|
13 |
var sin: Number = Math.sin(ball.vr);
|
16 |
addEventListener(Event.ENTER_FRAME,EnterFrameHandler); |
18 |
graphics.lineStyle( 1 , 0x999999 );
|
19 |
graphics.moveTo(ball.x,ball.y); |
23 |
function EnterFrameHandler(e:Event): void {???
|
24 |
???? var dx: Number = ball.x - centerX;?
|
25 |
???? var dy: Number = ball.y - centerY;?
|
26 |
???? var x2: Number = cos * dx - sin * dy;?
|
27 |
???? var y2: Number = cos * dy + sin * dx;?
|
28 |
???? ball.x = centerX + x2;?
|
29 |
???? ball.y = centerY + y2;
|
31 |
???? if (i<=( 2 *Math.PI+ball.vr)/ball.vr){
|
33 |
???????? graphics.lineTo(ball.x,ball.y);
|
效果完全相同,说明坐标旋转公式完全是有效的,问题来了:原本一个简单的问题,经过这样复杂的处理后,效果并没有变化,为何要化简为繁呢?
好处1:提高运行效率
下面演示的多个物体旋转的传统做法:
show source
view source
print
?
01 |
var arrBalls: Array = new Array ( 30 );
|
02 |
var centerX: Number = stage.stageWidth/ 2 ;
|
03 |
var centerY: Number = stage.stageHeight/ 2 ;
|
05 |
for ( var i: uint = 0 ,j: uint =arrBalls.length;i<j;i++){
|
06 |
???? arrBalls[i] = new Ball( 3 + Math.random()* 5 ,Math.random()* 0xffffff );
|
07 |
???? arrBalls[i].x = centerX + 100 * (Math.random()* 2 - 1 );
|
08 |
???? arrBalls[i].y = centerY + 100 * (Math.random()* 2 - 1 );
|
09 |
???? addChild(arrBalls[i]);
|
12 |
graphics.lineStyle( 1 );
|
13 |
graphics.moveTo(centerX,centerY- 5 );
|
14 |
graphics.lineTo(centerX,centerY+ 5 );
|
15 |
graphics.moveTo(centerX- 5 ,centerY);
|
16 |
graphics.lineTo(centerX+ 5 ,centerY);
|
18 |
addEventListener(Event.ENTER_FRAME,EnterFrameHandler); |
20 |
function EnterFrameHandler(e:Event): void {
|
21 |
???? for ( var i: uint = 0 ,j: uint =arrBalls.length;i<j;i++){
|
22 |
???????? var ball:Ball = arrBalls[i];
|
23 |
???????? var dx: Number = ball.x - stage.stageWidth/ 2 ;
|
24 |
???????? var dy: Number = ball.y - stage.stageHeight/ 2 ;
|
25 |
???????? var dist: Number = Math.sqrt(dx*dx + dy*dy);
|
26 |
???????? ball.vr = Math.atan2(dy,dx);
|
27 |
???????? ball.vr += 0.005 ;
|
28 |
???????? ball.x = centerX + dist * Math.cos(ball.vr);
|
29 |
???????? ball.y = centerY + dist * Math.sin(ball.vr);
|
坐标旋转的新做法:
show source
view source
print
?
01 |
var arrBalls: Array = new Array ( 30 );
|
02 |
var centerX: Number = stage.stageWidth/ 2 ;
|
03 |
var centerY: Number = stage.stageHeight/ 2 ;
|
06 |
for ( var i: uint = 0 ,j: uint =arrBalls.length;i<j;i++){
|
07 |
???? arrBalls[i] = new Ball( 3 + Math.random()* 5 ,Math.random()* 0xffffff );
|
08 |
???? arrBalls[i].x = centerX + 100 * (Math.random()* 2 - 1 );
|
09 |
???? arrBalls[i].y = centerY + 100 * (Math.random()* 2 - 1 );
|
10 |
???? arrBalls[i].vr = vr;
|
11 |
???? addChild(arrBalls[i]);
|
14 |
graphics.lineStyle( 1 );
|
15 |
graphics.moveTo(centerX,centerY- 5 );
|
16 |
graphics.lineTo(centerX,centerY+ 5 );
|
17 |
graphics.moveTo(centerX- 5 ,centerY);
|
18 |
graphics.lineTo(centerX+ 5 ,centerY);
|
20 |
addEventListener(Event.ENTER_FRAME,EnterFrameHandler); |
23 |
var cos: Number = Math.cos(vr);
|
24 |
var sin: Number = Math.sin(vr);
|
26 |
function EnterFrameHandler(e:Event): void {
|
27 |
???? for ( var i: uint = 0 ,j: uint =arrBalls.length;i<j;i++){
|
28 |
???????? var ball:Ball = arrBalls[i];
|
29 |
???????? var dx: Number = ball.x - stage.stageWidth/ 2 ;
|
30 |
???????? var dy: Number = ball.y - stage.stageHeight/ 2 ;
|
31 |
???????? var x2: Number = cos * dx - sin * dy;?
|
32 |
???????? var y2: Number = cos * dy + sin * dx;
|
33 |
???????? ball.x = centerX + x2;
|
34 |
???????? ball.y = centerY + y2;??????
|
对比代码可以发现,同样的效果用坐标旋转处理后,Math的调用全部提升到循环外部了,对于30个小球来讲,每一帧至少减少了30 * 4 = 120次的三角函数运算
?
好处2:可以方便的处理斜面反弹
先来看下正向/反向旋转的测试
show source
view source
print
?
01 |
var ball:Ball= new Ball( 15 );
|
04 |
var centerX: Number =stage.stageWidth/ 2 ;
|
05 |
var centerY: Number =stage.stageHeight/ 2 ;
|
06 |
var radius: Number = 100 ;
|
08 |
ball.x=centerX+radius; |
13 |
graphics.lineStyle( 1 , 0xdddddd );
|
14 |
graphics.moveTo(centerX,centerY); |
15 |
graphics.lineTo(ball.x,ball.y); |
16 |
graphics.lineStyle( 1 );
|
17 |
graphics.moveTo(centerX,centerY - 10 );
|
18 |
graphics.lineTo(centerX,centerY + 10 );
|
19 |
graphics.moveTo(centerX- 10 ,centerY);
|
20 |
graphics.lineTo(centerX+ 10 ,centerY);
|
22 |
var angle: Number = 30 *Math.PI/ 180 ;
|
25 |
btn1.addEventListener(MouseEvent.MOUSE_DOWN,btn1Click); |
28 |
function btn1Click(e:MouseEvent): void {
|
29 |
???? var cos: Number =Math.cos(angle);
|
30 |
???? var sin: Number =Math.sin(angle);
|
31 |
???? var dx: Number =ball.x-centerX;
|
32 |
???? var dy: Number =ball.y-centerY;
|
33 |
???? var x1: Number =dx*cos-dy*sin;
|
34 |
???? var y1: Number =dy*cos+dx*sin;
|
35 |
???? ball.x=centerX+x1;
|
36 |
???? ball.y=centerY+y1;
|
37 |
???? graphics.lineStyle( 1 , 0xdddddd );
|
38 |
???? graphics.moveTo(centerX,centerY);
|
39 |
???? graphics.lineTo(ball.x,ball.y);
|
42 |
btn2.addEventListener(MouseEvent.MOUSE_DOWN,btn2Click); |
45 |
function btn2Click(e:MouseEvent): void {
|
46 |
???? var dx: Number =ball.x-centerX;
|
47 |
???? var dy: Number =ball.y-centerY;
|
48 |
???? var cos: Number =Math.cos(-angle);
|
49 |
???? var sin: Number =Math.sin(-angle);
|
50 |
???? var x1: Number =dx*cos-dy*sin;
|
51 |
???? var y1: Number =dy*cos+dx*sin;
|
52 |
???? ball.x=centerX+x1;
|
53 |
???? ball.y=centerY+y1;
|
54 |
???? graphics.lineStyle( 1 , 0xdddddd );
|
55 |
???? graphics.moveTo(centerX,centerY);
|
56 |
???? graphics.lineTo(ball.x,ball.y);
|
59 |
btn3.addEventListener(MouseEvent.MOUSE_DOWN,btn3Click); |
62 |
function btn3Click(e:MouseEvent): void {
|
63 |
???? var dx: Number =ball.x-centerX;
|
64 |
???? var dy: Number =ball.y-centerY;
|
65 |
???? var cos: Number =Math.cos(angle);
|
66 |
???? var sin: Number =Math.sin(angle);
|
68 |
???? var x1: Number =dx*cos+dy*sin;
|
69 |
???? var y1: Number =dy*cos-dx*sin;
|
70 |
???? ball.x=centerX+x1;
|
71 |
???? ball.y=centerY+y1;
|
72 |
???? graphics.lineStyle( 1 , 0xdddddd );
|
73 |
???? graphics.moveTo(centerX,centerY);
|
74 |
???? graphics.lineTo(ball.x,ball.y);
|
对于水平或垂直的反弹运动,实现起来并不复杂,但对于斜面而言,情况就复杂多了,首先:物体反弹并不是光学中的反射,所以用“入射角=反射角”来模拟并不准确,其次我们还要考虑到重力因素/摩擦力因素,这些都会影响到速度的大小和方向。
如果用坐标旋转的思维方式去考虑这一复杂的问题,解决办法就变得非常简单。
所有向量(物理学中也常称矢量,虽然这二者在严格意义上讲并不相同)都可应用坐标旋转,我们可以把整个系统(包括斜面以及相对斜面运行物体的速度向量)都通过坐标旋转变成水平面或垂直面,这样就把问题简单化了,等一切按水平或垂直的简单方式处理完成以后,再把系统旋转回最初的样子。

show source
view source
print
?
003 |
???? import flash.display.Sprite;
|
004 |
???? import flash.events.Event;
|
005 |
???? import flash.events.MouseEvent;
|
006 |
???? import flash.ui.Mouse;
|
007 |
???? import flash.ui.MouseCursor;
|
008 |
???? import flash.geom.Rectangle;
|
011 |
???? public class AngleBounce extends Sprite { |
013 |
???????? private var ball:Ball;
|
014 |
???????? private var line:Sprite; |
015 |
???????? private var gravity: Number = 0.25 ;
|
016 |
???????? private var bounce: Number =- 0.6 ;
|
017 |
???????? private var rect:Rectangle; |
019 |
???????? public function AngleBounce() { |
023 |
???????? private function init(): void {
|
024 |
???????????? Mouse.cursor=MouseCursor.BUTTON;
|
025 |
???????????? ball= new Ball( 10 );
|
026 |
???????????? addChild(ball);
|
027 |
???????????? ball.x= 100 ;
|
028 |
???????????? ball.y= 100 ;
|
029 |
???????????? line= new Sprite? ;
|
030 |
???????????? line.graphics.lineStyle( 1 );
|
031 |
???????????? line.graphics.lineTo( 300 , 0 );
|
032 |
???????????? addChild(line);
|
033 |
???????????? line.x= 50 ;
|
034 |
???????????? line.y= 200 ;
|
035 |
???????????? line.rotation= 25 ;
|
036 |
???????????? stage.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
|
038 |
???????????? rect = line.getBounds( this );
|
040 |
???????????? graphics.beginFill( 0xefefef )
|
041 |
???????????? graphics.drawRect(rect.left,rect.top,rect.width,rect.height);
|
042 |
???????????? graphics.endFill();
|
045 |
???????? private function MouseDownHandler(e:Event) {
|
046 |
???????????? addEventListener(Event.ENTER_FRAME,EnterFrameHandler);
|
049 |
???????? private function EnterFrameHandler(e:Event): void {
|
054 |
???????????? ball.vy+=gravity;
|
055 |
???????????? ball.x+=ball.vx;
|
056 |
???????????? ball.y+=ball.vy;
|
063 |
???????????? if (ball.x > rect.left && ball.x < rect.right && ball.y >rect.top && ball.y < rect.bottom){
|
068 |
???????????????? var angle: Number =line.rotation*Math.PI/ 180 ;
|
069 |
???????????????? var cos: Number =Math.cos(angle);
|
070 |
???????????????? var sin: Number =Math.sin(angle);
|
073 |
???????????????? var dx: Number =ball.x-line.x;
|
074 |
???????????????? var dy: Number =ball.y-line.y;
|
077 |
???????????????? var x2: Number =cos*dx+sin*dy;
|
078 |
???????????????? var y2: Number =cos*dy-sin*dx;
|
081 |
???????????????? var vx2: Number =cos*ball.vx+sin*ball.vy;
|
082 |
???????????????? var vy2: Number =cos*ball.vy-sin*ball.vx;
|
085 |
???????????????? if (y2>- ball.height/ 2 ) {
|
086 |
???????????????????? y2=- ball.height/ 2 ;
|
087 |
???????????????????? vy2*=bounce;
|
089 |
???????????????????? dx=cos*x2-sin*y2;
|
090 |
???????????????????? dy=cos*y2+sin*x2;
|
092 |
???????????????????? ball.vx=cos*vx2-sin*vy2;
|
093 |
???????????????????? ball.vy=cos*vy2+sin*vx2;
|
096 |
???????????????????? ball.x=line.x+dx;
|
097 |
???????????????????? ball.y=line.y+dy;
|
102 |
???????????? if (ball.x>=stage.stageWidth-ball.width/ 2 ||ball.y>=stage.stageHeight-ball.height/ 2 ) {
|
103 |
???????????????? ball.x= 100 ;
|
104 |
???????????????? ball.y= 100 ;
|
105 |
???????????????? ball.vx= 0 ;
|
106 |
???????????????? ball.vy= 0 ;
|
107 |
???????????????? removeEventListener(Event.ENTER_FRAME,EnterFrameHandler);
|
?多角度斜面反弹:
show source
view source
print
?
002 |
???? import flash.display.Sprite;
|
003 |
???? import flash.events.Event;
|
004 |
???? import flash.display.StageScaleMode;
|
005 |
???? import flash.display.StageAlign;
|
006 |
???? import flash.geom.Rectangle;
|
007 |
???? import flash.events.MouseEvent;
|
008 |
???? import flash.ui.Mouse;
|
009 |
???? import flash.ui.MouseCursor;
|
011 |
???? public class MultiAngleBounce extends Sprite { |
012 |
???????? private var ball:Ball;
|
013 |
???????? private var lines: Array ;
|
014 |
???????? private var numLines: uint = 5 ;
|
015 |
???????? private var gravity: Number = 0.3 ;
|
016 |
???????? private var bounce: Number =- 0.6 ;
|
018 |
???????? public function MultiAngleBounce() {
|
022 |
???????? private function init(): void {
|
023 |
???????????? stage.scaleMode=StageScaleMode.NO_SCALE;
|
024 |
???????????? stage.align=StageAlign.TOP_LEFT;
|
025 |
???????????? ball= new Ball( 20 );
|
026 |
???????????? addChild(ball);
|
027 |
???????????? ball.x= 100 ;
|
028 |
???????????? ball.y= 50 ;
|
030 |
???????????? lines = new Array ();
|
031 |
???????????? for ( var i: uint = 0 ; i < numLines; i++) {
|
032 |
???????????????? var line:Sprite = new Sprite();
|
033 |
???????????????? line.graphics.lineStyle( 1 );
|
034 |
???????????????? line.graphics.moveTo(- 50 , 0 );
|
035 |
???????????????? line.graphics.lineTo( 50 , 0 );
|
036 |
???????????????? addChild(line);
|
037 |
???????????????? lines.push(line);
|
041 |
???????????? lines[ 0 ].x= 100 ;
|
042 |
???????????? lines[ 0 ].y= 100 ;
|
043 |
???????????? lines[ 0 ].rotation= 30 ;
|
044 |
???????????? lines[ 1 ].x= 100 ;
|
045 |
???????????? lines[ 1 ].y= 230 ;
|
046 |
???????????? lines[ 1 ].rotation= 45 ;
|
047 |
???????????? lines[ 2 ].x= 250 ;
|
048 |
???????????? lines[ 2 ].y= 180 ;
|
049 |
???????????? lines[ 2 ].rotation=- 30 ;
|
050 |
???????????? lines[ 3 ].x= 150 ;
|
051 |
???????????? lines[ 3 ].y= 330 ;
|
052 |
???????????? lines[ 3 ].rotation= 10 ;
|
053 |
???????????? lines[ 4 ].x= 230 ;
|
054 |
???????????? lines[ 4 ].y= 250 ;
|
055 |
???????????? lines[ 4 ].rotation=- 30 ;
|
056 |
???????????? addEventListener(Event.ENTER_FRAME,onEnterFrame);
|
058 |
???????????? ball.addEventListener(MouseEvent.MOUSE_DOWN,MouseDownHandler);
|
059 |
???????????? ball.addEventListener(MouseEvent.MOUSE_OVER,MouSEOverHandler);
|
060 |
???????????? stage.addEventListener(MouseEvent.MOUSE_UP,MouseUpHandler);
|
064 |
???????? function MouSEOverHandler(e:MouseEvent): void {
|
065 |
???????????? Mouse.cursor=MouseCursor.HAND;
|
068 |
???????? function MouseDownHandler(e:MouseEvent): void {
|
069 |
???????????? Mouse.cursor=MouseCursor.HAND;
|
070 |
???????????? var bounds:Rectangle = new Rectangle(ball.width,ball.height,stage.stageWidth- 2 *ball.width,stage.stageHeight- 2 *ball.height);
|
071 |
???????????? ball.startDrag( true ,bounds);
|
072 |
???????????? removeEventListener(Event.ENTER_FRAME,onEnterFrame);
|
075 |
???????? function MouseUpHandler(e:MouseEvent): void {
|
076 |
???????????? ball.stopDrag();
|
077 |
???????????? ball.vx= 0 ;
|
078 |
???????????? ball.vy= 0 ;
|
079 |
???????????? Mouse.cursor=MouseCursor.AUTO;
|
080 |
???????????? addEventListener(Event.ENTER_FRAME,onEnterFrame);
|
083 |
???????? private function onEnterFrame(event:Event): void {
|
085 |
???????????? ball.vy+=gravity;
|
086 |
???????????? ball.x+=ball.vx;
|
087 |
???????????? ball.y+=ball.vy;
|
089 |
???????????? if (ball.x+ball.radius>stage.stageWidth) {
|
090 |
???????????????? ball.x=stage.stageWidth-ball.radius;
|
091 |
???????????????? ball.vx*=bounce;
|
092 |
???????????? } else if (ball.x - ball.radius < 0 ) {
|
093 |
???????????????? ball.x=ball.radius;
|
094 |
???????????????? ball.vx*=bounce;
|
096 |
???????????? if (ball.y+ball.radius>stage.stageHeight) {
|
097 |
???????????????? ball.y=stage.stageHeight-ball.radius;
|
098 |
???????????????? ball.vy*=bounce;
|
099 |
???????????? } else if (ball.y - ball.radius < 0 ) {
|
100 |
???????????????? ball.y=ball.radius;
|
101 |
???????????????? ball.vy*=bounce;
|
104 |
???????????? for ( var i: uint = 0 ; i < numLines; i++) {
|
105 |
???????????????? checkLine(lines[i]);
|
108 |
???????? private function checkLine(line:Sprite): void {
|
110 |
???????????? var bounds:Rectangle=line.getBounds( this );
|
111 |
???????????? if (ball.x>bounds.left&&ball.x<bounds.right) {
|
113 |
???????????????? var angle: Number =line.rotation*Math.PI/ 180 ;
|
114 |
???????????????? var cos: Number =Math.cos(angle);
|
115 |
???????????????? var sin: Number =Math.sin(angle);
|
117 |
???????????????? var x1: Number =ball.x-line.x;
|
118 |
???????????????? var y1: Number =ball.y-line.y;
|
120 |
???????????????? var y2: Number =cos*y1-sin*x1;
|
122 |
???????????????? var vy1: Number =cos*ball.vy-sin*ball.vx;
|
124 |
???????????????? if (y2>- ball.height/ 2 &&y2<vy1) {
|
126 |
???????????????????? var x2: Number =cos*x1+sin*y1;
|
128 |
???????????????????? var vx1: Number =cos*ball.vx+sin*ball.vy;
|
129 |
???????????????????? y2=- ball.height/ 2 ;
|
130 |
???????????????????? vy1*=bounce;
|
132 |
???????????????????? x1=cos*x2-sin*y2;
|
134 |
???????????????????? y1=cos*y2+sin*x2;
|
135 |
???????????????????? ball.vx=cos*vx1-sin*vy1;
|
136 |
???????????????????? ball.vy=cos*vy1+sin*vx1;
|
137 |
???????????????????? ball.x=line.x+x1;
|
138 |
???????????????????? ball.y=line.y+y1;
|
作者:
菩提树下的杨过
出处:
http://yjmyzz.cnblogs.com
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|