Reputation: 53129
I am creating simple gravity simulation. I use Pixi.JS to render the objects. I use Math.atan2
to calculate vector angle from object A to object B. Fur some reason, when object are situated at certain angles it doesn't work properly - I get a repulsive force instead of attractive.
var renderer = PIXI.autoDetectRenderer(600, 500,{backgroundColor : 0x0});
document.body.appendChild(renderer.view);
// create the root of the scene graph
var stage = new PIXI.Container();
// create a texture from an image path
var texture = PIXI.Texture.fromImage('http://pixijs.github.io/examples/_assets/basics/bunny.png');
var objects = [];
// start animating
animate();
function animate() {
requestAnimationFrame(animate);
// render the container
renderer.render(stage);
}
/**
the third argument, mass, must be in kilograms **/
function GravityWell(x,y,mass) {
this.sprite = new PIXI.Sprite(texture);
// center the sprite's anchor point
this.sprite.anchor.x = 0.5;
this.sprite.anchor.y = 0.5;
// move the sprite to the center of the screen
this.sprite.position.x = this.x = x;
this.sprite.position.y = this.y = y;
stage.addChild(this.sprite);
this.rotation = 0;
this.sprite.rotation = this.rotation;
this.vx = 0;
this.vy = 0;
this.mass = mass;
}
GravityWell.prototype.G = 6.674e-11;
GravityWell.prototype.acceleration = function(object) {
var dist = (this.x-object.x)*(this.x-object.x)+(this.y-object.y)*(this.y-object.y);
if(dist>0)
return (this.G*this.mass*object.mass)/dist;
else
return 0;
}
// This should be correct according to http://gamedev.stackexchange.com/a/33710/25920
GravityWell.prototype.angleTo = function(object) {
return Math.atan2(-this.x+object.x, -this.y+object.y);
}
GravityWell.prototype.accelerate = function(direction, magnitude) {
var deltaV = magnitude/this.mass;
this.vx += deltaV*Math.cos(direction);
this.vy += deltaV*Math.sin(direction);
}
GravityWell.prototype.move = function(dt) {
dt /= 1000;
this.x += this.vx*dt;
this.y += this.vy*dt;
this.sprite.position.x = this.x;
this.sprite.position.y = this.y;
}
// Creating objects
var ship;
objects.push(new GravityWell(300, 250, 1000000000));
objects.push(new GravityWell(400, 400, 20000));
objects.push(new GravityWell(100, 100, 20000));
objects.push(new GravityWell(400, 100, 20000));
var last = performance.now();
setInterval(function() {
var dt = performance.now() - last;
for(var i=0,l=objects.length; i<l; i++) {
var obj = objects[i];
for(var j=i+1,l=objects.length; j<l; j++) {
var a = obj.acceleration(objects[j]);
if(a!=0) {
obj.accelerate(obj.angleTo(objects[j]), a);
objects[j].accelerate(objects[j].angleTo(obj), a);
}
}
}
for(var i=0,l=objects.length; i<l; i++) {
objects[i].move(dt*10000);
}
}, 10);
<script src="//darker.github.io/asteroids/demo-elastic-bounce/pixi.js"></script>
I'm not sure what am I doing wrong. I tried to alter sign in the acceleration but it didn't have desired effect.
Upvotes: 1
Views: 1278
Reputation: 25972
There are several errors in your code.
1.) If dx = r*cos(phi)
and dy = r*sin(phi)
as used in the velocity update, then
phi = atan2( dy, dx )
i.e., reverse order of arguments.
2.) For the force vector computation you do not need the angle at all, as in
var dx = this.x-object.x;
var dy = this.y-object.y;
var dist = Math.sqrt(dx*dx+dy*dy);
var deltaV = magnitude/this.mass;
var deltaVx = dx/dist;
var deltaVy = dy/dist;
3.) Your update of the velocities also needs the time step dt
, v += a*dt
. One logical point to insert this is at
var deltaV = magnitude*dt/this.mass;
or in the parameter passing of magnitude.
Upvotes: 1