scriptrm/spctrvl.html

283 lines
6.5 KiB
HTML
Executable File

<!-- 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)">&uarr;<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>&larr;</button></td>
<td><button onmousedown="thrust(-1)" onmouseup="thrust(0)"
ontouchstart="thrust(-1)">RETRO<br>&darr;</button></td>
<td><button onmousedown="rotate(-1)" onmouseup="rotate(0)"
ontouchstart="rotate(-1)">ROT. R.<br>&rarr;</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>