Kinetic Energy formula:
Momentum formula:
Conservation of momentum:
Conservation of energy:
According to these rules, the following equations can be obtained:
Solve the equations and obtain the following formula:
Subtract the two formulas to obtain:
That is:
We often use this formula to simplify operations.
Demonstration of basic momentum conservation:
First, add a quality "attribute" To The Ball class"
Package {import flash. display. sprite; // ball class public class ball extends sprite {public var radius: uint; // radius public var color: uint; // color public var VX: Number = 0; // X axis speed public var Vy: Number = 0; // y axis speed public var count: uint = 0; // The auxiliary counting variable public var isdragged = false; // whether the image is being dragged public var Vr: Number = 0; // rotating speed public var mass: Number = 1; // quality public function ball (r: Number = 50, c: uint = 0xff0000) {This. radius = r; this. color = C; Init ();} private function Init (): void {graphics. beginfill (color); graphics. drawcircle (0, 0, radius); graphics. endfill ();}}}
One-dimensional single-axis rigid body collision test:
Package {import flash. display. sprite; import flash. events. event; public class billiard1 extends sprite {private var ball0: ball; private var ball1: ball; private var bounce: Number =-0.6; Public Function billiard1 () {Init ();} private function Init (): void {ball0 = new ball (40); addchild (ball0); ball1 = new ball (20, 0x0000ff); addchild (ball1 ); restart ();} private function restart (): void {ball0.mass = 2; ball0.x = 50; ball0.y = stage. stageheight/2; ball0.vx = 5; ball1.mass = 1; ball1.x = 300; ball1.y = stage. stageheight/2; ball1.vx =-5; addeventlistener (event. enter_frame, enterframehandler);} private function enterframehandler (Event: Event): void {ball0.x + = ball0.vx; ball1.x + = ball1.vx; var Dist: Number = ball1.x-ball0.x; // if it hits if (math. ABS (DIST) <ball0.radius + ball1.radius) {var vdx: Number = ball0.vx-ball1.vx; var vx0final: Number = (ball0.mass-ball1.mass) * ball0.vx + 2 * ball1.mass * ball1.vx) // (ball0.mass + ball1.mass); var vx1final: Number = vx0final + vdx; ball0.vx = vx0final; ball1.vx = vx1final; // the following two sentences are not added, it is possible to see two balls hitting each other's sphere, which is not in line with the definition of the physics "Rigid Body" Model ball0.x + = ball0.vx; ball1.x + = ball1.vx ;} // stage boundary rebound if (ball0.x> = stage. stageWidth-ball0.radius | ball0.x <= ball0.radius) {ball0.x-= ball0.vx; ball0.vx * = bounce;} If (ball1.x> = stage. stageWidth-ball1.radius | ball1.x <= ball1.radius) {ball1.x-= ball1.vx; ball1.vx * = bounce;} trace (ball1.vx, ball0.vx); // if both balls stop if (math. ABS (ball1.vx) <= 0.05 & math. ABS (ball0.vx) <= 0.05) {removeeventlistener (event. enter_frame, enterframehandler); restart ();}}}}
Rigid Body collision on two-dimensional coordinates:
First, let's take a look at this figure. The red ball a is moving at the VA speed, and the blue ball B is moving at the VB speed. The line of the two balls is just parallel to the X axis (that is, horizontal center collision ), the collision process can be understood as the result of two-ball horizontal velocity component vax, vbx application traffic conservation and capability conservation (the speed in the Y axis direction is not affected !)
However, in many cases, the two-ball line is not always parallel to the coordinate axis, such as the following:
Idea: we still use coordinates to rotate. We first reverse the two balls to the horizontal position of the link, and then process them in the conventional way. After the task is finished, we will rotate them back.
VaR Balla: ball = new ball (80, math. random () * 0 xffffff); var ballb: ball = new ball (50, math. random () * 0 xffffff); var bounce: Number =-1; Balla. X = Balla. radius + 100; ballb. X = Balla. radius + 200; Balla. y = 120; ballb. y= 300; Balla. mass = 2; ballb. mass = 1; Balla. VX = 5 * (math. random () * 2-1); ballb. VX = 5 * (math. random () * 2-1); Balla. vy = 5 * (math. random () * 2-1); ballb. vy = 5 * (math. random () * 2-1); addchild (Balla); addchild (ballb); addeventlistener (event. enter_frame, enterframehandler); function enterframehandler (E: Event): void {Balla. X + = Balla. VX; Balla. Y + = Balla. vy; ballb. X + = ballb. VX; ballb. Y + = ballb. vy; // traffic volume conservation start var DX: Number = ballb. x-ballA.x; var DY: Number = ballb. y-ballA.y; var Dist: Number = math. SQRT (dx * dx + dy * Dy); If (Dist <(Balla. radius + ballb. radius) {var angle: Number = math. atan2 (dy, dx); var cos: Number = math. cos (angle); var sin: Number = math. sin (angle); // use the Balla center as the rotation center to reverse rotate var XA: Number = 0; // The Balla itself is the rotation center, therefore, the relative coordinates after self-rotation are 0var ya: Number = 0; var XB: Number = DX * Cos + dy * sin; var Yb: number = Dy * Cos-DX * sin; // first (reverse) rotate two balls relative (Balla) Speed var vxa = Balla. VX * Cos + Balla. vy * sin; var vya = Balla. vy * cos-ballA.vx * sin; var vxb = ballb. VX * Cos + ballb. vy * sin; var vyb = ballb. vy * cos-ballB.vx * sin; // the VX speed after rotation handles traffic conservation var vdx = vxa-vxb; var vxafinal = (Balla. mass-ballb. mass) * vxa + 2 * ballb. mass * vxb)/(Balla. mass + ballb. mass); var vxbfinal = vxafinal + vdx; // processing XA + = vxafinal; XB + = vxbfinal; // processing is complete, then rotate it back // first process the Coordinate Position var xafinal: Number = XA * Cos-ya * sin; var yafinal: Number = ya * Cos + XA * sin; var xbfinal: number = XB * Cos-Yb * sin; var ybfinal: Number = Yb * Cos + XB * sin; // process the final location change ballb. X = Balla. X + xbfinal; ballb. y = Balla. Y + ybfinal; Balla. X + = xafinal; Balla. Y + = yafinal; // reprocessing speed Balla. VX = vxafinal * Cos-vya * sin; Balla. vy = vya * Cos + vxafinal * sin; ballb. VX = vxbfinal * Cos-vyb * sin; ballb. vy = vyb * Cos + vxbfinal * sin;} // <--- checkbounds (Balla); checkbounds (ballb);} // stage bounds (B: ball) {If (B. x <B. radius) {B. X = B. radius; B. VX * = bounce;} else if (B. x> stage. stageWidth-b.radius) {B. X = stage. stageWidth-b.radius; B. VX * = bounce;} If (B. Y <B. radius) {B. y = B. radius; B. vy * = bounce;} else if (B. y> stage. stageHeight-b.radius) {B. y = stage. stageHeight-b.radius; B. vy * = bounce ;}}
Adhesion problem:
Running the above animation repeatedly may occasionally find that the two balls are stuck together and cannot be separated. There are many reasons for this. The following analyzes one of the possible causes.
Solution: Find out the overlapping parts, and move the two balls in reverse direction to separate the two balls.
First, let's test the code to verify whether it works.
VaR Balla: ball = new ball (80, 0xff0000); Balla. X = stage. stagewidth/2; Balla. y = stage. stageheight/2; addchild (Balla); var ballb: ball = new ball (60, 0x00ff00); ballb. X = stage. stagewidth/2-70; ballb. y = stage. stageheight/2; addchild (ballb); btn1.x = stage. stagewidth/2; btn1.y = stage. stageHeight-btn1.height; btn1.addeventlistener (mouseevent. mouse_down, mousedownhandler); function mousedownhandler (E: mouseevent): void {var overlap: Number = Balla. radius + ballb. radius-Math.abs (Balla. x-ballB.x); // calculate the overlapping part trace (overlap); // calculate the percentage of each ball in the overlapped part var aradio: Number = Balla. RADIUS/(Balla. radius + ballb. radius); var bradio: Number = ballb. RADIUS/(Balla. radius + ballb. radius); // separate the IF (Overlap> 0) {If (Balla. x> ballb. x) {Balla. X + = overlap * aradio; ballb. x-= overlap * bradio;} else {Balla. x-= overlap * aradio; ballb. X + = overlap * bradio ;}} Balla. addeventliste NER (mouseevent. mouse_down, startdraghandler); ballb. addeventlistener (mouseevent. mouse_down, startdraghandler); Balla. addeventlistener (mouseevent. mouse_over, mouseoverhandler); Balla. addeventlistener (mouseevent. mouse_out, mouseouthandler); ballb. addeventlistener (mouseevent. mouse_over, mouseoverhandler); ballb. addeventlistener (mouseevent. mouse_out, mouseouthandler); stage. addeventlistener (mouseevent. mouse_up, St Opdraghandler); var OBJ: ball; var rect: rectangle = new rectangle (0, stage. stageheight/2, stage. stagewidth, 0); function startdraghandler (E: mouseevent): void {mouse. cursor = mousecursor. hand; OBJ = E. currenttarget as ball; obj. startdrag ();} function stopdraghandler (E: mouseevent): void {If (OBJ! = NULL) {obj. stopdrag (true, rect); OBJ = NULL; mouse. cursor = mousecursor. auto ;}} function mouseoverhandler (E: mouseevent): void {mouse. cursor = mousecursor. hand;} function mouseouthandler (E: mouseevent): void {mouse. cursor = mousecursor. auto ;}
Drag the ball horizontally to intentionally overlap them, and click the "separate" button to test it. OK, it works!
Then we can solve the problem of adhesion in traffic conservation:
You only need
// XA + = vxafinal; XB + = vxbfinal;
Replace:
// Relative position processing (to prevent adhesion at the same time) // XA + = vxafinal; // XB + = vxbfinal; var sumradius = Balla. radius + ballb. radius; var overlap: Number = sumRadius-Math.abs (xA-xB); // calculate the overlapping portion // trace (overlap); // calculate the ratio of each ball's overlapping portion var aradio: number = Balla. RADIUS/sumradius; var bradio: Number = ballb. RADIUS/sumradius; // separate the judgment if (Overlap> 0) {If (xa> xb) {XA + = overlap * aradio; XB-= overlap * bradio ;} else {XA-= overlap * aradio; XB + = overlap * bradio ;}}
Finally, the old rule: Let's dance in a group, and place a bunch of balls together.
Package {import flash. display. sprite; import flash. events. event; import flash. geom. point; public class multibilliard extends sprite {private var bils: array; private var numbils: uint = 8; private var bounce: Number =-1.0; Public Function multibilliard () {Init ();} private function Init (): void {bils = new array (); For (var I: uint = 0; I <numbils; I ++) {var radius: Number = math. random () * 40 + 10; var ball: ball = new ball (radius, math. random () * 0 xffffff); ball. mass = radius; ball. X = I * 100; ball. y = I * 50; ball. VX = math. random () * 10-5; ball. vy = math. random () * 10-5; addchild (ball); bils. push (ball);} addeventlistener (event. enter_frame, onenterframe);} private function onenterframe (Event: Event): void {for (var I: uint = 0; I <numbils; I ++) {var ball: ball = bils [I]; ball. X + = ball. VX; ball. Y + = ball. vy; checkwils (ball) ;}for (I = 0; I <numbils-1; I ++) {var Balla: ball = bils [I]; for (VAR J: number = I + 1; j <numbils; j ++) {var ballb: ball = bils [J]; checkcollision (Balla, ballb );}}} // stage Boundary Detection Function checkwils (B: ball) {If (B. x <B. radius) {B. X = B. radius; B. VX * = bounce;} else if (B. x> stage. stageWidth-b.radius) {B. X = stage. stageWidth-b.radius; B. VX * = bounce;} If (B. Y <B. radius) {B. y = B. radius; B. vy * = bounce;} else if (B. y> stage. stageHeight-b.radius) {B. y = stage. stageHeight-b.radius; B. vy * = bounce;} private function rotate (X: Number, Y: Number, sin: Number, cos: Number, reverse: Boolean): point {var result: point = new point (); If (reverse) {result. X = x * Cos + y * sin; result. y = y * Cos-x * sin;} else {result. X = x * Cos-y * sin; result. y = y * Cos + x * sin;} return result;} private function checkcollision (ball0: ball, ball1: ball): void {var DX: Number = ball1.x-ball0.x; vaR DY: Number = ball1.y-ball0.y; var Dist: Number = math. SQRT (dx * dx + dy * Dy); If (Dist <ball0.radius + ball1.radius) {// calculated angle and Cosine var angle: Number = math. atan2 (dy, dx); var sin: Number = math. sin (angle); var cos: Number = math. cos (angle); // rotate the position of ball0 var pos0: Point = new point (); // rotate the speed of ball1 var pos1: Point = rotate (dx, Dy, sin, cos, true); // rotate the speed of ball0 var vel0: Point = rotate (ball0.vx, ball0.vy, sin, cos, true); // rotate the speed of ball1 var vel1: point = rotate (ball1.vx, ball1.vy, sin, cos, true); // the force of the collision var vxtotal: Number = vel0.x-vel1.x; vel0.x = (ball0.mass-ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x)/(ball0.mass + ball1.mass); vel1.x = vxtotal + vel0.x; // update location var absv: Number = math. ABS (vel0.x) + math. ABS (vel1.x); var overlap: Number = (ball0.radius + ball1.radius)-math. ABS (pos0.x-pos1.x); pos0.x + = vel0.x/absv * overlap; pos1.x + = vel1.x/absv * overlap; // rotate the position back to VaR pos0f: Object = rotate (pos0.x, pos0.y, sin, cos, false); var pos1f: Object = rotate (pos1.x, pos1.y, sin, cos, false ); // adjust the position to the actual position of the screen ball1.x = ball0.x + pos1f. x; ball1.y = ball0.y + pos1f. y; ball0.x = ball0.x + pos0f. x; ball0.y = ball0.y + pos0f. y; // rotate the speed back var vel0f: Object = rotate (vel0.x, vel0.y, sin, cos, false); var vel1f: Object = rotate (vel1.x, vel1.y, sin, cos, false); ball0.vx = vel0f. x; ball0.vy = vel0f. y; ball1.vx = vel1f. x; ball1.vy = vel1f. Y ;}}}}
Note: This code is optimized to extract some common parts and encapsulate them into functions. At the same time, a more algorithm is used to solve the adhesion problem.
Note: I understand the usage of these things in this article? Let me think about it. Maybe it will be useful when the company needs to develop a desktop billiards game.