Skip to content

Instantly share code, notes, and snippets.

@FND
Created April 11, 2009 17:23
Show Gist options
  • Save FND/93642 to your computer and use it in GitHub Desktop.
Save FND/93642 to your computer and use it in GitHub Desktop.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JavaScript-based game experiment</title>
<link rel="stylesheet" type="text/css" href="styles/main.css">
</head>
<body>
<div id="screen"></div>
<div id="info">
<h2>Controls</h2>
<dl>
<dt>space</dt>
<dd>toggle pause</dd>
<dt>cursor keys (&uarr;, &darr;, &larr;, &rarr;)</dt>
<dd>movement</dd>
</dl>
<h2>Description</h2>
<p>This is a simple experiment exploring how a game might be implemented using web standards.</p>
<p>The idea is for this to eventually become a (very basic) skydiving simulator.</p>
<h2>Caveats</h2>
<p>Currently only tested on Firefox.</p>
<p>Not using <code>canvas</code> yet.</p>
<p>Precision of motion calculations are imperfect (especially visible near the edges of the screen element).</p>
<p>Collision detection might turn out to be tricky to implement.</p>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
<script src="scripts/util.js" type="text/javascript"></script>
<script src="scripts/main.js" type="text/javascript"></script>
</body>
</html>
* {
margin: 0;
padding: 0;
}
h2,
p,
dd {
margin: 0.2em 0;
}
dl {
overflow: auto; /* detach from floated neighbor */
}
dt {
font-weight: bold;
}
dd {
margin-left: 1em;
}
#info {
margin-left: 830px; /* based on total size of screen element */
}
#screen {
position: absolute;
top: 10px;
left: 10px;
width: 800px;
height: 600px;
overflow: hidden;
border: 5px solid #AAA;
background-color: #EEE;
}
.player {
position: relative;
top: 0;
left: 395px;
width: 10px;
height: 10px;
background-color: #F00;
}
(function($) {
/*
* settings
*/
var game = {
fps: 30, // frame rate
sensitivity: 0.5, // controls sensitivity
screen: "#screen"
};
var keys = {
start: 32, // space -- XXX: rename?
up: 38, // up arrow
down: 40, // down arrow
left: 37, // left arrow
right: 39 // right arrow
};
/*
* rendering and input processing
*/
var busy = false; // indicates whether calculation in progress
var tick = function() { // redraw step
if(busy) { // skip to prevent sync disruption
log("throttled");
return;
}
busy = true;
handleInput();
busy = false;
};
var handleInput = function() { // XXX: rename?
var cmds = game.commands; // alias
// player movement
var vert = 0;
var horiz = 0;
if(cmds.contains(keys.up)) {
vert += game.sensitivity * 0.1;
}
if(cmds.contains(keys.down)) {
vert -= game.sensitivity * 0.1;
}
if(cmds.contains(keys.left)) {
horiz -= game.sensitivity * 0.1;
}
if(cmds.contains(keys.right)) {
horiz += game.sensitivity * 0.1;
}
move(game.player, {
vert: vert,
horiz: horiz
});
};
/*
* keyboard handling
*/
$(document).keypress(function(ev) {
if(ev.which == keys.start) {
togglePause();
}
});
// game controls -- XXX: prevent event propagation?
game.commands = []; // current command stack (processed on redraw) -- XXX: do not use key codes directly
$(document).keydown(function(ev) {
game.commands.push(ev.which);
});
$(document).keyup(function(ev) {
game.commands.splice(game.commands.indexOf(ev.which), 1);
});
/*
* utility functions
*/
/*
* accelerate element along vector, using inertia from previous motions
*
* direction is determined by vector's "vert" and "horiz" members (negative
* values reverse direction)
* these members' values also determine acceleration rate (pixels per second)
*
* caches element position to avoid repeatedly querying the DOM
*/
var move = function(el, vector) { // XXX: rename -- TODO: make jQuery method
var pos = el.pos || el.position();
var impetus = el.impetus || { vert: 0, horiz: 0 }; // XXX: rename?
el.impetus = {
vert: impetus.vert + vector.vert * delay,
horiz: impetus.horiz + vector.horiz * delay
}; // XXX: ensure vector * speed >= 1 -- TODO: make vector members optional
el.pos = {
top: pos.top - impetus.vert,
left: pos.left + impetus.horiz
};
el.css(el.pos);
};
/*
* initialization
*/
var delay = 1000 / game.fps; // milliseconds between redraws
var paused = true;
var togglePause = function() {
if(paused) {
log("launching");
$(game.screen).fadeTo("normal", 1.0);
game.pid = setInterval(tick, delay);
paused = false;
} else {
clearInterval(game.pid);
paused = true;
$(game.screen).fadeTo("normal", 0.3);
log("paused");
return;
}
};
var init = function() {
$(game.screen).
click(function() { togglePause(); });
game.player = $('<div class="player" />').
appendTo(game.screen);
game.player.impetus = { vert: -10, horiz: 0 };
togglePause(); // launch
togglePause(); // pause
};
$(function() {
init();
});
})(jQuery);
// log message for debugging
function log(message) {
if(window.console && console.log) {
console.log(new Date(), message);
}
}
// return a given item's position in the array
if(!Array.indexOf) {
Array.prototype.indexOf = function(item, from) {
if(!from) {
from = 0;
}
for(var i = from; i < this.length; i++) {
if(this[i] === item) {
return i;
}
}
return -1;
};
}
// return whether an entry exists in the array
Array.prototype.contains = function(item) {
return this.indexOf(item) != -1;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment