Calculate the speed and direction of the ball in collision with the ball based on mass and rebound coefficient

I used the following code based on this

ballA.vx = (u1x * (m1 - m2) + 2 * m2 * u2x) / (m1 + m2); ballA.vy = (u1y * (m1 - m2) + 2 * m2 * u2y) / (m1 + m2); ballB.vx = (u2x * (m2 - m1) + 2 * m1 * u1x) / (m1 + m2); ballB.vy = (u2y * (m2 - m1) + 2 * m1 * u1y) / (m1 + m2); 

but this is clearly not as good as the formula is for one-dimensional collisions.

So, I tried to use the formula below from this section .

But the problem is that I do not know what the deviation angle is and how to calculate it. Also, how to take into account the bounce rate in this formula?

Change Perhaps I was not clean. The above code works, although this may not be the expected behavior, since the original formula is for 1D collisions. Therefore, I try:

  • What is the 2D equivalent?
  • How to take into account the rebound coefficient ?
  • How to calculate direction (which is expressed using v x and v y ) two balls after a collision?
+6
source share
3 answers

I should start by saying: I created a new answer because I feel that the old has value for its simplicity

as promised, this is a much more complex physics engine, but I still feel that it is simple enough to follow (hopefully or just lost time ... lol), (url: http://jsbin.com/otipiv / edit # javascript, live )

 function Vector(x, y) { this.x = x; this.y = y; } Vector.prototype.dot = function (v) { return this.x * vx + this.y * vy; }; Vector.prototype.length = function() { return Math.sqrt(this.x * this.x + this.y * this.y); }; Vector.prototype.normalize = function() { var s = 1 / this.length(); this.x *= s; this.y *= s; return this; }; Vector.prototype.multiply = function(s) { return new Vector(this.x * s, this.y * s); }; Vector.prototype.tx = function(v) { this.x += vx; this.y += vy; return this; }; function BallObject(elasticity, vx, vy) { this.v = new Vector(vx || 0, vy || 0); // velocity: m/s^2 this.m = 10; // mass: kg this.r = 15; // radius of obj this.p = new Vector(0, 0); // position this.cr = elasticity; // elasticity } BallObject.prototype.draw = function(ctx) { ctx.beginPath(); ctx.arc(this.px, this.py, this.r, 0, 2 * Math.PI); ctx.closePath(); ctx.fill(); ctx.stroke(); }; BallObject.prototype.update = function(g, dt, ppm) { this.vy += g * dt; this.px += this.vx * dt * ppm; this.py += this.vy * dt * ppm; }; BallObject.prototype.collide = function(obj) { var dt, mT, v1, v2, cr, sm, dn = new Vector(this.px - obj.px, this.py - obj.py), sr = this.r + obj.r, // sum of radii dx = dn.length(); // pre-normalized magnitude if (dx > sr) { return; // no collision } // sum the masses, normalize the collision vector and get its tangential sm = this.m + obj.m; dn.normalize(); dt = new Vector(dn.y, -dn.x); // avoid double collisions by "un-deforming" balls (larger mass == less tx) // this is susceptible to rounding errors, "jiggle" behavior and anti-gravity // suspension of the object get into a strange state mT = dn.multiply(this.r + obj.r - dx); this.p.tx(mT.multiply(obj.m / sm)); obj.p.tx(mT.multiply(-this.m / sm)); // this interaction is strange, as the CR describes more than just // the ball bounce properties, it describes the level of conservation // observed in a collision and to be "true" needs to describe, rigidity, // elasticity, level of energy lost to deformation or adhesion, and crazy // values (such as cr > 1 or cr < 0) for stange edge cases obviously not // handled here (see: http://en.wikipedia.org/wiki/Coefficient_of_restitution) // for now assume the ball with the least amount of elasticity describes the // collision as a whole: cr = Math.min(this.cr, obj.cr); // cache the magnitude of the applicable component of the relevant velocity v1 = dn.multiply(this.v.dot(dn)).length(); v2 = dn.multiply(obj.v.dot(dn)).length(); // maintain the unapplicatble component of the relevant velocity // then apply the formula for inelastic collisions this.v = dt.multiply(this.v.dot(dt)); this.v.tx(dn.multiply((cr * obj.m * (v2 - v1) + this.m * v1 + obj.m * v2) / sm)); // do this once for each object, since we are assuming collide will be called // only once per "frame" and its also more effiecient for calculation cacheing // purposes obj.v = dt.multiply(obj.v.dot(dt)); obj.v.tx(dn.multiply((cr * this.m * (v1 - v2) + obj.m * v2 + this.m * v1) / sm)); }; function FloorObject(floor) { var py; this.v = new Vector(0, 0); this.m = 5.9722 * Math.pow(10, 24); this.r = 10000000; this.p = new Vector(0, py = this.r + floor); this.update = function() { this.vx = 0; this.vy = 0; this.px = 0; this.py = py; }; // custom to minimize unnecessary filling: this.draw = function(ctx) { var c = ctx.canvas, s = ctx.scale; ctx.fillRect(c.width / -2 / s, floor, ctx.canvas.width / s, (ctx.canvas.height / s) - floor); }; } FloorObject.prototype = new BallObject(1); function createCanvasWithControls(objs) { var addBall = function() { objs.unshift(new BallObject(els.value / 100, (Math.random() * 10) - 5, -20)); }, d = document, c = d.createElement('canvas'), b = d.createElement('button'), els = d.createElement('input'), clr = d.createElement('input'), cnt = d.createElement('input'), clrl = d.createElement('label'), cntl = d.createElement('label'); b.innerHTML = 'add ball with elasticity: <span>0.70</span>'; b.onclick = addBall; els.type = 'range'; els.min = 0; els.max = 100; els.step = 1; els.value = 70; els.style.display = 'block'; els.onchange = function() { b.getElementsByTagName('span')[0].innerHTML = (this.value / 100).toFixed(2); }; clr.type = cnt.type = 'checkbox'; clr.checked = cnt.checked = true; clrl.style.display = cntl.style.display = 'block'; clrl.appendChild(clr); clrl.appendChild(d.createTextNode('clear each frame')); cntl.appendChild(cnt); cntl.appendChild(d.createTextNode('continuous shower!')); c.style.border = 'solid 1px #3369ff'; c.style.display = 'block'; c.width = 700; c.height = 550; c.shouldClear = function() { return clr.checked; }; d.body.appendChild(c); d.body.appendChild(els); d.body.appendChild(b); d.body.appendChild(clrl); d.body.appendChild(cntl); setInterval(function() { if (cnt.checked) { addBall(); } }, 333); return c; } // start: var objs = [], c = createCanvasWithControls(objs), ctx = c.getContext('2d'), fps = 30, // target frames per second ppm = 20, // pixels per meter g = 9.8, // m/s^2 - acceleration due to gravity t = new Date().getTime(); // add the floor: objs.push(new FloorObject(c.height - 10)); // as expando so its accessible in draw [this overides .scale(x,y)] ctx.scale = 0.5; ctx.fillStyle = 'rgb(100,200,255)'; ctx.strokeStyle = 'rgb(33,69,233)'; ctx.transform(ctx.scale, 0, 0, ctx.scale, c.width / 2, c.height / 2); setInterval(function() { var i, j, nw = c.width / ctx.scale, nh = c.height / ctx.scale, nt = new Date().getTime(), dt = (nt - t) / 1000; if (c.shouldClear()) { ctx.clearRect(nw / -2, nh / -2, nw, nh); } for (i = 0; i < objs.length; i++) { // if a ball > viewport width away from center remove it while (objs[i].px < -nw || objs[i].px > nw) { objs.splice(i, 1); } objs[i].update(g, dt, ppm, objs, i); for (j = i + 1; j < objs.length; j++) { objs[j].collide(objs[i]); } objs[i].draw(ctx); } t = nt; }, 1000 / fps); 

the real "meat" and origin for this discussion is the obj.collide(obj) method.

if we dive into (I commented on this this time, since it is much more complicated than the "last"), you will see that this equation: equation for inelastic collision , still remains the only one used in this line: this.v.tx(dn.multiply((cr * obj.m * (v2 - v1) + this.m * v1 + obj.m * v2) / sm)); Now I'm sure that you are still saying: "zomg wtf! Is the same one-dimensional equation!" but when you stop and think about it, a “collision” occurs in only one dimension. That is why we use vector equations to extract applicable components and apply collisions only to those specific parts, leaving the others untouched to go our own fun (ignoring friction and simplifying the collision so as not to take into account the dynamic forces of energy conversion, as described in the commentary for CR). This concept, obviously, becomes more complicated as the complexity of the object increases and the number of points of scene data increases to account for things such as deformation, rotational inertia, uneven distribution of mass and friction points ... but what still goes beyond this is almost not worth mentioning ..

Basically, the concepts that you really need to “understand” in order to feel intuitive for you are the basics of the vector equations (they are all located in the Vector prototype), how they interact with each (which really means normalizing, or take a point-scalar product, for example, after reading / talking with someone who knows) and a basic understanding of how collisions affect the properties of an object (mass, speed, etc.), read / speak with someone who knows)

Hope this helps, good luck! -ck

+11
source

Here's a demonstration of the inelastic collision in action equation for you:

 function BallObject(elasticity) { this.v = { x: 1, y: 20 }; // velocity: m/s^2 this.m = 10; // mass: kg this.p = { x: 40, y: 0}; // position this.r = 15; // radius of obj this.cr = elasticity; // elasticity } function draw(obj) { ctx.beginPath(); ctx.arc(obj.px, obj.py, obj.r, 0, 2 * Math.PI); ctx.closePath(); ctx.stroke(); ctx.fill(); } function collide(obj) { obj.vy = (obj.cr * floor.m * -obj.vy + obj.m * obj.vy) / (obj.m + floor.m); } function update(obj, dt) { // over-simplified collision detection // only consider the floor for simplicity if ((obj.py + obj.r) > c.height) { obj.py = c.height - obj.r; collide(obj); } obj.vy += g * dt; obj.px += obj.vx * dt * ppm; obj.py += obj.vy * dt * ppm; } var d = document, c = d.createElement('canvas'), b = d.createElement('button'), els = d.createElement('input'), clr = d.createElement('input'), clrl = d.createElement('label'), ctx = c.getContext('2d'), fps = 30, // target frames per second ppm = 20, // pixels per meter g = 9.8, // m/s^2 - acceleration due to gravity objs = [], floor = { v: { x: 0, y: 0 }, // floor is immobile m: 5.9722 * Math.pow(10, 24) // mass of earth (probably could be smaller) }, t = new Date().getTime(); b.innerHTML = 'add ball with elasticity: <span>0.70</span>'; b.onclick = function() { objs.push(new BallObject(els.value / 100)); }; els.type = 'range'; els.min = 0; els.max = 100; els.step = 1; els.value = 70; els.style.display = 'block'; els.onchange = function() { b.getElementsByTagName('span')[0].innerHTML = (this.value / 100).toFixed(2); }; clr.type = 'checkbox'; clr.checked = true; clrl.appendChild(clr); clrl.appendChild(d.createTextNode('clear each frame')); c.style.border = 'solid 1px #3369ff'; c.style.borderRadius = '10px'; c.style.display = 'block'; c.width = 400; c.height = 400; ctx.fillStyle = 'rgb(100,200,255)'; ctx.strokeStyle = 'rgb(33,69,233)'; d.body.appendChild(c); d.body.appendChild(els); d.body.appendChild(b); d.body.appendChild(clrl); setInterval(function() { var nt = new Date().getTime(), dt = (nt - t) / 1000; if (clr.checked) { ctx.clearRect(0, 0, c.width, c.height); } for (var i = 0; i < objs.length; i++) { update(objs[i], dt); draw(objs[i]); } t = nt; }, 1000 / fps); 

to see it in action yourself, just go here: http://jsbin.com/iwuxol/edit#javascript,live

This uses this equation: enter image description here

and since your “floor” does not move, you only need to consider the effect on the speed of the ball. remember that there are quite a few shortcuts and oversights, so this is a very primitive physics engine and is mainly intended to illustrate this equation ...

hope this helps -ck

+3
source

I highly recommend that you familiarize yourself with the center of the momentum frame . This makes collisions much easier to understand. (And without this understanding, you are simply manipulating mysterious equations, and you will never know why everything went wrong.)

In any case, to determine the angle, you can use the impact parameter, basically how far “from the center” one ball hits another. Two balls approach each other in opposite directions (in the frame of the center-momentum), and the distance between their centers perpendicular to these velocities is the impact parameter h . Then the deviation angle is 2 acos (h / (r 1 + r 2 )).

Once you get it perfectly, you can worry about inelastic collisions and restitution rates.

+1
source

Source: https://habr.com/ru/post/909235/


All Articles