Tomáš Zato
Tomáš Zato

Reputation: 53129

My gravity simulation is repulsing objects in 1nd and 3rd quadrant

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

Answers (1)

Lutz Lehmann
Lutz Lehmann

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

Related Questions