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;

}



The physics doesn't work, the balls fall right through the line when the bounce coefficient is less than one.

The lines can only horisontal, I want the lines to work at all angles!

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) 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 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,



This is the code- 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)