git @ Cat's Eye Technologies Cosmos-Boulders / master

Tree @master (Download .tar.gz)

Cosmos Boulders

Play it online @ | See also: Bubble EscapeNested Modal Transducers

Screenshot of Cosmos Boulders

An arcade-style HTML5 minigame built with immutable data and reducers in ES5 JavaScript.


The main goals are to demonstrate:

I say reducers are "acceptable" because I think Nested Modal Transducers would be better in several respects. The long-term plan is to write a version using them instead, to compare.


State machine diagram

This diagram was generated by State Machine Cat from the description in cosmos-boulders.smcat. While it does not capture every detail, it does show the overall structure.

State diagram of this video game

Tour of the code

The code uses Immutable.js to implement immutable data, and Redux.js to implement reducers. Neither library is used so extensively that it couldn't be easily eliminated, with the relevant parts of the code written "from scratch".

The code starts with some utility functions. These should be fairly self-explanatory. Some of them are designed to work with objects and actions inside reducers.

There is then a sequence of sections, one for each of the following objects: Player, Missile, Boulder, Game. Each section contains

One action that all of the reducers for all of these kinds of objects take, is STEP, which progresses the state of the entire game by one timeslice (usually somewhere around 1/60th of a second).

When a state machine is implemented with a reducer, the "state variable" which can take on a finite set of values, is not called state as might be expected; instead it is called the mode of the object. This is to avoid confusion between it and the state of the entire object.

The code tries to be very careful about not modifying game state data in the reducer functions, to the extent that it does not even overwrite local variables; instead it introduces a new local variables (called e.g. game2, game3, etc.) and places the new value in it. (i.e., in ES6 JavaScript, these locals could all be declared const.)

The section for InputContext objects may seem somewhat roundabout. Strictly speaking, the InputContext is not necessary, but it intends to illustrate a couple of things.

In a web browser, the DOM translates key presses into "key down" and "key up" events. But in an arcade cabinet, buttons are simply switches that are either make or break when the circuit reads them. The virtual hardware tries to simulate that.

But it's still useful for the game code to see "button pressed" as events. So it's the job of InputContext to synthesize those button level changes back into events for the game reducers.

The virtual hardware tries to simulate the basic circuitry of a video game arcade cabinet, including the screen (as a canvas) and the controls (as switches whose make or break state is reflected in a boolean value). It generates events when a new video frame is ready to be displayed, and when a coin is inserted.

Finally, the main driver sets up the virtual hardware, hooking up the events to a Redux store; subscribes to the store to update the video display.

Further reading