Roguelike 2 - Using HTML for graphics
This is the second of several posts I’m writing to catalogue the development of my game. This article focusses on how to use HTML as graphics.
Continuing from Part 1, where I scaffolded a game loop and a state stack, now on to the more interesting bit: handling HTML elements in a game.
Everything you see on screen is an HTML element. There are two main ‘categories’ of elements. The first is the structure that holds everything in place. The second are the elements that make up the tiles of the game. The first one is straight forward, just a bunch of static divs, so I’ll just focus on the second category.
The decorator pattern
All parts of the game are controlled by Javascript. Since almost all parts of the game are also HTML elements, this project uses the decorator pattern liberally to attach more actions to elements. Simply put, it allows the game to store objects that act more like game objects, while still capable of being HTML elements. Here’s a fiddle with an example (also see Assets below).
I chose not to extend the prototype of native class HTMLElement
for this because not all methods added this way are applicable to all elements. This methods just expands the capabilities of a single object of type HTMLElement
. More specifically, move
will move the object n
amount of pixels to the left or right by setting the specific dataset
attributes, and then parsing those as style in the draw
function. This allows me to do all sorts of checks and balances before manipulating the actual position of the element on the screen.
I’m using this pattern for almost everything that has a shared componenent, that in other languages might have been an inherited class or interface.
Tiles and assets
Two concepts. a Tile is a square of a particular size representing a specific chunk of the game world. This drives game mechanics and visuals, so Tiles are more functional in nature and can be seen as the definition of said chunk of game. There are tiles for rock, water and trees, but also for players, monsters and items.
The second concept is assets, which govern the technical nature of a chunk in the game world. An asset has actions like the ability to position itself on the screen and can keep track of all attributes like current position, wether it’s visible to the player or invisible etc. Part of an asset in this scenario is a Tile type, but all actions and attributes are more or less independent of that. An asset is like the implementation of a game chunk.
To streamline the process of defining Tiles and creating Assets, the game has the following:
- a tile bank, holding information about every type of tile out there. I want a central repository which will just simply give me a tree, without me specifying every time there needs to be a
*
character in it, or that you can’t walk through a tree. - an asset generator, which implements a tile using the decorator pattern explained above.
Tilebank
function TileBank() { |
The reason TileBank
creates new Tile
objects is that every tile you’re getting out should be unique. If I simply return the object literal, I can never tweak that particular tile without changing all tiles of that type - the object literal would be referenced everywhere.
Usage example:
var bank = new TileBank(); |
Assets
The Asset function uses the decorator described above. What you see below is not the full code, it’s meant to show you how I’ve approached creating assets and should be used as an example.
function Asset(tile, x, y) { |
To get a tree in grid position [5,10] and put it in the browser all that’s left to do is:
var tree = Asset(bank.get('tree'), 5, 10); |
In reality this should be fleshed out. My roguelike implements not only static objects like trees and grass, but also moving elements like the player object. They have the get
, set
and draw
functions, but were run through an additional decorator to add functions for movement, for instance collision detection.
With some CSS styling to add colours, the result looks like this:
In part three, I will explain how I generated that island above.