Skip to content

Instantly share code, notes, and snippets.

@ederst
Last active November 16, 2019 20:58
Show Gist options
  • Save ederst/bb75db4beb74620a7c8569635a0a8889 to your computer and use it in GitHub Desktop.
Save ederst/bb75db4beb74620a7c8569635a0a8889 to your computer and use it in GitHub Desktop.
simple planetary gravity with phaser3
// based on this example:
// * http://jsfiddle.net/gJ4kA/
// further reads:
// * https://gamedev.stackexchange.com/questions/71233/planet-gravity
// * https://gamedev.stackexchange.com/questions/21063/2d-planet-gravity
// * http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/
// calc: https://www.ajdesigner.com/phpgravity/gravity_acceleration_equation.php#ajscroll
// todo: how to scale -> m/s² conversion to px/s² etc...
/*
// Constrain reticle to a cirlcle around player
function constrainReticle(reticle)
{
var distX = reticle.x - player.x; // X distance between player & reticle
var distY = reticle.y - player.y; // Y distance between player & reticle
var maxDist = 300;
var maxDistVec = new Phaser.Math.Vector2(distX, distY).normalize().multiply(
new Phaser.Math.Vector2(maxDist, maxDist)
);
// Ensures reticle cannot be moved offscreen (player follow)
text.setText([
"distXY: " + distX + " : " + distY,
"maxDistVec: " + maxDistVec.x + " : " + maxDistVec.y
]);
//reticle.x = player.x + maxDistVec.x;
//reticle.y = player.y + maxDistVec.y;
if ((maxDistVec.x > 0 && distX > maxDistVec.x) || (maxDistVec.x < 0 && distX < maxDistVec.x))
reticle.x = player.x + maxDistVec.x;
if ((maxDistVec.y > 0 && distY > maxDistVec.y) || (maxDistVec.y < 0 && distY < maxDistVec.y))
reticle.y = player.y + maxDistVec.y;
}
*/
var config = {
type: Phaser.AUTO,
parent: 'planet-gravity-example',
width: 1024,
height: 768,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x: 0 },
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.atlas('space', 'assets/tests/space/space.png', 'assets/tests/space/space.json');
this.load.image('target', 'assets/demoscene/ball.png');
}
var planet;
var moon;
var ship;
var keyBackThrust;
var keyFwdThrust;
var keyLeft;
var keyRight;
var keyShipCam;
var keyPlanetCam;
var keyMoonCam;
var reticle;
var mainCam;
//var rt;
//var trail;
var G = 0.5;//6.67e-11;
var planetMass = 500000000;
var moonMass = planetMass/20;
var planetRadius = 2500;
var moonRadius = 250;
var shipRadius = 10;
var graphics;
//var initialSpeed = 0;
//var initialVector;
function create() {
graphics = this.add.graphics();
planet = this.physics.add.sprite(400, 300, 'space', 'blue-planet').setOrigin(0.5, 0.5).setDisplaySize(planetRadius*2,planetRadius*2);
moon = this.physics.add.sprite(400, 15600, 'space', 'moon1').setOrigin(0.5, 0.5).setDisplaySize(moonRadius*2,moonRadius*2);
ship = this.physics.add.sprite(400, -2500, 'space', 'ship').setDepth(2).setOrigin(0.5, 0.5).setDisplaySize(20,20);
//rt = this.add.renderTexture(-20000, -20000, 40000, 40000);
//trail = this.add.image(0, 0, 'space', 'ship').setOrigin(0.5,0.5).setDisplaySize(10,10).setVisible(false);
ship.body.allowGravity = true;
moon.body.allowGravity = true;
var shipBodyPos = new Phaser.Math.Vector2(ship.x, ship.y);
var planetBodyPos = new Phaser.Math.Vector2(planet.x, planet.y);
var moonBodyPos = new Phaser.Math.Vector2(moon.x, moon.y);
// setup ship initial velocity
var shipPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, shipBodyPos.x, shipBodyPos.y);
// perpendicular 2d vector to gravitational vector (https://gamedev.stackexchange.com/a/146492)
var initialShipVector = new Phaser.Math.Vector2(-(planetBodyPos.y - shipBodyPos.y), planetBodyPos.x - shipBodyPos.x).normalize();
var initialShipSpeed = Math.sqrt(G*planetMass/shipPlanetDistance);
ship.body.velocity.x = initialShipVector.x * initialShipSpeed;
ship.body.velocity.y = initialShipVector.y * initialShipSpeed;
// setup moon initial velocity
var moonPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, moonBodyPos.x, moonBodyPos.y);
// perpendicular 2d vector to gravitational vector (https://gamedev.stackexchange.com/a/146492)
var initialMoonVector = new Phaser.Math.Vector2(-(planetBodyPos.y - moonBodyPos.y), planetBodyPos.x - moonBodyPos.x).normalize();
var initialMoonSpeed = Math.sqrt(G*planetMass/moonPlanetDistance);
moon.body.velocity.x = initialMoonVector.x * initialMoonSpeed;
moon.body.velocity.y = initialMoonVector.y * initialMoonSpeed;
text = this.add.text(32, 32).setScrollFactor(0).setFontSize(16).setColor('#ffffff');
// ship cam
mainCam = this.cameras.main;
mainCam.startFollow(ship);
keyBackThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
keyFwdThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
keyPlanetCam = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.P);
keyPlanetCam.on('down', function (key, event) {
// planet cam
mainCam.startFollow(planet);
mainCam.zoom = 0.13;
});
keyMoonCam = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.O);
keyMoonCam.on('down', function (key, event) {
// moon cam
mainCam.startFollow(moon);
mainCam.zoom = 0.5;
});
keyShipCam = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.I);
keyShipCam.on('down', function (key, event) {
// ship cam
mainCam.startFollow(ship);
mainCam.zoom = 1;
});
reticle = this.physics.add.sprite(ship.x, ship.y + 50, 'target');
reticle.setOrigin(0.5, 0.5).setDisplaySize(5, 5);
// Pointer lock will only work after mousedown
game.canvas.addEventListener('mousedown', function () {
game.input.mouse.requestPointerLock();
});
this.input.on('pointermove', function (pointer) {
if (this.input.mouse.locked)
{
reticle.x += pointer.movementX;
reticle.y += pointer.movementY;
}
}, this);
}
function update() {
var shipBodyPos = new Phaser.Math.Vector2(ship.body.x + shipRadius, ship.body.y + shipRadius);
ship.rotation = Phaser.Math.Angle.Between(ship.x, ship.y, reticle.x, reticle.y);
//restrainReticle()
reticle.body.velocity.x = ship.body.velocity.x;
reticle.body.velocity.y = ship.body.velocity.y;
/*var reticleBodyPos = new Phaser.Math.Vector2(reticle.body.x + reticle.body.width/2, reticle.body.y + reticle.body.height/2);
shipReticleNormalized = new Phaser.Math.Vector2(reticleBodyPos.x - shipBodyPos.x, reticleBodyPos.y - shipBodyPos.y).normalize();
if (shipBodyPos.x + shipReticleNormalized.x * 100 > reticleBodyPos.x) {
reticle.body.x = shipBodyPos.x + shipReticleNormalized.x * 100;
} else if (shipBodyPos.x + shipReticleNormalized.x * 100 < reticleBodyPos.x) {
reticle.body.x = shipBodyPos.x + shipReticleNormalized.x * 100;
}
if (shipBodyPos.y + shipReticleNormalized.y * 100 > reticleBodyPos.y) {
reticle.body.y = shipBodyPos.y + shipReticleNormalized.y * 100;
} else if (shipBodyPos.y + shipReticleNormalized.y * 100 < reticleBodyPos.y) {
reticle.body.y = shipBodyPos.y + shipReticleNormalized.y * 100;
}*/
var noCursorDown = true;
var downVec = Phaser.Math.Vector2.ZERO;
var upVec = Phaser.Math.Vector2.ZERO;
var leftVec = Phaser.Math.Vector2.ZERO;
var rightVec = Phaser.Math.Vector2.ZERO;
if (keyLeft.isDown) {
noCursorDown = false;
leftVec = this.physics.velocityFromAngle(ship.angle - 90, 10);
}
if (keyRight.isDown) {
noCursorDown = false;
rightVec = this.physics.velocityFromAngle(ship.angle + 90, 10);
}
if (keyBackThrust.isDown) {
noCursorDown = false;
downVec = this.physics.velocityFromAngle(ship.angle - 180, 10);
}
if (keyFwdThrust.isDown) {
noCursorDown = false;
upVec = this.physics.velocityFromAngle(ship.angle, 200);
}
var addVec = new Phaser.Math.Vector2()
.add(downVec)
.add(upVec)
.add(leftVec)
.add(rightVec);
if (noCursorDown) {
ship.setAcceleration(0);
} else {
ship.body.acceleration = addVec;
}
var planetBodyPos = new Phaser.Math.Vector2(planet.body.x + planetRadius, planet.body.y + planetRadius);
var moonBodyPos = new Phaser.Math.Vector2(moon.body.x + moonRadius, moon.body.y + moonRadius);
var shipAcc = new Phaser.Math.Vector2();
var shipPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, shipBodyPos.x, shipBodyPos.y);
var shipPlanetDistanceSquared = Math.pow(shipPlanetDistance, 2);
shipPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/shipPlanetDistanceSquared, (G*planetMass)/shipPlanetDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
shipPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - shipBodyPos.x, planetBodyPos.y - shipBodyPos.y).normalize();
shipAcc.add(shipPlanetNormalized.clone().multiply(shipPlanetGravity));
// add atmospheric drag, but not with this drag since it decelerates just to 0, instead of just slowing down things
var shipMoonDistance = Phaser.Math.Distance.Between(moonBodyPos.x, moonBodyPos.y, shipBodyPos.x, shipBodyPos.y);
var shipMoonDistanceSquared = Math.pow(shipMoonDistance, 2);
shipMoonGravity = new Phaser.Math.Vector2((G*moonMass)/shipMoonDistanceSquared, (G*moonMass)/shipMoonDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
shipMoonNormalized = new Phaser.Math.Vector2(moonBodyPos.x - shipBodyPos.x, moonBodyPos.y - shipBodyPos.y).normalize();
shipAcc.add(shipMoonNormalized.clone().multiply(shipMoonGravity));
ship.body.gravity = shipAcc;
var moonPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, moonBodyPos.x, moonBodyPos.y);
var moonPlanetDistanceSquared = Math.pow(moonPlanetDistance, 2);
moonPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/moonPlanetDistanceSquared, (G*planetMass)/moonPlanetDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
moonPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - moonBodyPos.x, planetBodyPos.y - moonBodyPos.y).normalize();
moonAcc = moonPlanetNormalized.clone().multiply(moonPlanetGravity);
moon.body.gravity = moonAcc;
graphics.clear();
graphics.lineStyle(2, 0x0000ff, 1);
graphics.lineBetween(shipBodyPos.x, shipBodyPos.y, shipBodyPos.x + shipPlanetNormalized.x * 50, shipBodyPos.y + shipPlanetNormalized.y * 50);
graphics.lineStyle(2, 0xff0000, 1);
graphics.lineBetween(shipBodyPos.x, shipBodyPos.y, shipBodyPos.x + shipMoonNormalized.x * 50, shipBodyPos.y + shipMoonNormalized.y * 50);
var shipTrajectory = estimateTrajectory(shipBodyPos.clone(), ship.body.velocity.clone(), planetBodyPos.clone(), moonBodyPos.clone(), moon.body.velocity.clone());
var currentPos = shipBodyPos;
for (var i = 0; i < shipTrajectory.length; i++) {
var nextPos = shipTrajectory[i];
graphics.lineStyle(2, 0xffff00, 1);
graphics.lineBetween(currentPos.x, currentPos.y, nextPos.x, nextPos.y);
currentPos = nextPos;
}
text.setText([
"G: " + G,
//"traj: " + shipTrajectory[1].x + ":" + shipTrajectory[1].y + "(" + shipTrajectory.length + ")",
//"ship: " + shipBodyPos.x + ":" + shipBodyPos.y,
//"pos: " + planet.body.offset.x + " -- " + planet.y,
"shipAcc: " + shipAcc.x + " : " + shipAcc.y,
"acc: " + ship.body.acceleration.x + " : " + ship.body.acceleration.y,
"vel: " + ship.body.speed + "(" + ship.body.velocity.x + ":" + ship.body.velocity.y + ")",
//"initVel: " + initialSpeed,
//"initVec: " + initialVector.x + ":" + initialVector.y,
"shipPlanetDistance: " + shipPlanetDistance,
"moonPlanetDistance: " + moonPlanetDistance
//"planetMass: " + Math.sqrt(shipAcc.x * shipAcc.x + shipAcc.y * shipAcc.y)*distanceSquared/G,
]);
}
function estimateTrajectory(shipBodyPos, shipVelocity, planetBodyPos, moonBodyPos2, moonVelocity) {
/*currentPos = startingPosition
currentVel = startingVelcoity
resultTrajectory.append(currentPos)
for N times{
currentForce = gatherForces()
currentAccel = currentForce / mass
deltaT = fixedTimeStep
nextPos = currentPos + currentVel * deltaT + currentAccel * deltaT * deltaT * 0.5
nextVel = currentVel + currentAccel * deltaT
resultTrajectory.append(nextPos)
currentPos = nextPos
currentVel = nextVel
}*/
var steps = 10;
var deltaT = 0.2;
var shipTrajectory = [shipBodyPos.clone()];
var currentBodyShipPos = shipBodyPos.clone();
var currentShipVel = shipVelocity.clone();
var moonBodyPos = moonBodyPos2.clone();
var currentMoonVel = moonVelocity.clone();
for (var i = 0; i < steps; i++) {
// gather forces accs
var currentShipAcc = new Phaser.Math.Vector2();
var shipPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, currentBodyShipPos.x, currentBodyShipPos.y);
var shipPlanetDistanceSquared = Math.pow(shipPlanetDistance, 2);
var shipPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/shipPlanetDistanceSquared, (G*planetMass)/shipPlanetDistanceSquared);
var shipPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - currentBodyShipPos.x, planetBodyPos.y - currentBodyShipPos.y).normalize();
currentShipAcc.add(shipPlanetNormalized.clone().multiply(shipPlanetGravity));
var shipMoonDistance = Phaser.Math.Distance.Between(moonBodyPos.x, moonBodyPos.y, currentBodyShipPos.x, currentBodyShipPos.y);
var shipMoonDistanceSquared = Math.pow(shipMoonDistance, 2);
var shipMoonGravity = new Phaser.Math.Vector2((G*moonMass)/shipMoonDistanceSquared, (G*moonMass)/shipMoonDistanceSquared);
var shipMoonNormalized = new Phaser.Math.Vector2(moonBodyPos.x - currentBodyShipPos.x, moonBodyPos.y - currentBodyShipPos.y).normalize();
currentShipAcc.add(shipMoonNormalized.clone().multiply(shipMoonGravity));
var moonPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, moonBodyPos.x, moonBodyPos.y);
var moonPlanetDistanceSquared = Math.pow(moonPlanetDistance, 2);
moonPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/moonPlanetDistanceSquared, (G*planetMass)/moonPlanetDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
moonPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - moonBodyPos.x, planetBodyPos.y - moonBodyPos.y).normalize();
var currentMoonAcc = moonPlanetNormalized.clone().multiply(moonPlanetGravity);
var nextMoonBodyPos = new Phaser.Math.Vector2(
moonBodyPos.x + currentMoonVel.x * deltaT + currentMoonAcc.x * deltaT * deltaT * 0.5,
moonBodyPos.y + currentMoonVel.y * deltaT + currentMoonAcc.y * deltaT * deltaT * 0.5,
);
var nextMoonVel = new Phaser.Math.Vector2(
currentMoonVel.x + currentMoonAcc.x * deltaT,
currentMoonVel.y + currentMoonAcc.y * deltaT
);
var nextBodyShipPos = new Phaser.Math.Vector2(
currentBodyShipPos.x + currentShipVel.x * deltaT + currentShipAcc.x * deltaT * deltaT * 0.5,
currentBodyShipPos.y + currentShipVel.y * deltaT + currentShipAcc.y * deltaT * deltaT * 0.5
);
var nextShipVel = new Phaser.Math.Vector2(
currentShipVel.x + currentShipAcc.x * deltaT,
currentShipVel.y + currentShipAcc.y * deltaT
)
shipTrajectory.push(nextBodyShipPos.clone());
currentBodyShipPos = nextBodyShipPos.clone();
currentShipVel = nextShipVel.clone();
moonBodyPos = nextMoonBodyPos.clone();
currentMoonVel = nextMoonVel.clone();
}
return shipTrajectory;
}
// based on this example:
// * http://jsfiddle.net/gJ4kA/
// further reads:
// * https://gamedev.stackexchange.com/questions/71233/planet-gravity
// * https://gamedev.stackexchange.com/questions/21063/2d-planet-gravity
// * http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/
// calc: https://www.ajdesigner.com/phpgravity/gravity_acceleration_equation.php#ajscroll
// todo: how to scale -> m/s² conversion to px/s² etc...
var config = {
type: Phaser.AUTO,
parent: 'planet-gravity-example',
width: 1024,
height: 768,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x: 0 },
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.atlas('space', 'assets/tests/space/space.png', 'assets/tests/space/space.json');
this.load.image('target', 'assets/demoscene/ball.png');
}
var planet;
var moon;
var ship;
var keyBackThrust;
var keyFwdThrust;
var keyLeft;
var keyRight;
var reticle;
//var rt;
//var trail;
var G = 0.5;//6.67e-11;
var planetMass = 500000000;
var moonMass = planetMass/20;
var planetRadius = 2500;
var moonRadius = 250;
var shipRadius = 10;
var graphics;
//var initialSpeed = 0;
//var initialVector;
function create() {
graphics = this.add.graphics();
planet = this.physics.add.sprite(400, 300, 'space', 'blue-planet').setOrigin(0.5, 0.5).setDisplaySize(planetRadius*2,planetRadius*2);
moon = this.physics.add.sprite(400, 15600, 'space', 'moon1').setOrigin(0.5, 0.5).setDisplaySize(moonRadius*2,moonRadius*2);
ship = this.physics.add.sprite(400, -2500, 'space', 'ship').setDepth(2).setOrigin(0.5, 0.5).setDisplaySize(20,20);
//rt = this.add.renderTexture(-20000, -20000, 40000, 40000);
//trail = this.add.image(0, 0, 'space', 'ship').setOrigin(0.5,0.5).setDisplaySize(10,10).setVisible(false);
ship.body.allowGravity = true;
moon.body.allowGravity = true;
var shipBodyPos = new Phaser.Math.Vector2(ship.x, ship.y);
var planetBodyPos = new Phaser.Math.Vector2(planet.x, planet.y);
var moonBodyPos = new Phaser.Math.Vector2(moon.x, moon.y);
// setup ship initial velocity
var shipPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, shipBodyPos.x, shipBodyPos.y);
// perpendicular 2d vector to gravitational vector (https://gamedev.stackexchange.com/a/146492)
var initialShipVector = new Phaser.Math.Vector2(-(planetBodyPos.y - shipBodyPos.y), planetBodyPos.x - shipBodyPos.x).normalize();
var initialShipSpeed = Math.sqrt(G*planetMass/shipPlanetDistance);
ship.body.velocity.x = initialShipVector.x * initialShipSpeed;
ship.body.velocity.y = initialShipVector.y * initialShipSpeed;
// setup moon initial velocity
var moonPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, moonBodyPos.x, moonBodyPos.y);
// perpendicular 2d vector to gravitational vector (https://gamedev.stackexchange.com/a/146492)
var initialMoonVector = new Phaser.Math.Vector2(-(planetBodyPos.y - moonBodyPos.y), planetBodyPos.x - moonBodyPos.x).normalize();
var initialMoonSpeed = Math.sqrt(G*planetMass/moonPlanetDistance);
moon.body.velocity.x = initialMoonVector.x * initialMoonSpeed;
moon.body.velocity.y = initialMoonVector.y * initialMoonSpeed;
text = this.add.text(32, 32).setScrollFactor(0).setFontSize(16).setColor('#ffffff');
this.cameras.main.startFollow(ship);
this.cameras.main.zoom = 0.75;
keyBackThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
keyFwdThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
reticle = this.physics.add.sprite(ship.x, ship.y + 50, 'target');
reticle.setOrigin(0.5, 0.5).setDisplaySize(5, 5);
// Pointer lock will only work after mousedown
game.canvas.addEventListener('mousedown', function () {
game.input.mouse.requestPointerLock();
});
this.input.on('pointermove', function (pointer) {
if (this.input.mouse.locked)
{
reticle.x += pointer.movementX;
reticle.y += pointer.movementY;
}
}, this);
}
function update() {
var shipBodyPos = new Phaser.Math.Vector2(ship.body.x + shipRadius, ship.body.y + shipRadius);
ship.rotation = Phaser.Math.Angle.Between(ship.x, ship.y, reticle.x, reticle.y);
//restrainReticle()
reticle.body.velocity.x = ship.body.velocity.x;
reticle.body.velocity.y = ship.body.velocity.y;
/*var reticleBodyPos = new Phaser.Math.Vector2(reticle.body.x + reticle.body.width/2, reticle.body.y + reticle.body.height/2);
shipReticleNormalized = new Phaser.Math.Vector2(reticleBodyPos.x - shipBodyPos.x, reticleBodyPos.y - shipBodyPos.y).normalize();
if (shipBodyPos.x + shipReticleNormalized.x * 100 > reticleBodyPos.x) {
reticle.body.x = shipBodyPos.x + shipReticleNormalized.x * 100;
} else if (shipBodyPos.x + shipReticleNormalized.x * 100 < reticleBodyPos.x) {
reticle.body.x = shipBodyPos.x + shipReticleNormalized.x * 100;
}
if (shipBodyPos.y + shipReticleNormalized.y * 100 > reticleBodyPos.y) {
reticle.body.y = shipBodyPos.y + shipReticleNormalized.y * 100;
} else if (shipBodyPos.y + shipReticleNormalized.y * 100 < reticleBodyPos.y) {
reticle.body.y = shipBodyPos.y + shipReticleNormalized.y * 100;
}*/
var noCursorDown = true;
var downVec = Phaser.Math.Vector2.ZERO;
var upVec = Phaser.Math.Vector2.ZERO;
var leftVec = Phaser.Math.Vector2.ZERO;
var rightVec = Phaser.Math.Vector2.ZERO;
if (keyLeft.isDown) {
noCursorDown = false;
leftVec = this.physics.velocityFromAngle(ship.angle - 90, 10);
}
if (keyRight.isDown) {
noCursorDown = false;
rightVec = this.physics.velocityFromAngle(ship.angle + 90, 10);
}
if (keyBackThrust.isDown) {
noCursorDown = false;
downVec = this.physics.velocityFromAngle(ship.angle - 180, 10);
}
if (keyFwdThrust.isDown) {
noCursorDown = false;
upVec = this.physics.velocityFromAngle(ship.angle, 200);
}
var addVec = new Phaser.Math.Vector2()
.add(downVec)
.add(upVec)
.add(leftVec)
.add(rightVec);
if (noCursorDown) {
ship.setAcceleration(0);
} else {
ship.body.acceleration = addVec;
}
var planetBodyPos = new Phaser.Math.Vector2(planet.body.x + planetRadius, planet.body.y + planetRadius);
var moonBodyPos = new Phaser.Math.Vector2(moon.body.x + moonRadius, moon.body.y + moonRadius);
var shipAcc = new Phaser.Math.Vector2();
var shipPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, shipBodyPos.x, shipBodyPos.y);
var shipPlanetDistanceSquared = Math.pow(shipPlanetDistance, 2);
shipPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/shipPlanetDistanceSquared, (G*planetMass)/shipPlanetDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
shipPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - shipBodyPos.x, planetBodyPos.y - shipBodyPos.y).normalize();
shipAcc.add(shipPlanetNormalized.clone().multiply(shipPlanetGravity));
// add atmospheric drag, but not with this drag since it decelerates just to 0, instead of just slowing down things
var shipMoonDistance = Phaser.Math.Distance.Between(moonBodyPos.x, moonBodyPos.y, shipBodyPos.x, shipBodyPos.y);
var shipMoonDistanceSquared = Math.pow(shipMoonDistance, 2);
shipMoonGravity = new Phaser.Math.Vector2((G*moonMass)/shipMoonDistanceSquared, (G*moonMass)/shipMoonDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
shipMoonNormalized = new Phaser.Math.Vector2(moonBodyPos.x - shipBodyPos.x, moonBodyPos.y - shipBodyPos.y).normalize();
shipAcc.add(shipMoonNormalized.clone().multiply(shipMoonGravity));
ship.body.gravity = shipAcc;
var moonPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, moonBodyPos.x, moonBodyPos.y);
var moonPlanetDistanceSquared = Math.pow(moonPlanetDistance, 2);
moonPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/moonPlanetDistanceSquared, (G*planetMass)/moonPlanetDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
moonPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - moonBodyPos.x, planetBodyPos.y - moonBodyPos.y).normalize();
moonAcc = moonPlanetNormalized.clone().multiply(moonPlanetGravity);
moon.body.gravity = moonAcc;
graphics.clear();
graphics.lineStyle(2, 0x0000ff, 1);
graphics.lineBetween(shipBodyPos.x, shipBodyPos.y, shipBodyPos.x + shipPlanetNormalized.x * 50, shipBodyPos.y + shipPlanetNormalized.y * 50);
graphics.lineStyle(2, 0xff0000, 1);
graphics.lineBetween(shipBodyPos.x, shipBodyPos.y, shipBodyPos.x + shipMoonNormalized.x * 50, shipBodyPos.y + shipMoonNormalized.y * 50);
var shipTrajectory = estimateTrajectory(shipBodyPos.clone(), ship.body.velocity.clone(), planetBodyPos.clone(), moonBodyPos.clone(), moon.body.velocity.clone());
var currentPos = shipBodyPos;
for (var i = 0; i < shipTrajectory.length; i++) {
var nextPos = shipTrajectory[i];
graphics.lineStyle(2, 0xffff00, 1);
graphics.lineBetween(currentPos.x, currentPos.y, nextPos.x, nextPos.y);
currentPos = nextPos;
}
text.setText([
"G: " + G,
//"traj: " + shipTrajectory[1].x + ":" + shipTrajectory[1].y + "(" + shipTrajectory.length + ")",
//"ship: " + shipBodyPos.x + ":" + shipBodyPos.y,
//"pos: " + planet.body.offset.x + " -- " + planet.y,
"shipAcc: " + shipAcc.x + " : " + shipAcc.y,
"acc: " + ship.body.acceleration.x + " : " + ship.body.acceleration.y,
"vel: " + ship.body.speed + "(" + ship.body.velocity.x + ":" + ship.body.velocity.y + ")",
//"initVel: " + initialSpeed,
//"initVec: " + initialVector.x + ":" + initialVector.y,
"shipPlanetDistance: " + shipPlanetDistance,
"moonPlanetDistance: " + moonPlanetDistance
//"planetMass: " + Math.sqrt(shipAcc.x * shipAcc.x + shipAcc.y * shipAcc.y)*distanceSquared/G,
]);
}
function estimateTrajectory(shipBodyPos, shipVelocity, planetBodyPos, moonBodyPos2, moonVelocity) {
/*currentPos = startingPosition
currentVel = startingVelcoity
resultTrajectory.append(currentPos)
for N times{
currentForce = gatherForces()
currentAccel = currentForce / mass
deltaT = fixedTimeStep
nextPos = currentPos + currentVel * deltaT + currentAccel * deltaT * deltaT * 0.5
nextVel = currentVel + currentAccel * deltaT
resultTrajectory.append(nextPos)
currentPos = nextPos
currentVel = nextVel
}*/
var steps = 50;
var deltaT = 0.1;
var shipTrajectory = [shipBodyPos.clone()];
var currentBodyShipPos = shipBodyPos.clone();
var currentShipVel = shipVelocity.clone();
var moonBodyPos = moonBodyPos2.clone();
var currentMoonVel = moonVelocity.clone();
for (var i = 0; i < steps; i++) {
// gather forces accs
var currentShipAcc = new Phaser.Math.Vector2();
var shipPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, currentBodyShipPos.x, currentBodyShipPos.y);
var shipPlanetDistanceSquared = Math.pow(shipPlanetDistance, 2);
var shipPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/shipPlanetDistanceSquared, (G*planetMass)/shipPlanetDistanceSquared);
var shipPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - currentBodyShipPos.x, planetBodyPos.y - currentBodyShipPos.y).normalize();
currentShipAcc.add(shipPlanetNormalized.clone().multiply(shipPlanetGravity));
var shipMoonDistance = Phaser.Math.Distance.Between(moonBodyPos.x, moonBodyPos.y, currentBodyShipPos.x, currentBodyShipPos.y);
var shipMoonDistanceSquared = Math.pow(shipMoonDistance, 2);
var shipMoonGravity = new Phaser.Math.Vector2((G*moonMass)/shipMoonDistanceSquared, (G*moonMass)/shipMoonDistanceSquared);
var shipMoonNormalized = new Phaser.Math.Vector2(moonBodyPos.x - currentBodyShipPos.x, moonBodyPos.y - currentBodyShipPos.y).normalize();
currentShipAcc.add(shipMoonNormalized.clone().multiply(shipMoonGravity));
var moonPlanetDistance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, moonBodyPos.x, moonBodyPos.y);
var moonPlanetDistanceSquared = Math.pow(moonPlanetDistance, 2);
moonPlanetGravity = new Phaser.Math.Vector2((G*planetMass)/moonPlanetDistanceSquared, (G*planetMass)/moonPlanetDistanceSquared);
// Normalize and multiply by actual strength of gravity desired
moonPlanetNormalized = new Phaser.Math.Vector2(planetBodyPos.x - moonBodyPos.x, planetBodyPos.y - moonBodyPos.y).normalize();
var currentMoonAcc = moonPlanetNormalized.clone().multiply(moonPlanetGravity);
var nextMoonBodyPos = new Phaser.Math.Vector2(
moonBodyPos.x + currentMoonVel.x * deltaT + currentMoonAcc.x * deltaT * deltaT * 0.5,
moonBodyPos.y + currentMoonVel.y * deltaT + currentMoonAcc.y * deltaT * deltaT * 0.5,
);
var nextMoonVel = new Phaser.Math.Vector2(
currentMoonVel.x + currentMoonAcc.x * deltaT,
currentMoonVel.y + currentMoonAcc.y * deltaT
);
var nextBodyShipPos = new Phaser.Math.Vector2(
currentBodyShipPos.x + currentShipVel.x * deltaT + currentShipAcc.x * deltaT * deltaT * 0.5,
currentBodyShipPos.y + currentShipVel.y * deltaT + currentShipAcc.y * deltaT * deltaT * 0.5
);
var nextShipVel = new Phaser.Math.Vector2(
currentShipVel.x + currentShipAcc.x * deltaT,
currentShipVel.y + currentShipAcc.y * deltaT
)
shipTrajectory.push(nextBodyShipPos.clone());
currentBodyShipPos = nextBodyShipPos.clone();
currentShipVel = nextShipVel.clone();
moonBodyPos = nextMoonBodyPos.clone();
currentMoonVel = nextMoonVel.clone();
}
return shipTrajectory;
}
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#1b1464',
parent: 'phaser-example',
physics: {
default: 'matter',
matter: {
debug: true,
gravity: {
x: 0,
y: 0.03
}
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var ship;
var target;
var cursors;
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('ship', 'assets/sprites/x2kship.png');
this.load.image('target', 'assets/demoscene/ball.png');
}
function create ()
{
ship = this.matter.add.image(400, 300, 'ship').setDisplaySize(70, 30);
ship.setRotation(Math.PI*1.5);
let shipBottomCenter = ship.getTopRight();
//target = this.matter.add.image(shipBottomCenter.x, shipBottomCenter.y, 'target').setDisplaySize(10,10);
ship.setFrictionAir(0.001);
ship.setMass(70);
//ship.setFixedRotation();
this.matter.world.setBounds(0, 0, 800, 600);
//this.cameras.main.startFollow(ship);
cursors = this.input.keyboard.createCursorKeys();
}
function update ()
{
let rotation = ship.body.angle;
let turnLeftRot = rotation - Math.PI / 2;
let turnRightRot = rotation + Math.PI / 2;
let turnVal = 0.002;
let turnLeftForce = new Phaser.Math.Vector2(turnVal * Math.cos(turnLeftRot), turnVal * Math.sin(turnLeftRot));
let turnRightForce = new Phaser.Math.Vector2(turnVal * Math.cos(turnRightRot), turnVal * Math.sin(turnRightRot));
if (cursors.left.isDown) {
let bottomRight = ship.getBottomRight();
ship.applyForceFrom(bottomRight, turnLeftForce);
let topLeft = ship.getTopLeft();
ship.applyForceFrom(topLeft, turnRightForce);
}
if (cursors.right.isDown) {
let topRight = ship.getTopRight();
ship.applyForceFrom(topRight, turnRightForce);
let bottomLeft = ship.getBottomLeft();
ship.applyForceFrom(bottomLeft, turnLeftForce);
}
if (cursors.up.isDown) {
let thrustVal = 0.005;
let thrustForce = new Phaser.Math.Vector2(thrustVal * Math.cos(rotation), thrustVal * Math.sin(rotation));
//ship.thrust(0.08);
let rear = ship.getLeftCenter();
//let top = ship.getTopCenter();
//ship.applyForceFrom(ship.body.position, thrustForce);
ship.applyForceFrom(rear, thrustForce);
//ship.applyForceFrom(top, thrustForce);
}
}
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#1b1464',
parent: 'phaser-example',
physics: {
default: 'matter',
matter: {
debug: true,
gravity: {
x: 0,
y: 0
}
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var ship;
var target;
var cursors;
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('ship', 'assets/sprites/x2kship.png');
this.load.image('target', 'assets/demoscene/ball.png');
}
function create ()
{
ship = this.matter.add.image(400, 300, 'ship').setDisplaySize(30,30);
let shipBottomCenter = ship.getTopRight();
//target = this.matter.add.image(shipBottomCenter.x, shipBottomCenter.y, 'target').setDisplaySize(10,10);
ship.setFrictionAir(0);
ship.setMass(70);
//ship.setFixedRotation();
this.matter.world.setBounds(0, 0, 800, 600);
//this.cameras.main.startFollow(ship);
cursors = this.input.keyboard.createCursorKeys();
}
function update ()
{
let rotation = ship.body.angle;
let turnLeftRot = rotation - Math.PI / 2;
let turnRightRot = rotation + Math.PI / 2;
let turnVal = 0.002;
let turnLeftForce = new Phaser.Math.Vector2(turnVal * Math.cos(turnLeftRot), turnVal * Math.sin(turnLeftRot));
let turnRightForce = new Phaser.Math.Vector2(turnVal * Math.cos(turnRightRot), turnVal * Math.sin(turnRightRot));
if (cursors.left.isDown) {
let bottomRight = ship.getBottomRight();
ship.applyForceFrom(bottomRight, turnLeftForce);
let topLeft = ship.getTopLeft();
ship.applyForceFrom(topLeft, turnRightForce);
}
if (cursors.right.isDown) {
let topRight = ship.getTopRight();
ship.applyForceFrom(topRight, turnRightForce);
let bottomLeft = ship.getBottomLeft();
ship.applyForceFrom(bottomLeft, turnLeftForce);
}
if (cursors.up.isDown) {
let thrustVal = 0.005;
let thrustForce = new Phaser.Math.Vector2(thrustVal * Math.cos(rotation), thrustVal * Math.sin(rotation));
//ship.thrust(0.08);
let rear = ship.getLeftCenter();
//let top = ship.getTopCenter();
//ship.applyForceFrom(ship.body.position, thrustForce);
ship.applyForceFrom(rear, thrustForce);
//ship.applyForceFrom(top, thrustForce);
}
}
// based on this example:
// * http://jsfiddle.net/gJ4kA/
// further reads:
// * https://gamedev.stackexchange.com/questions/71233/planet-gravity
// * https://gamedev.stackexchange.com/questions/21063/2d-planet-gravity
// * http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/
// calc: https://www.ajdesigner.com/phpgravity/gravity_acceleration_equation.php#ajscroll
// todo: how to scale -> m/s² conversion to px/s² etc...
var config = {
type: Phaser.AUTO,
parent: 'planet-gravity-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x: 0 },
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.atlas('space', 'assets/tests/space/space.png', 'assets/tests/space/space.json');
}
var planet;
var ship;
function create() {
ship = this.physics.add.sprite(400, 100, 'space', 'ship').setDepth(2).setOrigin(0.5, 0.5).setDisplaySize(20,20);
planet = this.physics.add.sprite(400, 300, 'space', 'blue-planet').setOrigin(0.5, 0.5).setDisplaySize(200,200);
// Use our own gravity
ship.body.allowGravity = true;
//planet.body.allowGravity = true;
// Set an initial motion
ship.body.velocity.x = 80;
text = this.add.text(32, 32).setScrollFactor(0).setFontSize(16).setColor('#ffffff');
//text.setText("test");
this.cameras.main.startFollow(ship)
}
function update() {
planetMass = 1500000;
invPlanetMass = Math.pow(planetMass, -1);
distance = Phaser.Math.Distance.Between(planet.x, planet.y, ship.x, ship.y);
invDistanceSquared = Math.pow(distance, -2);
// calculate with inverse numbers to prevent division through zero
planetGravity = new Phaser.Math.Vector2(invDistanceSquared/invPlanetMass, invDistanceSquared/invPlanetMass);
//distanceSquared = Math.pow(distance, 2);
//planetGravity2 = new Phaser.Math.Vector2(planetMass/distanceSquared, planetMass/distanceSquared);
// Normalize and multiply by actual strength of gravity desired
shipGravity = new Phaser.Math.Vector2(planet.x - ship.x, planet.y - ship.y).normalize().multiply(planetGravity);
ship.body.gravity = shipGravity;
// add atmospheric drag, but not with this drag since it decelerates just to 0, instead of just slowing down things
/*if (distance < 100) {
ship.body.drag.x = 500;
ship.body.drag.y = 500;
}*/
text.setText(
"shipGravity: " + shipGravity.x + " : " + shipGravity.y
//+ "\npG (inv): " + planetGravity.x + " : " + planetGravity.y
//+ "\npG (nor): " + planetGravity2.x + " : " + planetGravity2.y
+ "\nacc: " + ship.body.acceleration.x + " : " + ship.body.acceleration.y
+ "\nvel: " + ship.body.speed
+ "\ndistance: " + distance);
}
// based on this example:
// * http://jsfiddle.net/gJ4kA/
// further reads:
// * https://gamedev.stackexchange.com/questions/71233/planet-gravity
// * https://gamedev.stackexchange.com/questions/21063/2d-planet-gravity
// * http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/
// calc: https://www.ajdesigner.com/phpgravity/gravity_acceleration_equation.php#ajscroll
// todo: how to scale -> m/s² conversion to px/s² etc...
var config = {
type: Phaser.AUTO,
parent: 'planet-gravity-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x: 0 },
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.atlas('space', 'assets/tests/space/space.png', 'assets/tests/space/space.json');
}
var planet;
var ship;
var keyBackThrust;
var keyFwdThrust;
var keyLeft;
var keyRight;
var reticle;
var rt;
var trail;
function create() {
ship = this.physics.add.sprite(400, -300, 'space', 'ship').setDepth(2).setOrigin(0.5, 0.5).setDisplaySize(20,20);
planet = this.physics.add.sprite(400, 300, 'space', 'blue-planet').setOrigin(0.5, 0.5).setDisplaySize(1000,1000);
rt = this.add.renderTexture(-2000, -2000, 4000, 4000);
trail = this.add.image(0, 0, 'space', 'ship').setOrigin(0.5,0.5).setDisplaySize(10,10).setVisible(false);
// Use our own gravity
ship.body.allowGravity = true;
//planet.body.allowGravity = true;
// Set an initial motion
ship.body.velocity.x = 288.67513459481285;
text = this.add.text(32, 32).setScrollFactor(0).setFontSize(16).setColor('#ffffff');
//text.setText("test");
this.cameras.main.startFollow(ship);
keyBackThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
keyFwdThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
reticle = this.physics.add.sprite(ship.x, ship.y + 50, 'target');
reticle.setOrigin(0.5, 0.5).setDisplaySize(10, 10);
// Pointer lock will only work after mousedown
game.canvas.addEventListener('mousedown', function () {
game.input.mouse.requestPointerLock();
});
this.input.on('pointermove', function (pointer) {
if (this.input.mouse.locked)
{
reticle.x += pointer.movementX;
reticle.y += pointer.movementY;
}
}, this);
}
function update() {
ship.rotation = Phaser.Math.Angle.Between(ship.x, ship.y, reticle.x, reticle.y);
reticle.body.velocity.x = ship.body.velocity.x;
reticle.body.velocity.y = ship.body.velocity.y;
var noCursorDown = true;
var downVec = Phaser.Math.Vector2.ZERO;
var upVec = Phaser.Math.Vector2.ZERO;
var leftVec = Phaser.Math.Vector2.ZERO;
var rightVec = Phaser.Math.Vector2.ZERO;
if (keyLeft.isDown) {
noCursorDown = false;
leftVec = this.physics.velocityFromAngle(ship.angle - 90, 50);
//ship.body.acceleration = leftVec;
}
if (keyRight.isDown) {
noCursorDown = false;
rightVec = this.physics.velocityFromAngle(ship.angle + 90, 50);
//ship.body.acceleration = rightVec;
}
if (keyBackThrust.isDown) {
noCursorDown = false;
downVec = this.physics.velocityFromAngle(ship.angle - 180, 75);
//ship.body.acceleration = downVec;
}
if (keyFwdThrust.isDown) {
noCursorDown = false;
upVec = this.physics.velocityFromAngle(ship.angle, 150);
//ship.body.acceleration = upVec;
}
var addVec = new Phaser.Math.Vector2(
downVec.x + upVec.x + leftVec.x + rightVec.x,
downVec.y + upVec.y + leftVec.y + rightVec.y
);
if (noCursorDown) {
ship.setAcceleration(0);
} else {
ship.body.acceleration = addVec;
}
planetMass = 50000000;
invPlanetMass = Math.pow(planetMass, -1);
distance = Phaser.Math.Distance.Between(planet.x, planet.y, ship.x, ship.y);
distanceSquared = Math.pow(distance, 2);
// calculate with inverse numbers to prevent division through zero
//planetGravity = new Phaser.Math.Vector2(invDistanceSquared/invPlanetMass, invDistanceSquared/invPlanetMass);
//distanceSquared = Math.pow(distance, 2);
planetGravity = new Phaser.Math.Vector2(planetMass/distanceSquared, planetMass/distanceSquared);
// Normalize and multiply by actual strength of gravity desired
normalized = new Phaser.Math.Vector2(planet.x - ship.x, planet.y - ship.y).normalize();
shipAcc = normalized.clone().multiply(planetGravity);
//ship.body.gravity = shipGravity;
// add atmospheric drag, but not with this drag since it decelerates just to 0, instead of just slowing down things
/*if (distance < 100) {
ship.body.drag.x = 500;
ship.body.drag.y = 500;
}*/
var G = 6.67e-11;
//var Me =
var velWanted = Math.sqrt(planetMass/distance);
ship.body.acceleration = shipAcc.clone();
trail.x = ship.x + 2000;
trail.y = ship.y + 2000;
rt.draw(trail);
text.setText([
"G: " + G,
"shipAcc: " + shipAcc.x + " : " + shipAcc.y,
"acc: " + ship.body.acceleration.x + " : " + ship.body.acceleration.y,
"vel: " + ship.body.speed,
"velWanted: " + velWanted,
"distance: " + distance,
"planetMass: " + Math.sqrt(shipAcc.x * shipAcc.x + shipAcc.y * shipAcc.y)*distanceSquared,
]);
}
// based on this example:
// * http://jsfiddle.net/gJ4kA/
// further reads:
// * https://gamedev.stackexchange.com/questions/71233/planet-gravity
// * https://gamedev.stackexchange.com/questions/21063/2d-planet-gravity
// * http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/
// calc: https://www.ajdesigner.com/phpgravity/gravity_acceleration_equation.php#ajscroll
// todo: how to scale -> m/s² conversion to px/s² etc...
var config = {
type: Phaser.AUTO,
parent: 'planet-gravity-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x: 0 },
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.atlas('space', 'assets/tests/space/space.png', 'assets/tests/space/space.json');
}
var planet;
var ship;
var keyBackThrust;
var keyFwdThrust;
var keyLeft;
var keyRight;
var reticle;
var rt;
var trail;
var G = 1;//6.67e-11;
var planetMass = 50000000;
var planetRadius = 500;
var shipRadius = 10;
var initialSpeed = 0;
function create() {
ship = this.physics.add.sprite(400, -300, 'space', 'ship').setDepth(2).setOrigin(0.5, 0.5).setDisplaySize(20,20);
planet = this.physics.add.sprite(400, 300, 'space', 'blue-planet').setOrigin(0.5, 0.5).setDisplaySize(1000,1000);
rt = this.add.renderTexture(-2000, -2000, 4000, 4000);
trail = this.add.image(0, 0, 'space', 'ship').setOrigin(0.5,0.5).setDisplaySize(10,10).setVisible(false);
// Use our own gravity
ship.body.allowGravity = false;
ship.body.allowDrag = false;
//planet.body.allowGravity = true;
// Set an initial motion
var shipBodyPos = new Phaser.Math.Vector2(ship.x, ship.y);
var planetBodyPos = new Phaser.Math.Vector2(planet.x, planet.y);
var distance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, shipBodyPos.x, shipBodyPos.y);
initialSpeed = Math.sqrt(G*planetMass/distance);
ship.body.velocity.x = 288.67;//initialSpeed; //288;//Math.sqrt(G*planetMass/distance);
text = this.add.text(32, 32).setScrollFactor(0).setFontSize(16).setColor('#ffffff');
//text.setText("test");
this.cameras.main.startFollow(ship);
this.cameras.main.zoom = 0.75;
keyBackThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
keyFwdThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
reticle = this.physics.add.sprite(ship.x, ship.y + 50, 'target');
reticle.setOrigin(0.5, 0.5).setDisplaySize(10, 10);
// Pointer lock will only work after mousedown
game.canvas.addEventListener('mousedown', function () {
game.input.mouse.requestPointerLock();
});
this.input.on('pointermove', function (pointer) {
if (this.input.mouse.locked)
{
reticle.x += pointer.movementX;
reticle.y += pointer.movementY;
}
}, this);
}
function update() {
ship.rotation = Phaser.Math.Angle.Between(ship.x, ship.y, reticle.x, reticle.y);
reticle.body.velocity.x = ship.body.velocity.x;
reticle.body.velocity.y = ship.body.velocity.y;
var noCursorDown = true;
var downVec = Phaser.Math.Vector2.ZERO;
var upVec = Phaser.Math.Vector2.ZERO;
var leftVec = Phaser.Math.Vector2.ZERO;
var rightVec = Phaser.Math.Vector2.ZERO;
var shipBodyPos = new Phaser.Math.Vector2(ship.body.x + shipRadius, ship.body.y + shipRadius);
var planetBodyPos = new Phaser.Math.Vector2(planet.body.x + planetRadius, planet.body.y + planetRadius);
//reticle.x = planetBodyPos.x;
//reticle.y = planetBodyPos.y;
if (keyLeft.isDown) {
noCursorDown = false;
leftVec = this.physics.velocityFromAngle(ship.angle - 90, 10);
//ship.body.acceleration = leftVec;
}
if (keyRight.isDown) {
noCursorDown = false;
rightVec = this.physics.velocityFromAngle(ship.angle + 90, 10);
//ship.body.acceleration = rightVec;
}
if (keyBackThrust.isDown) {
noCursorDown = false;
downVec = this.physics.velocityFromAngle(ship.angle - 180, 10);
//ship.body.acceleration = downVec;
}
if (keyFwdThrust.isDown) {
noCursorDown = false;
upVec = this.physics.velocityFromAngle(ship.angle, 50);
//ship.body.acceleration = upVec;
}
var addVec = new Phaser.Math.Vector2(
downVec.x + upVec.x + leftVec.x + rightVec.x,
downVec.y + upVec.y + leftVec.y + rightVec.y
);
if (noCursorDown) {
ship.setAcceleration(0);
} else {
ship.body.acceleration = addVec;
}
var invPlanetMass = Math.pow(planetMass, -1);
var distance = Phaser.Math.Distance.Between(planetBodyPos.x, planetBodyPos.y, shipBodyPos.x, shipBodyPos.y);
var distanceSquared = Math.pow(distance, 2);
// calculate with inverse numbers to prevent division through zero
//planetGravity = new Phaser.Math.Vector2(invDistanceSquared/invPlanetMass, invDistanceSquared/invPlanetMass);
//distanceSquared = Math.pow(distance, 2);
planetGravity = new Phaser.Math.Vector2((G*planetMass)/distanceSquared, (G*planetMass)/distanceSquared);
// Normalize and multiply by actual strength of gravity desired
normalized = new Phaser.Math.Vector2(planetBodyPos.x - shipBodyPos.x, planetBodyPos.y - shipBodyPos.y).normalize();
shipAcc = normalized.clone().multiply(planetGravity);
//ship.body.gravity = shipGravity;
// add atmospheric drag, but not with this drag since it decelerates just to 0, instead of just slowing down things
/*if (distance < 100) {
ship.body.drag.x = 500;
ship.body.drag.y = 500;
}*/
//var Me =
//var velWanted = Math.sqrt(G*planetMass/distance);
ship.body.acceleration.add(shipAcc);
//var velCalc = Math.sqrt(Math.pow(shipAcc.x, 2) + Math.pow(shipAcc.y, 2)) * (16/1000);
//velCalcX = normalized.y * velWanted;
//velCalcY = normalized.x * velWanted * -1;
//velCalc = Math.sqrt(Math.pow(velCalcX, 2) + Math.pow(velCalcY, 2));
//ship.body.velocity.x = velCalcX;
//ship.body.velocity.y = velCalcY;
// v = a/t (m/s)
trail.x = ship.x + 2000;
trail.y = ship.y + 2000;
rt.draw(trail);
text.setText([
"G: " + G,
//"pos: " + planet.body.offset.x + " -- " + planet.y,
"shipAcc: " + shipAcc.x + " : " + shipAcc.y,
"acc: " + ship.body.acceleration.x + " : " + ship.body.acceleration.y,
"vel: " + ship.body.speed + "(" + ship.body.velocity.x + ":" + ship.body.velocity.y + ")",
"initVel: " + initialSpeed,
"distance: " + distance,
"planetMass: " + Math.sqrt(shipAcc.x * shipAcc.x + shipAcc.y * shipAcc.y)*distanceSquared/G,
]);
}
// based on this example:
// * http://jsfiddle.net/gJ4kA/
// further reads:
// * https://gamedev.stackexchange.com/questions/71233/planet-gravity
// * https://gamedev.stackexchange.com/questions/21063/2d-planet-gravity
// * http://codeflow.org/entries/2010/aug/28/integration-by-example-euler-vs-verlet-vs-runge-kutta/
// calc: https://www.ajdesigner.com/phpgravity/gravity_acceleration_equation.php#ajscroll
// todo: how to scale -> m/s² conversion to px/s² etc...
var config = {
type: Phaser.AUTO,
parent: 'planet-gravity-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0, x: 0 },
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.atlas('space', 'assets/tests/space/space.png', 'assets/tests/space/space.json');
}
var planet;
var ship;
var keyBackThrust;
var keyFwdThrust;
var keyLeft;
var keyRight;
var reticle;
function create() {
ship = this.physics.add.sprite(400, -300, 'space', 'ship').setDepth(2).setOrigin(0.5, 0.5).setDisplaySize(20,20);
planet = this.physics.add.sprite(400, 300, 'space', 'blue-planet').setOrigin(0.5, 0.5).setDisplaySize(1000,1000);
// Use our own gravity
ship.body.allowGravity = true;
//planet.body.allowGravity = true;
// Set an initial motion
ship.body.velocity.x = 275;
text = this.add.text(32, 32).setScrollFactor(0).setFontSize(16).setColor('#ffffff');
//text.setText("test");
this.cameras.main.startFollow(ship);
keyBackThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
keyFwdThrust = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
reticle = this.physics.add.sprite(ship.x, ship.y + 50, 'target');
reticle.setOrigin(0.5, 0.5).setDisplaySize(10, 10);
// Pointer lock will only work after mousedown
game.canvas.addEventListener('mousedown', function () {
game.input.mouse.requestPointerLock();
});
this.input.on('pointermove', function (pointer) {
if (this.input.mouse.locked)
{
reticle.x += pointer.movementX;
reticle.y += pointer.movementY;
}
}, this);
}
function update() {
ship.rotation = Phaser.Math.Angle.Between(ship.x, ship.y, reticle.x, reticle.y);
reticle.body.velocity.x = ship.body.velocity.x;
reticle.body.velocity.y = ship.body.velocity.y;
var noCursorDown = true;
var downVec = Phaser.Math.Vector2.ZERO;
var upVec = Phaser.Math.Vector2.ZERO;
var leftVec = Phaser.Math.Vector2.ZERO;
var rightVec = Phaser.Math.Vector2.ZERO;
if (keyLeft.isDown) {
noCursorDown = false;
leftVec = this.physics.velocityFromAngle(ship.angle - 90, 50);
//ship.body.acceleration = leftVec;
}
if (keyRight.isDown) {
noCursorDown = false;
rightVec = this.physics.velocityFromAngle(ship.angle + 90, 50);
//ship.body.acceleration = rightVec;
}
if (keyBackThrust.isDown) {
noCursorDown = false;
downVec = this.physics.velocityFromAngle(ship.angle - 180, 75);
//ship.body.acceleration = downVec;
}
if (keyFwdThrust.isDown) {
noCursorDown = false;
upVec = this.physics.velocityFromAngle(ship.angle, 150);
//ship.body.acceleration = upVec;
}
var addVec = new Phaser.Math.Vector2(
downVec.x + upVec.x + leftVec.x + rightVec.x,
downVec.y + upVec.y + leftVec.y + rightVec.y
);
if (noCursorDown) {
ship.setAcceleration(0);
} else {
ship.body.acceleration = addVec;
}
planetMass = 50000000;
invPlanetMass = Math.pow(planetMass, -1);
distance = Phaser.Math.Distance.Between(planet.x, planet.y, ship.x, ship.y);
invDistanceSquared = Math.pow(distance, -2);
// calculate with inverse numbers to prevent division through zero
planetGravity = new Phaser.Math.Vector2(invDistanceSquared/invPlanetMass, invDistanceSquared/invPlanetMass);
//distanceSquared = Math.pow(distance, 2);
//planetGravity2 = new Phaser.Math.Vector2(planetMass/distanceSquared, planetMass/distanceSquared);
// Normalize and multiply by actual strength of gravity desired
shipGravity = new Phaser.Math.Vector2(planet.x - ship.x, planet.y - ship.y).normalize().multiply(planetGravity);
ship.body.gravity = shipGravity;
// add atmospheric drag, but not with this drag since it decelerates just to 0, instead of just slowing down things
/*if (distance < 100) {
ship.body.drag.x = 500;
ship.body.drag.y = 500;
}*/
text.setText(
"shipGravity: " + shipGravity.x + " : " + shipGravity.y
//+ "\npG (inv): " + planetGravity.x + " : " + planetGravity.y
//+ "\npG (nor): " + planetGravity2.x + " : " + planetGravity2.y
+ "\nacc: " + ship.body.acceleration.x + " : " + ship.body.acceleration.y
+ "\nvel: " + ship.body.speed
+ "\ndistance: " + distance);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment