<!-- spctrvl.html - Space Travel video game --> <!-- Programming Notes Next tasks: - calibrate thrust velocity change with tick length - scale acceleration to zoom level - gravity --> <!DOCTYPE html> <html> <head> <title>Space Travel</title> <meta charset="utf-8"> <meta name="description" content="Space Travel video game"> <!-- [STYLE] ======================================================= --> <style> body { color: #009000 ; background-color: black ; font-family: "Bitstream Vera Sans Mono", "Lucida Sans", "Lucida Console", "MS Gothic" ; } canvas { border: 1px solid #909090; margin: auto; } button { width: 100%; } </style> </head> <body> <!-- [CONTENT] ===================================================== --> <h1>Space Travel</h1> <canvas id="canvas" width="600" height="600"></canvas> <div id="controls"> <table> <tr> <td><button onmousedown="zoom(1)" onmouseup="zoom(0)" ontouchstart="zoom(1)">ZOOM +<br>Z</button></td> <td><button onmousedown="reset()" ontouchstart="reset()">RESET<br>R</button></td> <td></td> <td><button onmousedown="thrust(1)" onmouseup="thrust(0)" ontouchstart="thrust(1)">↑<br>THRUST</button></td> </tr> <tr> <td><button onmousedown="zoom(-1)" onmouseup="zoom(0)" ontouchstart="zoom(-1)">ZOOM -<br>X</button></td> <td><button onmousedown="pause()" ontouchstart="pause()">PAUSE<br>P</button></td> <td><button onmousedown="rotate(1)" onmouseup="rotate(0)" ontouchstart="rotate(1)">ROT. L.<br>←</button></td> <td><button onmousedown="thrust(-1)" onmouseup="thrust(0)" ontouchstart="thrust(-1)">RETRO<br>↓</button></td> <td><button onmousedown="rotate(-1)" onmouseup="rotate(0)" ontouchstart="rotate(-1)">ROT. R.<br>→</button></td> </tr> </table> </div> <!-- [SCRIPT] ====================================================== --> <script> // Earth data var EARTHX = 0, // x position (km) EARTHY = 0, // y position (km) EARTHRADIUS = 6378, // radius (km) EARTHMASS = 5.97, // mass (* 10^24 kg) EARTHCOLOR = "#009000"; // Key codes var KEYLARR = 37, KEYUARR = 38, KEYRARR = 39, KEYDARR = 40, KEYP = 80, KEYR = 82, KEYX = 88, KEYZ = 90; // Other constants var PI2 = 2 * Math.PI, TICK = 10; // ms // Ship initial status var SHIPX0 = EARTHRADIUS, // km - On X-axis at Earth's surface SHIPY0 = 0, SHIPVX0 = 0, SHIPVY0 = 0, SHIPHEAD0 = 0; // Other initial values var SCALE0 = 1000; var CANVAS = document.getElementById("canvas"); var CTX = CANVAS.getContext("2d"); var ZOOM = 0; var HEADINCR = Math.PI / 200; // Ship status var shipX = 6378, // x position (km) shipY = 0, // y position (km) shipVx = 0, // x velocity (km/s) shipVy = 0, // y velocity (km/s) shipHead = 0, // heading (radian) shipColor = "#00ff00", shipThrust = 0, shipRotate = 0; // Other status var keyin = false, paused = false, scale = 1000, // canvas width in km timer; function xformPx (x, y) { var d = Math.sqrt (Math.pow (x - shipX, 2) + Math.pow (y - shipY, 2)); var phi = shipHead + Math.atan ((y - shipY) / (x - shipX)); var dPx = scalePx (d); var xC = -1 * dPx * Math.sin (phi); var yC = dPx * Math.cos (phi); return [xC, yC]; } function pause () { if (paused) { timer = setInterval (update, TICK); paused = false; } else { clearInterval (timer); paused = true; } } function reset () { shipX = SHIPX0; shipY = SHIPY0; shipVx = SHIPVX0; shipVy = SHIPVY0; shipHead = SHIPHEAD0; scale = SCALE0; } function scalePx (km) { return km * CANVAS.width / scale; } function thrust (dir) { shipThrust = dir; } function rotate (dir) { shipRotate = dir; } function zoom (dir) { ZOOM = dir; } function changeHead (dir) { shipHead += (dir * HEADINCR); if (shipHead >= PI2) shipHead -= PI2; else if (shipHead < 0) shipHead += PI2; } function drawShip () { CTX.beginPath (); CTX.moveTo (-5, 0); CTX.lineTo (5, 0); CTX.lineTo (0, -10); CTX.closePath (); CTX.fillStyle = shipColor; CTX.fill (); } function drawBody (x, y, r, color) { var cXY = xformPx (x, y); CTX.beginPath (); CTX.arc (cXY[0], cXY[1], scalePx (r), 0, 2*Math.PI); CTX.strokeStyle = color; CTX.stroke (); } 1 function handleKeyDown (event) { // alert ("handleKeyDown "); if (!event) { event = window.event; } var keycode = event.keyCode || event.which; // alert ("handleKeyDown " + keycode); switch (keycode) { case KEYLARR: rotate (1); break; case KEYUARR: thrust (1); break; case KEYRARR: rotate (-1); break; case KEYDARR: thrust (-1); break; case KEYP: pause (); break; case KEYR: reset (); break; case KEYX: zoom (-1); break; case KEYZ: zoom (1); break; } } function handleKeyUp (event) { // alert ("handleKeyUp "); if (!event) { event = window.event; } var keycode = event.keyCode || event.which; // alert ("handleKeyUp " + keycode); switch (keycode) { case KEYLARR: case KEYRARR: rotate (0); break; case KEYUARR: case KEYDARR: thrust (0); break; case KEYX: case KEYZ: zoom (0); break; } } function update () { // if (keyin) alert ("keyin " + keyin); if (ZOOM > 0) scale *= 0.99; if (ZOOM < 0) scale *= 1.01; changeHead (shipRotate); shipVx += shipThrust * Math.cos (shipHead); shipVy += -1 * shipThrust * Math.sin (shipHead); shipX += shipVx; shipY += shipVy; CTX.clearRect (-1 * CANVAS.width / 2, -1 * CANVAS.height / 2, CANVAS.width, CANVAS.height); drawBody (EARTHX, EARTHY, EARTHRADIUS, EARTHCOLOR); drawShip (); } // Main process CTX.translate (CANVAS.width/2, CANVAS.height/2); if (window.addEventListener) { document.addEventListener("keydown", handleKeyDown, false); document.addEventListener("keyup", handleKeyUp, false); } else { document.attachEvent("onkeydown", handleKeyDown); document.attachEvent("onkeyup", handleKeyUp); } timer = setInterval (update, TICK); </script> </body> </html>