Roguelike development in JavaScript
Roguelike development in JavaScript
Is it scary?
(Hint: no)
This talk
- Slight introduction to JS subculture
- Aimed at seasoned traditional RL devs
- Definitely not a PR for my kickass JS toolkit rot.js
Contents
- Using JS for rapid prototyping/development
- Common myths and FUDs busted
- Typical JS scenarios
JavaScript is cool, because…
- Cross-platform availability, accessibility
- Battle-tested (20 years old)
- Easy to start with (hard to master, though)
- Many useful APIs available in every browser
JavaScript is expressive
- Dynamic typing
- No type checks, duck typing, monkey patching
- First-class functions
- Prototypal inheritance
- Automatic memory management (GC)
JavaScript is expressive
Example: fiery explosion
var nearby = map.getNearby(x, y, r);
var damaged = nearby.filter(function(entity) {
if (!entity.damage) { return false; } /* not damagable */
entity.damage(5);
Math.random() > 0.5 && (entity.catchFire || entity.burn)();
return true;
});
alert(damaged.length + " entities were damaged");
But JavaScript is slow?
- It depends.
- Modern implementations compile JS to native code (JIT)
- Cross-language benchmarks: fortran 1×, C/C++ 1.1×, JS 5×, Lua 50×, PHP 90×, Python 110×, …
- Is speed a first-class concern? Rogue 1980, Moria 1983, Hack 1985, …
But JavaScript is broken?
- Yes, I saw the "WAT?" talk
- Shooting yourself in the leg does not imply the gun is bad
- People uncomfortable with all language features can limit themself to "safe" subsets (The Good Parts)
- Many transpilable languages: CoffeeScript, TypeScript, ClojureScript, …
But JavaScript has this weird OOP?
- Yes, there are no classes
- Just three non-traditional concepts to familiarize with
this
resolved at runtime
- prototypal inheritance (
prototype
and __proto__
) properties
new
operator being just a syntax sugar
But JavaScript needs cross-browser thingiez?
- Not anymore
- Modern browsers converged to unified APIs
- jQuery (and its alternatives) is mostly obsolete in 2014
- Bleeding edge features can be often polyfilled
But JavaScript is all async and I am afraid of synchronization?
- JS runs in a single thread, always
- Your JS code is wrapped into an (invisible) event loop, handled by the browser
- No interrupts, no (dead)locks, no problems
JS Scenarios: main loop
while (true) {
processInput();
update();
render();
}
- There are no blocking calls in JS
- No waiting or sleeping
- Event-driven programming
- The loop is implicit
JS Scenarios: main loop
window.addEventListener("keypress", function() {
processInput();
update();
render();
});
JS Scenarios: input APIs
- Keyboard events (keydown, keypress, keyup)
- Mouse events (mousedown, mouseup, click, mousemove, …)
- Touch events
- Event data: key/char identifiers, modifier keys, mouse position
JS Scenarios: KB input
var KBHandler = {
handleEvent: function(e) {
var what = null;
if (e.type == "keydown") { what = e.keyCode; } /* hardware key code */
if (e.type == "keypress") { what = String.fromCharCode(e.charCode); } /* unicode code point */
switch (what) {
case 37: /* move left */ break;
case "d": /* drop stuff */ break;
}
}
}
window.addEventListener("keydown", KBHandler);
window.addEventListener("keypress", KBHandler);
JS Scenarios: output APIs
- DOM (HTML elements) – beware, this is a tricky beast
- 2D Canvas: raster drawing (paintbrush), accelerated when available
- 3D WebGL: OpenGL ES 2.0
- Support for TTF/OTF/WOFF vector fonts
JS Scenarios: 2D output
<canvas width="640" height="480">
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "20px monospace";
ctx.fillStyle = "blue";
ctx.fillText(50, 50, "@");
ctx.beginPath();
ctx.moveTo(100, 50);
ctx.lineTo(50, 100);
ctx.stroke();
ctx.drawImage(imageOrCanvas, 100, 100);
JS Scenarios: misc APIs
- Network: HTTP, WebSocket (no BSD sockets)
- Native audio/video playback
- WebWorkers: additional JS in a separate thread; nothing shared though (message event passing)
You see a scroll labeled "Questions?"