Max Hudson
Max Hudson

Reputation: 10206

Gravity and impact bug

I am starting on a physics/particle simulator and I am having some trouble with collision detection:

http://mmhudson.com/physics.html

Im not so much looking for a code solution, but someone to explain the issue to me conceptually.

The way it works is I check to see if the particle is going to be inside/intersect with the object when it is next moved. If it is, the gravity multiplier is reversed so its direction is reversed.

The equation for movement I use is:

Next location = current speed + rate of gravity + current location

Where speed is the gravity multiplier

Hopefully someone has seen an issue like this before or is willing to check out the source of my page.

Any help at all is greatly appreciated

Upvotes: 0

Views: 195

Answers (2)

Celos
Celos

Reputation: 517

No conceptual explanation, but a bunch of random observations:

I'd recommend adding canvas width/height variables and comparing them against the particle position. Right now, your particles keep falling even if they drop off the canvas. Something like:

if( particles[i][1] > height )
    particles.splice(i,1);

newPY < objects[k][2] + objects[k][3] + radius

is really weird. What are you getting from this? Adding the width and height of the objects and the particle radius? If you remove this part, particles will bounce off objects as long as they have "momentum".


As for momentum, I assume you want to figure out how to stop the particles from falling through the objects. Given current code, I'd do this: add a fifth variable to the particle, defaulting to the height of the canvas. Then, once you find out that you have an impact, save the impact position to the particle and after the loop, check if the particle is below that point. If so, reset it to that point. Dirty fix, but hey, it works. I've added the complete loop below that worked for me. To stop the objects from being wiped out by the clearRect method, maybe consider redrawing them.


You are checking for particles on top of the objects only, but I assume the "falling through" aspect is part of the bug you asked about, so not too important at the moment:

particles[i][1] < objects[k][1] + objects[k][3] + radius 

Could be however, if you decided to play around and reduce gravity, so that particles would instead gain momentum and bounce against objects above.


As for your objCheck variable, you confuse the width for y in the last && part. It should be:

mY < objects[i][1] + objects[i][3] + radius 

instead of

mY < objects[i][2] + objects[i][3] + radius

Right now, your objCheck is not working.


Also

for(var i=0; i < particles.length; i++) {
    var clrRadius = 2*radius;
    canvas.clearRect(particles[i][0]-radius, particles[i][1]-radius, clrRadius, clrRadius);
}

is better than

for(var i=0; i < particles.length; i++){
    var clrRadius = radius + 4;
    canvas.clearRect(particles[i][0]-(clrRadius/2), particles[i][1]-(clrRadius/2), clrRadius, clrRadius);
}

edit: Seems you changed the code, since I last checked it, so the above might no longer be relevant!

edit2: added particle stopping fix. Here's the complete gravity loop:

for(var i=0; i<particles.length; i++){
var clrRadius = 2*radius;
canvas.clearRect(particles[i][0]-radius, particles[i][1]-radius, clrRadius, clrRadius);
}

for(var i=0; i < particles.length; i++){
var newPY = particles[i][1] += particles[i][2] + particles[i][3];

for(var k=0; k<objects.length; k++){
    if(
        //particle
        particles[i][0] > objects[k][0] - radius && 
        particles[i][0] < objects[k][0] + objects[k][2] + radius && 
        particles[i][1] > objects[k][1] - radius &&
        particles[i][1] < objects[k][1] + objects[k][3] + radius //&& 
    ){
            //reverse gravity
            particles[i][2] = particles[i][2] * -1;
            particles[i][5] = objects[k][1] - radius;
    }
}


particles[i][2] += particles[i][3]*weight;
particles[i][1] += particles[i][2];

if( particles[i][1] > particles[i][5] )
    particles[i][1] = particles[i][5];

if( particles[i][1] > height )
    particles.splice(i,1);
}

for(var i=0; i <particles.length; i++){
canvas.fillStyle = "#000";
canvas.beginPath();
canvas.arc(particles[i][0], particles[i][1], radius, 0, Math.PI*2, true);
canvas.closePath();
canvas.fill();
}

Upvotes: 2

scolej
scolej

Reputation: 1

I wouldn't use a gravity multiplier.

Each object should look something like this:

var circle = {
    x: 0,   // x position
    y: 0,   // y position
    dx: 0,  // x velocity
    dy: 0   // y velocity
}

To update the particle, multiply velocity (dx, dy) by some time interval and add this to the current position.

Every cycle, add some change in velocity as a result of gravity.

If you detect a collision change the velocity so the circles bounce off each other. An example of this would be:

// In a collision, simply reverse the direction of movement
// so the circles move away from each other.

function onCollision(circleA, circleB) {
    circleA.dx *= -1;
    circleA.dy *= -1;

    circleB.dx *= -1;
    circleB.dy *= -1;
}

Upvotes: 0

Related Questions