Demo
Mult: Refresh: ms
JavaScript
This code uses the same 3 classes as the previous demo. To keep the math simpler, I assume that the spaceship starts out 1 unit from the center of the solar system and has a speed of 1. Unlike the previous demo, the acceleration follows the inverse square law to improve realism.
Ship
The ship is still a position, velocity, and acceleration, but now it also has a direction and a concept of a thruster.
1 var Ship = function() { 2 this.pos = new Vector(); 3 this.vel = new Vector(); 4 this.acc = new Vector(); 5 this.color = "255,255,255"; 6 this.dir = 0; 7 this.max_dir = 12; 8 this.thrusterOn = false; 9 this.thrusterForce = 0.1; 10 this.size = 0.01; 11 } 12 13 Ship.prototype.turnRight = function() { 14 this.dir = (this.dir + 1) % this.max_dir; 15 } 16 17 Ship.prototype.turnLeft = function() { 18 this.dir = (this.dir + this.max_dir - 1) % this.max_dir; 19 } 20 21 Ship.prototype.angle = function() { 22 return this.dir * 2 * Math.PI / this.max_dir 23 } 24 25 Ship.prototype.adjust = function(time) { 26 if (this.thrusterOn) { 27 this.acc.x += this.thrusterForce * Math.sin(this.angle()); 28 this.acc.y -= this.thrusterForce * Math.cos(this.angle()); 29 } 30 this.vel.adjust(this.acc, time); 31 this.pos.adjust(this.vel, time); 32 } 33 34 Ship.prototype.draw = function(ctx) { 35 ctx.save(); 36 ctx.translate(this.pos.x, this.pos.y); 37 ctx.rotate(this.angle()); 38 ctx.strokeStyle = "rgb(" + this.color + ")"; 39 ctx.scale(this.size, this.size); 40 ctx.beginPath(); 41 ctx.moveTo(0, -10); 42 ctx.lineTo(5, 10); 43 ctx.lineTo(-5, 10); 44 ctx.lineTo(0, -10); 45 ctx.stroke(); 46 47 if (this.thrusterOn) { 48 ctx.fillStyle = "rgb(" + this.color + ")"; 49 circle(ctx, 0, 11, 1); 50 circle(ctx, -2, 13, 1); 51 circle(ctx, 2, 13, 1); 52 circle(ctx, -4, 15, 1); 53 circle(ctx, 4, 15, 1); 54 circle(ctx, -1, 15, 1); 55 circle(ctx, 1, 15, 1); 56 } 57 58 ctx.restore(); 59 }Simulation
The simulation has the same responsibilities as before, but also scales the display so that a radius of 1 in ship space corresponds to halfway out on the canvas.
1 var Simulation = function(ctx, size) { 2 this.ctx = ctx; 3 this.size = size; 4 this.reset(); 5 } 6 7 Simulation.prototype.drawStar = function() { 8 this.ctx.fillStyle= "#FF0"; 9 circle(this.ctx, 0, 0, 20); 10 } 11 12 Simulation.prototype.draw = function() { 13 this.ctx.fillStyle = "rgba(0,0,0,1.0)"; 14 this.ctx.fillRect(0, 0, this.size, this.size); 15 16 var dim = this.size/2; 17 18 this.ctx.save(); 19 this.ctx.translate(dim, dim); 20 this.drawStar(); 21 this.ctx.scale(dim/2.0, dim/2.0); 22 this.ship.draw(this.ctx); 23 this.ctx.restore(); 24 } 25 26 Simulation.prototype.step = function() { 27 var ship = this.ship; 28 var acc = ship.acc; 29 var angle = Math.atan2(ship.pos.x, ship.pos.y); 30 var d2 = ship.pos.x*ship.pos.x + ship.pos.y*ship.pos.y; 31 acc.x = -Math.sin(angle) / d2; 32 acc.y = -Math.cos(angle) / d2; 33 ship.adjust(this.mult); 34 if (d2 > 16) { 35 this.stop(); 36 alert("Ship Left Orbit!"); 37 } 38 } 39 40 41 Simulation.prototype.reset = function() { 42 this.stop(); 43 var ship = new Ship(); 44 ship.pos.x = 1.0; 45 ship.pos.y = 0.0; 46 ship.vel.x = 0.0; 47 ship.vel.y = -1.0; 48 this.ship = ship; 49 } 50 51 Simulation.prototype.run = function(mult, refresh) { 52 this.stop(); 53 this.mult = mult; 54 var self = this; 55 this.timer = setInterval(function() { 56 self.step(); 57 self.draw(); 58 }, refresh); 59 } 60 61 Simulation.prototype.stop = function() { 62 clearInterval(this.timer); 63 }Helper Function
Both the above classes call the helper function "circle" for drawing filled in circles.
1 var circle = function(ctx, x, y, rad) { 2 ctx.beginPath(); 3 ctx.arc(x, y, rad, 0, 2*Math.PI, false); 4 ctx.fill(); 5 }Onload
We need a few more controls, so the onload portion has a little extra functionality.
1 $(function() { 2 var canvas = document.getElementById("canvas"); 3 var size = 500; 4 canvas.width = size; 5 canvas.height = size; 6 var ctx = canvas.getContext('2d'); 7 var sim = new Simulation(ctx, size); 8 sim.draw(); 9 10 $("#run").click(function() {sim.run($("#mult").val(), $("#refresh").val())}); 11 $("#stop").click(function() {sim.stop()}); 12 $("#reset").click(function() {sim.reset(); sim.draw();}); 13 $("#ccw").click(function() {sim.ship.turnLeft(); sim.draw();}); 14 $("#cw").click(function() {sim.ship.turnRight(); sim.draw();}); 15 $("#thruster").mousedown(function() {sim.ship.thrusterOn = true; sim.draw();}); 16 $("#thruster").mouseup(function() {sim.ship.thrusterOn = false; sim.draw();}); 17 });HTML
Again, the HTML is just a canvas along with some controls.
1 <canvas id="canvas"></canvas> 2 <br /> 3 Mult: <input id="mult" type="text" value="0.01" size="4" /> 4 5 Refresh: <input id="refresh" type="text" value="15" size="3" />ms 6 7 <button id="run">Run</button> 8 <button id="stop">Stop</button> 9 <button id="reset">Reset</button> 10 <br /> 11 <button id="ccw">CCW</button> 12 <button id="cw">CW</button> 13 <button id="thruster">Thruster</button>