We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hey, I'm converting this sketch: https://processing.org/examples/circlecollision.html I've stripped back what I can, but still can't work out why it's flipping out. I can get it working in Processing just fine.
Using P5JS in the default IDE on OS X.
var ps;
function setup() {
createCanvas(640, 360);
ps = new ParticleSystem();
while(ps.particles.length < 2) {
var x = getRandomInt(0, width);
var y = getRandomInt(0, height);
ps.addParticle(x, y);
}
}
function draw() {
background(44, 44, 45);
ps.run();
ps.particles[0].checkCollision(ps.particles[1]);
}
function ParticleSystem(location) {
this.origin = createVector(width/2, height/2);
this.particles = [];
}
ParticleSystem.prototype.addParticle = function(x, y) {
this.particles.push(new Particle(x, y));
}
ParticleSystem.prototype.run = function() {
var p;
for (var i = this.particles.length - 1; i >= 0; i--) {
p = this.particles[i];
p.run();
}
}
function Particle(x, y) {
this.location = createVector(x, y);
var r = getRandomInt(40, 100);
this.radius = r;
this.m = r*0.01;
this.velocity = p5.Vector.random2D();
this.velocity.mult(3);
}
Particle.prototype.run = function() {
this.update();
this.checkBoundaryCollision();
this.display();
}
Particle.prototype.update = function() {
this.location.add(this.velocity);
}
Particle.prototype.display = function() {
fill(44, 44, 45);
stroke(255, 184, 12);
strokeWeight(5);
ellipse(this.location.x, this.location.y, this.radius*2, this.radius*2);
}
Particle.prototype.checkBoundaryCollision = function() {
if (this.location.x > width - this.radius) {
this.location.x = width - this.radius;
this.velocity.x *= -1;
}
else if (this.location.x < this.radius) {
this.location.x = this.radius;
this.velocity.x *= -1;
}
else if (this.location.y > height - this.radius) {
this.location.y = height-this.radius;
this.velocity.y *= -1;
}
else if (this.location.y < this.radius) {
this.location.y = this.radius;
this.velocity.y *= -1;
}
}
Particle.prototype.checkCollision = function(other) {
var bVect = p5.Vector.sub(this.location, other.location);
var bVectMag = sqrt(bVect.x * bVect.x + bVect.y * bVect.y);
if (bVectMag < this.radius + other.radius) {
// get angle of bVect
var theta = atan2(bVect.x, bVect.y);
// precalculate trig values
var sine = sin(theta);
var cosine = cos(theta);
/* bTemp will hold rotated ball positions. You
just need to worry about bTemp[1] position*/
var bTemp = [
createVector(),
createVector()
];
/* this ball's position is relative to the other
so you can use the vector between them (bVect) as the
reference point in the rotation expressions.
bTemp[0].position.x and bTemp[0].position.y will initialize
automatically to 0.0, which is what you want
since b[1] will rotate around b[0] */
bTemp[1].x = cosine * bVect.x + sine * bVect.y;
bTemp[1].y = cosine * bVect.y - sine * bVect.x;
// rotate Temporary velocities
var vTemp = [
createVector(),
createVector()
];
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
/* Now that velocities are rotated, you can use 1D
conservation of momentum equations to calculate
the final velocity along the x-axis. */
var vFinal = [
createVector(),
createVector()
];
// final rotated velocity for b[0]
vFinal[0].x = ((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (this.m + other.m);
vFinal[0].y = vTemp[0].y;
// final rotated velocity for b[0]
vFinal[1].x = ((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) / (this.m + other.m);
vFinal[1].y = vTemp[1].y;
// hack to avoid clumping
bTemp[0].x += vFinal[0].x;
bTemp[1].x += vFinal[1].x;
/* Rotate ball positions and velocities back
Reverse signs in trig expressions to rotate
in the opposite direction */
// rotate balls
var bFinal = [
createVector(),
createVector()
];
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
// update balls to screen position
other.location.x = this.location.x + bFinal[1].x;
other.location.y = this.location.y + bFinal[1].y;
this.location.add(bFinal[0]);
// update velocities
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
}
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
Cheers, Ben
Answers
I've tried to make 1 myself from the original: https://processing.org/examples/circlecollision.html
Unfortunately I've stumbled in some bug too. Although diff. from yours! :-<
Gonna try debugging it some other time: :-\"
P.S.: Fixed w/ v2.2 and on! B-)
Thanks for taking a look! Unfortunately when I run your script only one ball is created and I get the error:
"27: Uncaught TypeError: Object # has no method 'checkCollision'"
When you say just 'dances' do you mean it jiggles along the display boundary?
@quark, why don't you also follow my trick about running p5.js sketches in its own website?
Just paste his code (or mine) there and you'll see what he means. O:-)
@GoToLoop thanks for the trick about running p5.js sketches in its own website - works a treat.
I am not going to attempt to fix the code since I don't program using JavaScript but I do have a suggestion as to the cause.
If you consider what happens when two particles collide, you first calculate the new velocity vectors which are then are applied to the particles position on the next update to get their new positions. I believe the problem is that the 2 particles are still colliding after the update so new velocity vectors are calculated but these will be in the opposite direction to the last ones. If this continues then the particles will appear to dance.
The same thing can happen at the boundaries in that the particle remains outside the boundary jiggling back and forth because the velocity is multiplied by minus 1 on each update.
To avoid the risk of jiggling on the boundaries I suggest you changes lines 65-82 to
With regard to particle collisions you have two options
1) When the collision is detected calculate the 'rebound' velocity vectors. Then move the two particles apart along the line joining their centres so the distance between them is > than the sum of their radii i.e. no longer colliding
2) Use a boolean variable which is set to false when the two particles are not colliding and true when a collision has been detected. If true then still check for collision detection but do nothing if the boolean is true. It will eventually be changed back to false as they move apart. It means that the new velocity vectors are calculated just once per collision.
Both of these solutions are based on the assumption that your code correctly calculates the rebound velocities and I am not convinced on that.
@quark Thanks for your input, much appreciated! Very good to know, will definitely help me avoid some of the unwanted movements.
@GoToLoop Thanks for getting this working, I'll noodle through it and figure out where I was going wrong. Strange that it wasn't working in the P5JS IDE, so I'll investigate that also and submit a github issue if solve the problem.
p5.js' IDE is Mac OS X only! Seems like it's alpha and currently is at a very old version 0.1.8 from Sep 18th:
https://github.com/antiboredom/jside/releases/
While p5.js' complete library is v0.3.14 from Dec 10th:
https://github.com/lmccart/p5.js/releases/