What is coordinate rotation?
For example, after the (blue) Ball rotates a angle around a center point and reaches the position of the (red) Ball, the coordinates of the relative center of the red ball are:
X1 = DX * Cos (a)-dy * sin ()
Y1 = Dy * Cos (A) + dx * sin ()
This is the coordinate rotation formula. If you want to reverse rotation, you need to modify the formula. There are two methods:
1. convert a to-a, that is:
X1 = DX * Cos (-a)-dy * sin (-)
Y1 = Dy * Cos (-A) + dx * sin (-)
2. Swap the subtraction signs in the forward rotation formula
X1 = DX * Cos (A) + dy * sin ();
Y1 = Dy * Cos (a)-DX * sin ();
Let's first review a classic circular motion of a ball:
VaR ball: ball = new ball (10); var centerx: Number = stage. stagewidth/2; var centery: Number = stage. stageheight/2; var radius: Number = 50; var angle: Number = 0; addchild (ball); addeventlistener (event. enter_frame, enterframehandler); ball. X = centerx + math. cos (angle) * radius; ball. y = centery + math. sin (angle) * radius; graphics. linestyle (999999 X); graphics. moveTo (ball. x, ball. y); function enterframehandler (E: Event): void {ball. X = centerx + math. cos (angle) * radius; ball. y = centery + math. sin (angle) * radius; angle ++ = 0.02; If (angle <= 2 * Math. PI + 0.02) {graphics. lineto (ball. x, ball. Y );}}
This is nothing special. Next we will use the coordinate rotation formula for another method to verify whether it is effective:
var ball: ball = new ball (10); var centerx: Number = stage. stagewidth/2; var centery: Number = stage. stageheight/2; var radius: Number = 50; var angle: Number = 0; ball. vr = 0.02; // rotating angular velocity ball. X = centerx + radius; ball. y = centery; var cos: Number = math. cos (ball. vr); var sin: Number = math. sin (ball. vr); addchild (ball); addeventlistener (event. enter_frame, enterframehandler); graphics. linestyle (999999 X); graphics. moveTo (ball. x, ball. y); var I: Number = 0; function enterframehandler (E: Event): void {var DX: Number = ball. x-centerx; var DY: Number = ball. y-centery; var X2: Number = cos * DX-sin * dy; var Y2: Number = cos * dy + sin * DX; ball. X = centerx + x2; ball. y = centery + y2; I ++; if (I <= (2 * Math. PI + ball. vr)/ball. vr) {trace (I); graphics. lineto (ball. x, ball. y) ;}}
The results are exactly the same, indicating that the coordinate rotation formula is completely effective. The problem is: the original simple problem. After such complicated processing, the effect has not changed, why should we simplify it to a traditional one?
Benefit 1:Improve Operation Efficiency
The following describes the traditional practice of rotating multiple objects:
VaR arrbballs: array = new array (30); var centerx: Number = stage. stagewidth/2; var centery: Number = stage. stageheight/2; for (var I: uint = 0, J: uint = arrbils. length; I <j; I ++) {arrbballs [I] = new ball (3 + math. random () * 5, math. random () * 0 xffffff); arrbils [I]. X = centerx + 100 * (math. random () * 2-1); arrbils [I]. y = centery + 100 * (math. random () * 2-1); addchild (arrbils [I]);} graphics. linestyle (1); graphics. moveTo (centerx, centerY-5); graphics. lineto (centerx, centery + 5); graphics. moveTo (centerX-5, centery); graphics. lineto (centerx + 5, centery); addeventlistener (event. enter_frame, enterframehandler); function enterframehandler (E: Event): void {for (var I: uint = 0, J: uint = arrbballs. length; I <j; I ++) {var ball: ball = arrbils [I]; var DX: Number = ball. x-stage. stagewidth/2; var DY: Number = ball. y-stage. stageheight/2; var Dist: Number = math. SQRT (dx * dx + dy * Dy); // one math call ball. vr = math. atan2 (dy, dx); // two math calls ball. VR + = 0.005; ball. X = centerx + dist * Math. cos (ball. vr); // call ball three times for math. y = centery + dist * Math. sin (ball. vr); // 4 math calls }}
New Method of coordinate rotation:
VaR arrbballs: array = new array (30); var centerx: Number = stage. stagewidth/2; var centery: Number = stage. stageheight/2; var Vr: Number = 0.01; For (var I: uint = 0, J: uint = arrbils. length; I <j; I ++) {arrbballs [I] = new ball (3 + math. random () * 5, math. random () * 0 xffffff); arrbils [I]. X = centerx + 100 * (math. random () * 2-1); arrbils [I]. y = centery + 100 * (math. random () * 2-1); arrbils [I]. vr = VR; addchild (arrbils [I]);} graphics. linestyle (1); graphics. moveTo (centerx, centerY-5); graphics. lineto (centerx, centery + 5); graphics. moveTo (centerX-5, centery); graphics. lineto (centerx + 5, centery); addeventlistener (event. enter_frame, enterframehandler); // place the call of the math function to the VaR cos: Number = math. cos (VR); var sin: Number = math. sin (VR); function enterframehandler (E: Event): void {for (var I: uint = 0, J: uint = arrbils. length; I <j; I ++) {var ball: ball = arrbils [I]; var DX: Number = ball. x-stage. stagewidth/2; var DY: Number = ball. y-stage. stageheight/2; var X2: Number = cos * DX-sin * dy; var Y2: Number = cos * dy + sin * DX; ball. X = centerx + x2; ball. y = centery + y2 ;}}
ComparisonCodeIt can be found that after the same effect is processed by coordinate rotation, all the calls of math are upgraded to the External Loop. For 30 small balls, each frame is reduced by at least 30x4 = 120 trigonometric operations.
Benefit 2:This allows you to easily handle slope rebound.
First, let's look at the test of forward/Reverse Rotation.
VaR ball: ball = new ball (15); addchild (ball); var centerx: Number = stage. stagewidth/2; var centery: Number = stage. stageheight/2; var radius: Number = 100; ball. X = centerx + radius; ball. y = centery; graphics. linestyle (1, 0 xdddddd); graphics. moveTo (centerx, centery); graphics. lineto (ball. x, ball. y); graphics. linestyle (1); graphics. moveTo (centerx, centery-10); graphics. lineto (centerx, centery + 10); graphics. moveTo (centerX-10, centery); graphics. lineto (centerx + 10, centery); var angle: Number = 30 * Math. PI/180; btn1.addeventlistener (mouseevent. mouse_down, btn1click); // rotate function btn1click (E: mouseevent): void {var cos: Number = math. cos (angle); var sin: Number = math. sin (angle); var DX: Number = ball. x-centerx; var DY: Number = ball. y-centery; var X1: Number = DX * Cos-dy * sin; var Y1: Number = Dy * Cos + dx * sin; ball. X = centerx + x1; ball. y = centery + Y1; graphics. linestyle (1, 0 xdddddd); graphics. moveTo (centerx, centery); graphics. lineto (ball. x, ball. y);} btn2.addeventlistener (mouseevent. mouse_down, btn2click); // reverse 1 function btn2click (E: mouseevent): void {var DX: Number = ball. x-centerx; var DY: Number = ball. y-centery; var cos: Number = math. cos (-angle); var sin: Number = math. sin (-angle); var X1: Number = DX * Cos-dy * sin; var Y1: Number = Dy * Cos + dx * sin; ball. X = centerx + x1; ball. y = centery + Y1; graphics. linestyle (1, 0 xdddddd); graphics. moveTo (centerx, centery); graphics. lineto (ball. x, ball. y);} btn3.addeventlistener (mouseevent. mouse_down, btn3click); // reverse 2 function btn3click (E: mouseevent): void {var DX: Number = ball. x-centerx; var DY: Number = ball. y-centery; var cos: Number = math. cos (angle); var sin: Number = math. sin (angle); // inverse formula var X1: Number = DX * Cos + dy * sin; var Y1: Number = Dy * Cos-DX * sin; ball. X = centerx + x1; ball. y = centery + Y1; graphics. linestyle (1, 0 xdddddd); graphics. moveTo (centerx, centery); graphics. lineto (ball. x, ball. Y );}
It is not complicated to realize horizontal or vertical rebound, but the situation is much more complicated for the inclined surface. First, the bounce of an object is not a reflection in optics, therefore, it is not accurate to use "incident angle = reflection angle". Secondly, we need to consider the gravity/friction factors, which will affect the speed and direction.
If you think about this complex problem with coordinate rotation, the solution becomes very simple.
All vectors (also known as vectors in physics, although they are not exactly the same) can apply coordinate rotation, we can convert the whole system (including the inclined plane and the velocity vector of the object running relative inclined planes) to a horizontal plane or a vertical plane through coordinate rotation, which simplifies the problem, after all the operations are done in a simple horizontal or vertical way, the system is rotated back to its original state.
Package {import flash. display. sprite; import flash. events. event; import flash. events. mouseevent; import flash. UI. mouse; import flash. UI. mousecursor; import flash. geom. rectangle; public class anglebounce extends sprite {private var ball: ball; private var line: SPRITE; private var gravity: Number = 0.25; private var bounce: Number =-0.6; private var rect: rectangle; Public Function anglebounce () {Init ();} private function Init (): void {mouse. cursor = mousecursor. button; ball = new ball (10); addchild (ball); ball. X = 100; ball. y = 100; line = new sprite; line. graphics. linestyle (1); line. graphics. lineto (); addchild (line); line. X = 50; line. y = 200; line. rotation = 25; // rotate line to form an inclined stage. addeventlistener (mouseevent. mouse_down, mousedownhandler); rect = line. getbounds (this); // obtain the line rectangular boundary graphics. beginfill (0 xefefef) graphics. drawrect (rect. left, rect. top, rect. width, rect. height); graphics. endfill ();} private function mousedownhandler (E: Event) {addeventlistener (event. enter_frame, enterframehandler);} private function enterframehandler (E: Event): void {// line. rotation = (stage. stagewidth/2-mousex) * 0.1; // common motion code ball. vy + = gravity; ball. X + = ball. VX; ball. Y + = ball. vy;/* // only when the two (rectangular boundary) collide, if (ball. hittestobject (line) {* // You can also use the following method to detect if (ball. x> rect. left & ball. x <rect. right & ball. y> rect. top & ball. Y <rect. bottom) {// trace ("true"); // obtain the angle and cosine value var angle: Number = line. rotation * Math. PI/180; var cos: Number = math. cos (angle); var sin: Number = math. sin (angle); // obtain the relative position of ball and line var DX: Number = ball. x-line.x; var DY: Number = ball. y-line.y; // Reverse Rotation coordinates (get the coordinates of the ball "relative" slope line) var X2: Number = cos * dx + sin * dy; var Y2: number = cos * dy-sin * DX; // returns the reverse rotation speed vector (to get the ball's "relative" slope speed) var VXR: Number = cos * ball. VX + sin * ball. vy; var vy2: Number = cos * ball. vy-sin * ball. VX; // returns if (Y2>-ball. height/2) {y2 =-ball. height/2; vy2 * = bounce; // rotate everything forward back dx = cos * x2-sin * Y2; DY = cos * y2 + sin * X2; ball. VX = cos * vx2-sin * vy2; ball. vy = cos * vy2 + sin * VX2. // locate the ball. X = line. X + dx; ball. y = line. Y + dy ;}// run the stage boundary and place it in the original position if (ball. x> = stage. stageWidth-ball.width/2 | ball. y> = stage. stageHeight-ball.height/2) {ball. X = 100; ball. y = 100; ball. VX = 0; ball. vy = 0; removeeventlistener (event. enter_frame, enterframehandler );}}}}
Multi-angle slope rebound:
Package {import flash. display. sprite; import flash. events. event; import flash. display. stagescalemode; import flash. display. stagealign; import flash. geom. rectangle; import flash. events. mouseevent; import flash. UI. mouse; import flash. UI. mousecursor; public class multianglebounce extends sprite {private var ball: ball; private var lines: array; private var numlines: uint = 5; private var gravity: Number = 0.3; private var bounce: number =-0.6; Public Function multianglebounce () {Init ();} private function Init (): void {stage. scalemode = stagescalemode. no_scale; stage. align = stagealign. top_left; ball = new ball (20); addchild (ball); ball. X = 100; ball. y = 50; // create five line films lines = new array (); For (var I: uint = 0; I <numlines; I ++) {var line: sprite = new sprite (); line. graphics. linestyle (1); line. graphics. moveTo (-50, 0); line. graphics. lineto (50, 0); addchild (line); lines. push (line);} // place and rotate lines [0]. X = 100; lines [0]. y = 100; lines [0]. rotation = 30; lines [1]. X = 100; lines [1]. y = 230; lines [1]. rotation = 45; lines [2]. X = 250; lines [2]. y = 180; lines [2]. rotation =-30; lines [3]. X = 150; lines [3]. y = 330; lines [3]. rotation = 10; lines [4]. X = 230; lines [4]. y = 250; lines [4]. rotation =-30; addeventlistener (event. enter_frame, onenterframe); ball. addeventlistener (mouseevent. mouse_down, mousedownhandler); ball. addeventlistener (mouseevent. mouse_over, mouseoverhandler); stage. addeventlistener (mouseevent. mouse_up, mouseuphandler);} function mouseoverhandler (E: mouseevent): void {mouse. cursor = mousecursor. hand;} function mousedownhandler (E: mouseevent): void {mouse. cursor = mousecursor. hand; var bounds: rectangle = new rectangle (ball. width, ball. height, stage. stageWidth-2 * ball. width, stage. stageHeight-2 * ball. height); ball. startdrag (true, bounds); removeeventlistener (event. enter_frame, onenterframe);} function mouseuphandler (E: mouseevent): void {ball. stopdrag (); ball. VX = 0; ball. vy = 0; mouse. cursor = mousecursor. auto; addeventlistener (event. enter_frame, onenterframe);} private function onenterframe (Event: Event): void {// normal motion code ball. vy + = gravity; ball. X + = ball. VX; ball. Y + = ball. vy; // If (ball. X + ball. radius> stage. stagewidth) {ball. X = stage. stageWidth-ball.radius; ball. VX * = bounce;} else if (ball. x-ball. radius <0) {ball. X = ball. radius; ball. VX * = bounce;} If (ball. Y + ball. radius> stage. stageheight) {ball. y = stage. stageHeight-ball.radius; ball. vy * = bounce;} else if (ball. y-ball. radius <0) {ball. y = ball. radius; ball. vy * = bounce;} // check each line for (var I: uint = 0; I <numlines; I ++) {checkline (lines [I]);} private function checkline (line: SPRITE): void {// obtain the line boundary var bounds: rectangle = line. getbounds (this); If (ball. x> bounds. left & ball. x <bounds. right) {// obtain the angle and Cosine var angle: Number = line. rotation * Math. PI/180; var cos: Number = math. cos (angle); var sin: Number = math. sin (angle); // obtain the relative position of ball and line var X1: Number = ball. x-line.x; var Y1: Number = ball. y-line.y; // rotating coordinate var Y2: Number = cos * y1-sin * x1; // rotating speed vector var vy1: Number = cos * ball. vy-sin * ball. VX; // returns if (Y2>-ball. height/2 & Y2 <vy1) {// rotate the coordinate var X2: Number = cos * X1 + sin * Y1; // rotate the velocity vector var vx1: number = cos * ball. VX + sin * ball. vy; y2 =-ball. height/2; vy1 * = bounce; // rotate everything back X1 = cos * x2-sin * Y2; Y1 = cos * y2 + sin * X2; ball. VX = cos * vx1-sin * vy1; ball. vy = cos * vy1 + sin * vx1; ball. X = line. X + x1; ball. y = line. Y + Y1 ;}}}}}