eh Click and drag to make a line for the stream to bounce on

Simple bouncy physics thing

How to program a simple collision system

Pretty fun right? Here's an explaination of what's happening behind that canvas.

Making a physics simulation is not as easy as I thought! I spent months working on the code, just so I could get something functional. I decided I wanted to share my "hard" work and guide you through how I made my code work.

Lets begin with the most basic, the way our particle moves. Our particles have X and Y coordonates. I express them in the form of vectors.
eh
This doesnt tell us much our particle, we don't know where they are going. We need to add a velocity and acceleration. Take a look at where the particle goes when you change the initial velocity and acceleration.
eh
We have our first bit of code. We now have a class for our particle and a few functions. This code tells the computer how to move our particle in one unit of time. This code is running in your browser!
this.Update=function(){//Update position, velocity and acceleration
   this.Pos=this.NextPos();
   this.Vel.set(Vadd(this.Vel,this.Acc));
   this.Acc.set(this.Grav);
}
this.NextPos=function(){ //Change position by velocity and 1/2 acceleration
   return Vadd(this.Pos,Vadd(this.Vel,Vscale(this.Acc,0.5)));
}
Now that we understand how our particle works, Lets get to the hard part, the collision. I began with the most simple solution. We say it collides when its above the line before it updates and underneath the line when after. The simplest solution for the barrier is just a horisontal one.

Also, like in real life, our barrier should have some friction, and bounce. Try moving it around and changing some of its qualities.
eh
You might of noticed a few things about simulation above. This part for me was one of the roadblocks I ran into while trying to make this thing.

Heres the faulty code that runs the simulation.
if(Wall.Collides(Ball)){
   Wall.Bounce(Ball);
}
//This runs in the wall class
this.Collides=function(B){//takes a ball object
   var Cross= (B.Pos.y < this.Corner.y)&&(B.NextPos().y > this.Corner.y);
   //checks if it falls through
   var Tween= (B.Pos.x < this.Corner.x)&&(B.Pos.x > this.Corner.x+this.length);
   return Cross && Tween;
}
this.Bounce=function(B){//The bounce
   B.Vel.y*=-bounce;
   B.Vel.x*=slide;
}
Lets list out our problems-

The solution for the first issue came to me when I realised I could do something simple. The code above has no issues, I was just missing one crucial thing. I needed to add a normal force to stop it from falling through. A normal force is a force the push an object exerts on an object resting on it, to counter gravity, just what we need.

Here's what I added. (The particle becomes red when it gets stablised)
if(Wall.Collides(Ball)){
   Wall.Bounce(Ball);
   if(Wall.Collides(Ball)){ //Check if it still falls through
     Wall.Stablise(Ball); //Set Acc.y and Vel.y to 0
     Ball.PaintRed();
   }
}
eh
Thats better.

Now that thats solved lets move on to our next problem. Having it to work for the horisontal case was so easy, if only we could rotate the whole frame to make a tilded one horisontal. It turns out you can actually do just that!

There is actually a pair of functions that do this, vector multiplication and it's inverse, vector divison.

Look at the functions below, find out how they work.
eh eh
The first function returns the two vectors multiplied, which looks like one of them stacked on the other. Imagine holding the point 0,0 in place and streching the point 0,1 to a specific vector by scaling and rotating space. If we see where an other vector gets dragged to, thats the result of multiplying them together.

The second function is the inverse of the first, It takes a vector to the point 0,1, and sees how another gets dragged along with it. These functions actualy have a connection with imaginary numbers. If you want to see a cool demonstration of that, check this out.

This is the code-
function Vmult(A,B){
    return new vect(A.x*B.x-A.y*B.y,A.x*B.y+A.y*B.x);
}

function Vdiv(P,C){
   return new vect((C.x*P.x+C.y*P.y)/((C.x*C.x)+(C.y*C.y)),
   (C.x*P.y-C.y*P.x)/((C.x*C.x)+(C.y*C.y)));
}
These functions are usefull because we can use the division one do take a specific vector to 1,0 ,making it horisontal. Then we can multiply by the same vector to return it to its original state. This allows us to use the code we already made for the horisontal case, for all cases.

Now we can make our barriers slanted. Lets add the vector that indicates the barrier direction to the wall class. The new code for the Collides ,Bounce and Stabilise functions look like this.
this.Collides=function(Ball){
var Posr=Vdiv(Vadd(Ball.Pos,Vscale(Corner,-1)),Base); //Flattened Pos
var Nextr=Vdiv(Vadd(Ball.NextPos(),Vscale(Corner,-1)),Base)//Flattened nextPos;
var C1=((Posr.y> 0)&&(Nextr.y< 0));//Check all the combos
var C2=((Posr.y<0)&&(Nextr.y> 0));
var C3=((Posr.y===0)&&(Nextr.y< 0));
var C4=((Nextr.y===0)&&(Posr.y> 0));
var C5=((Posr.y===0)&&(Nextr.y===0));
var Tween=((Posr.x>=0)&&(Posr.x< =1))||((Nextr.x> =0)&&(Nextr.x<=1));
return (C1||C2||C3||C4||C5)&&Tween;
}
this.Bounce=function(Ball){
   var Rvel=Vdiv(Ball.Vel,Base);// Rotated Vel
   var RAcc=Vdiv(Ball.Acc,Base);// Rotated Acc
   Rvel.y*=-this.bounce;
   Rvel.x*=this.slide;
   Ball.Vel=Vmult(Rvel,Base);// Undo rotations
   Ball.Acc=Vmult(RAcc,Base);
}
this.Stablise=function(Ball){
   var RVel=Vdiv(Ball.Vel,Base);//Rotate frame
   var RACc=Vdiv(Ball.Acc,Base);
   RVel.y=0; //Stablise
   RACc.y=0;
   Ball.Vel=Vmult(RVel,Base);//Undo rotation
   Ball.Acc=Vx(RACc,Base);
}
Heres what it looks like-
eh
And thats it, thats how the thing works, for the most part!

Of course, it is not really that simple. I did leave out a lot of things like checking collision between multiple barriers, but thats for an other time.



Hope you enjoyed my strange thingy! If you did, you can go back to the main page to see more stuff like this. (When I finish making them, that is)
Back to main page