{{ message }}

Instantly share code, notes, and snippets.

# christopher4lis/util-elastic-collision.js

Last active Oct 9, 2021
A set of utility functions used to reproduce the effect of elastic collision within HTML5 canvas. Used in the Chris Courses tutorial video on collision detection: https://www.youtube.com/watch?v=789weryntzM
 /** * Rotates coordinate system for velocities * * Takes velocities and alters them as if the coordinate system they're on was rotated * * @param Object | velocity | The velocity of an individual particle * @param Float | angle | The angle of collision between two objects in radians * @return Object | The altered x and y velocities after the coordinate system has been rotated */ function rotate(velocity, angle) { const rotatedVelocities = { x: velocity.x * Math.cos(angle) - velocity.y * Math.sin(angle), y: velocity.x * Math.sin(angle) + velocity.y * Math.cos(angle) }; return rotatedVelocities; } /** * Swaps out two colliding particles' x and y velocities after running through * an elastic collision reaction equation * * @param Object | particle | A particle object with x and y coordinates, plus velocity * @param Object | otherParticle | A particle object with x and y coordinates, plus velocity * @return Null | Does not return a value */ function resolveCollision(particle, otherParticle) { const xVelocityDiff = particle.velocity.x - otherParticle.velocity.x; const yVelocityDiff = particle.velocity.y - otherParticle.velocity.y; const xDist = otherParticle.x - particle.x; const yDist = otherParticle.y - particle.y; // Prevent accidental overlap of particles if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) { // Grab angle between the two colliding particles const angle = -Math.atan2(otherParticle.y - particle.y, otherParticle.x - particle.x); // Store mass in var for better readability in collision equation const m1 = particle.mass; const m2 = otherParticle.mass; // Velocity before equation const u1 = rotate(particle.velocity, angle); const u2 = rotate(otherParticle.velocity, angle); // Velocity after 1d collision equation const v1 = { x: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2), y: u1.y }; const v2 = { x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2), y: u2.y }; // Final velocity after rotating axis back to original location const vFinal1 = rotate(v1, -angle); const vFinal2 = rotate(v2, -angle); // Swap particle velocities for realistic bounce effect particle.velocity.x = vFinal1.x; particle.velocity.y = vFinal1.y; otherParticle.velocity.x = vFinal2.x; otherParticle.velocity.y = vFinal2.y; } }

### ramanbanka commented Aug 14, 2018 • edited

 ``````// Prevent accidental overlap of particles if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) `````` HI Chris, I was watching your collision detection video, however I particularly don't understand the above if condition. Can you please explain?

### dev-itrankers commented Sep 8, 2018

 so that the algorithm doesn't run for object which are overlapped

### DebajyotiS commented Jan 20, 2019

 Hi, I tried to do this in processing, and I getting a weird bug. Some balls are getting stuck on the walls. Can someone help? Here's my code : ``````public class velocity{ float delx, dely; //Constructor 1 public velocity(){} //Constructor 2 public velocity(float delx, float dely){ this.delx = delx; this.dely = dely; } //Mutators for xvelocity and y velocity public float getdelx(){ return this.delx; } public float getdely(){ return this.dely; } //Accessors for xvelocity and y velocity public void setdelx(float delx){ this.delx = delx; } public void setdely(float dely){ this.dely = dely; } } public class particle{ private float xpos , ypos, delx , dely,size, decay, mass; color colour; //constructor 1 public particle(float x, float y){ this.xpos = x; this.ypos = y; } //constructor 2 public particle(float xpos, float ypos, float size, float delx, float dely,float decay, float mass){ this.xpos = xpos; this.ypos = ypos; this.size = size; this.delx = delx; this.dely = dely; this.decay = decay; this.mass = mass; } //Mutators for size, x velocity y velocity and velocity vector public void setsize(float size){ this.size = size; } public void setDX(float delx){ this.delx = delx; } public void setDY(float dely){ this.dely = dely; } //Accessors for size, x position, y position, x velocity and y velocity public float getsize(){ return this.size; } public float getX(){ return this.xpos; } public float getY(){ return this.ypos; } public float getDX(){ return this.delx; } public float getDY(){ return this.dely; } public float getmass(){ return this.mass; } public velocity getvel(){ velocity v = new velocity(this.getDX(), this.getDY()); return v; } //Functionality. Moving around, Bouncing off of walls, and basic display updates public void move(){ this.xpos += this.delx; this.ypos += this.dely; } public void bounce(){ if((this.xpos - this.size/2.0) < 0 || (this.xpos + this.size/2.0) > width){ this.setDX(this.getDX()*-(this.decay)); } if((this.ypos - this.size/2.0) < 0 || (this.ypos + this.size/2.0) > height){ this.setDY(this.getDY()*-(this.decay)); } } public void update(particle[] elec){ for(int i =0; i< elec.length; i++){ if(this == elec[i]) continue; if(dist(this.getX(),this.getY(),elec[i].getX(),elec[i].getY()) - this.getsize() <0){ collision(this, elec[i]); //println(dist(this.getX(),this.getY(),elec[i].getX(),elec[i].getY()) - this.getsize()/2); } } display(); } public void display(){ stroke(0); fill(119,240,153); ellipse(this.xpos, this.ypos, this.size ,this.size); } } velocity rotate(velocity v, float angle){ float x = v.getdelx()*cos(angle) - v.getdely()*sin(angle); float y = v.getdelx()*sin(angle) + v.getdely()*cos(angle); velocity vel = new velocity(x,y); return vel; } void collision(particle p1, particle p2){ float xveldiff = p1.getDX()-p2.getDX(); float yveldiff = p1.getDY()-p2.getDY(); float xdist = p2.getX() - p1.getX(); float ydist = p2.getY() - p1.getY(); //Check for accidental overlaps of particles if(xveldiff*xdist + yveldiff*ydist > 0){ float angle = -atan2(p2.getY() - p1.getY(), p2.getX() - p1.getY()); float m1 = p1.getmass(); float m2 = p2.getmass(); velocity u1 = rotate(p1.getvel(),angle); velocity u2 = rotate(p2.getvel(),angle); velocity v1 = new velocity(u1.getdelx() * (m1 - m2) / (m1 + m2) + u2.getdelx() * 2 * m2 / (m1 + m2), u1.getdely()); velocity v2 = new velocity(u2.getdelx() * (m1 - m2) / (m1 + m2) + u1.getdelx() * 2 * m2 / (m1 + m2), u2.getdely()); velocity vf1 = rotate(v1, -angle); velocity vf2 = rotate(v2, -angle); p1.setDX(vf1.getdelx()); p1.setDY(vf1.getdely()); p2.setDX(vf2.getdelx()); p2.setDY(vf2.getdely()); } } And this is the main file : particle[] elec = new particle; boolean record = false; void setup(){ float x=0,y=0; int i,j; float diam = 100; size(800,400); //Initialising the particle objects for (int k = 0; k < elec.length; k++){ x = random(width/10, width/1.2); y = random(height/10, height/1.2); elec[k] = new particle(x,y); } //Spawning at random places for ( i = 0; i < elec.length; i++){ if (i!=0){ for ( j = 0; j < elec.length; j ++){ if (dist(x,y,elec[j].getX(),elec[j].getY()) <= diam){ x = random(width/10, width/1.2); y = random(height/10, height/1.2); j = -1; } } } elec[i] = new particle(x,y,diam,4,4,1,2); } } void draw(){ background(0); for (int i = 0; i < elec.length; i++){ elec[i].update(elec); elec[i].move(); elec[i].bounce(); if(record){ saveFrame("collide_#####.png"); fill(255,0,0); } else { fill(0,255,0); } ellipse(width/1.01, height/1.01,5,5); } } void keyPressed(){ if (key =='r' || key =='R'){ record = !record; } } //float getdistance(float x, float y, float x1, float y1){ // return pow(pow((x-x1),2)+pow((y-y1),2),0.5); //} ``````

### Morschois commented Jun 13, 2019

 There is actually a mistake in the formula that only shows up if the colliding circles have different masses. you have two swap the subscipts of the masses too. At least where there is subtraction and division.

### leosarad commented Oct 2, 2019

 Problem 1: collisIon resolving actually overlaps circles Problem 2: when we set different masses for circles total energy in canvas is increased on several collisions (at least for my code )... Problem 1: // Prevent accidental overlap of particles if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) i don't know why but this code gave bug in my code. if circles touched then they overlapped each other providing a centrifugal force(or centripetal i don't remember). Later I changed it to if (xVelocityDiff * xDist + yVelocityDiff * yDist <= 0) it worked perfect Problem 2: there's something in comments above about this problem...refer to that

### khmahfuzhasan commented Oct 29, 2019

 Thank you.

### noru commented Nov 6, 2020 • edited

 For those who wonder this line `if (xVelocityDiff * xDist + yVelocityDiff * yDist >=0 )` This line is actually to detect if 2 overlapped circles are moving towards each other or not. If not, no need to perform a resolving process. The actual inequality (if 2 circles are moving away) is `(x + dx)^2 + (y + dy)^2 > x^2 + y^2` (velocity = dx / dy). After streamlined, you'll get the line. Note that, in this example, velocityDiff & dist are inconsistently calculated upon.

### NekoMaru76 commented Jan 27, 2021

 u guys r awesome

### PhillPanik commented Oct 9, 2021 • edited

 Hi! Thanks for the nice utility. Unfortunately this will only work for particles with the same mass. There are two small mistakes in the calculations for the second velocity. Line 52: const v2 = { x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2), y: u2.y }; Should be: const v2 = { x: u2.x * (m2 - m1) / (m1 + m2) + u1.x * 2 * m1 / (m1 + m2), y: u2.y };