Weltkriegsimulator (WKS) is a vertical scrolling shoot 'em up that was created to showcase the possibilities of creating a game using the open source zCanvas library.
You can play the game directly in your browser by navigating here.
WKS is a Javascript project (ES6) and uses the CommonJS require/exports-pattern. The dependencies are managed via NPM and the build scripts are written in Grunt.
The only requirement on your system is to have Node.js installed. With Node installed, you can resolve all dependencies via command line using:
npm install
You can start the dev mode by running:
grunt dev
This mode will launch a local server allowing you to debug the application from your browser through the local URL http://localhost:3000. When you make changes / additions to the source files, a watcher will register the changes, rebuild the application and refresh the browser so you can see the effect of your changes directly.
You can create a production ready package by running:
grunt build
WKS uses no framework but was written in vanilla JS. The only used libraries besides the aforementioned zCanvas are TweenMax (easing functions), Handlebars (for HTML templating) and pubsub-js (for messaging).
All source code resides in the ./src/js-directory. The main application logic is split up into:
- controllers
- factory
- model
- view
The controllers are responsible for managing changes in the model and updating the appropriate views. These controllers are:
- GameController sets up the game, changes game world properties, delegates changes in game state (through ActionFactory.js)
- InputController listens to keyboard/touch input and delegates these actions onto the Player
- RenderController maintains the zCanvas that will render all of the game's Actors on the screen as well as manage audio events
- ScreenController overlays different screens (e.g. title screen, game UI, high scores list)
The views represent each of the screens used in the game. They are managed by their appropriate controllers. Note: for the game elements (the Actors) these are represented by renderers (see zCanvas in WKS below).
The models contain all data and properties. For the game's model (Game.js) this is where the state and contents of the game's "world" are held. Apart from generic world properties determining the game's behaviour and progress, this model also references the Actors. The Actors are instances of all Objects in the game (for instance: the player, bullets, powerups, enemy ships). These share common properties such as coordinates, speed, but have their own custom properties (e.g. energy, weapon damage, etc.). These Actors are defined as ES6 classes as the Object Oriented Pattern works well for inheritance purposes. The remainder of the applications business logic follows the Functional Programming pattern.
Finally, the factories are used to generate data to populate the models. ActionFactory is of interest as it generates the enemy waves and the powerups.
Communication between these models, views and controllers is done using the publish-subscribe pattern where messages are broadcast to subscribed listeners to act upon. As such, different players might be interested in the same message for the same purpose (for instance: a message of GAME_OVER might trigger the GameController to stop the action queue and freeze the game loop, while at the same time the InputController decides to stop listening to input events and the ScreenController to open the high score input screen. "Separate the concerns"!
The zCanvas is used to render the game "world". All other visual components (energy bar, score, menus, etc.) are overlaid in HTML.
The zCanvas is maintained by RenderController. It is this controller that creates the zCanvas, sizes it accordingly and manages its display list. In WKS, there are multiple layers in the world to give the illusion of depth. Each of the games actors are appended to the appropriate according layer.
The visual representation of an Actor is done using a zCanvas zSprite. We refer to these instances as renderers. All zCanvas renderers reside in the ./src/js/view/renderers-directory. A renderers only job is to visually represent the state of the Actor. Game.js knows nothing about renderers, and it doesn't have to, it merely updates the actors in the game world.
On each render cycle (60 times per second) of the zCanvas, zCanvas requests an update() from the Game, subsequently it will draw all renderers onto the screen. Consult the zCanvas wiki to learn about the API.
Note zCanvas is always on-screen, the different screens (e.g. Title, High Scores, etc.) are overlaid on top (see ScreenController.js).
TweenMax is a powerful animation engine by Greensock. Within WKS it is used to perform easing functions on Actors which in turn are visualised as animations. Additionally, TweenMax is also a convenient timing engine, instead of relying on setTimeout() (which fires when the browser tab is suspended and can drift), we use TweenMax.delayedCall() which is rock solid and can pause when the applications tab suspends.
A vertical scrolling shoot 'em up is pure mayhem with a lot of Objects being in use simultaneously, as well a lot of generation / removal of Actors.
For this purpose, this application uses pooling. When a resource is no longer needed (for instance: bullet is out of screen bounds), it is not disposed, but returned to the pool. The next time a new instance of that type (for instance: newly fired bullet) is needed, it is retrieved from the pool and updated to have the appropriate properties (e.g. new position, direction, etc.). This pool is maintained by Game.js.
Apart from game Actors pools, there is also a pool for decorative effects (e.g. explosions which are triggered by Actors, but not actually an Actor by themselves). These are managed by RenderController.js.