This is the fifth post in the Building a Roguelike in Javascript series. I recommend you start at the beginning unless you've been following along. This part corresponds to the fourth part in Trystan's series. All the code for this part can be found at the part 4 tag of the jsrogue repository. At the time of writing, I am still using the d4ea2ab commit for rot.js.

Now that we've got some interesting caves we want a hero so that we can play our game and explore the dark depths of the caves! In this post we'll lay down the foundation for the characters in the game (which we'll call entities) and by the end of it we'll use this system to add our player to the map. If you played around with the demo from the last post you may have noticed that the caves aren't always fully connected. We want our hero to start the game in a random part of the cave every time so we're going to need to make a way so that the player isn't stuck if they can't get to one part of the cave. Our hero will be able to dig through walls in the cave in order to avoid ever getting stuck. Once we add lighting to the game this is going to be a really neat part of the game as we will have to explore and dig through walls without knowing what's on the other side!

Demo Link

The results after this post can be seen here

assets/glyph.js

First things first we have a small bit of refactoring to do! In part 3a we introduced the Glyph type , which had a constructor that accepted 3 arguments (character, foreground and background). However this isn't very flexible and isn't taking advantage of the features in Javascript! We are going to change this so that it accepts a simple Javascript object such as:

{
    character: '@',
    foreground: 'white',
    background: 'black'
}


Why is this better? We are going to want to extend the Glyph later on for characters, items, and all sorts of fancy features. By passing a Javascript object to our constructor (and making sure it gets passed to the parent class as well) we can quickly instantiate objects with the right properties while providing defaults if a given property isn't there. This was inspired by a similar method used in The Royal Wedding, a fantastic open-source roguelike written using rot.js which I encourage you to check out. We simply have to update our constructor like so:

1
2
3
4
5
6
7
Game.Glyph = function(properties) {
    // Instantiate properties to default if they weren't passed
    properties = properties || {};
    this._char = properties['character'] || ' ';
    this._foreground = properties['foreground'] || 'white';
    this._background = properties['background'] || 'black';
};

assets/tile.js

As our constructor has changed we have to update the code where we created glyphs for our tiles to use a Javascript object. While we're in the tile file, we're also going to need to add some notion of whether a tile can be walked on as well as whether a tile can be dug through. In order to do this, we're going to make Game.Tile extend Game.Glyph and accept a Javascript object in the constructor as well! This will allow us to define tiles in a much simpler fashion:

1
2
3
4
5
Game.Tile.wallTile = new Game.Tile({
    character: '#',
    foreground: 'goldenrod',
    isDiggable: true
})

So let's go ahead and update that code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Game.Tile = function(properties) {
    properties = properties || {};
    // Call the Glyph constructor with our properties
    Game.Glyph.call(this, properties);
    // Set up the properties. We use false by default.
    this._isWalkable = properties['isWalkable'] || false;
    this._isDiggable = properties['isDiggable'] || false;
};
// Make tiles inherit all the functionality from glyphs
Game.Tile.extend(Game.Glyph);

// Standard getters
Game.Tile.prototype.isWalkable = function() {
    return this._isWalkable;
}
Game.Tile.prototype.isDiggable = function() {
    return this._isDiggable;
}

Game.Tile.nullTile = new Game.Tile({})
Game.Tile.floorTile = new Game.Tile({
    character: '.',
    isWalkable: true
});
Game.Tile.wallTile = new Game.Tile({
    character: '#',
    foreground: 'goldenrod',
    isDiggable: true
});

Note that because we removed the getGlyph method (as it directly extends Glyph) we're going to have to fix up the rendering. This will be done later in the post so have no worries!

assets/entity.js

We are now ready to define an entity. In its most basic form, an entity is composed of a glyph as well as a position and a name (used in messages). It will be the base object for nearly everything that can be seen on the screen and can be interacted with. This is similar to Trystan's Creature class however we're going to try avoiding traditional inheritance and instead taking advantage of the powers of Javascript.

Because anything can be an entity, for example the hero, a potion on the ground, or a wildebeest, we're going to need some way of giving certain behaviors to different entities. For this we're going to use something similar to mixins which are small sets of functions and state that we can add to certain entities to give them certain behaviors. This was inspired by Steve Losh's Caves of Clojue approach. One example of a mixin defines an entity as moveable, giving it functions for moving and checking valid moves. Another example is defining an entity as a container of other entities. This could be used for an entity representing a chest, but could also be used for more strange things such as a chicken containing egg items.

For now we will first focus on creating a basic entity class which extends a glyph with a position and a name:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Game.Entity = function(properties) {
    properties = properties || {};
    // Call the glyph's construtor with our set of properties
    Game.Glyph.call(this, properties);
    // Instantiate any properties from the passed object
    this._name = properties['name'] || '';
    this._x = properties['x'] || 0;
    this._y = properties['y'] || 0;
}
// Make entities inherit all the functionality from glyphs
Game.Entity.extend(Game.Glyph);

Game.Entity.prototype.setName = function(name) {
    this._name = name;
}
Game.Entity.prototype.setX = function(x) {
    this._x = x;
}
Game.Entity.prototype.setY = function(y) {
    this._y = y;
}
Game.Entity.prototype.getName = function() {
    return this._name;
}
Game.Entity.prototype.getX = function() {
    return this._x;
}
Game.Entity.prototype.getY   = function() {
    return this._y;
}

A mixin will be a simple Javascript object which will be attached to each entity that chooses it. Note that we will set it up so that this can be used in the mixin objects to refer to the calling entity. Each mixin can have an init function which is called when we create a new entity and attach that mixin, and it will pass the same Javascript object to the init function that was used to create the entity (like the object used to create a Glyph above). A mixin must also have a name attribute which will be useful when we try to determine if a player has a given mixin. This is going to make our code base a bit more complicated, but I believe it will be very useful for us to easily assign bits and pieces of functionality to different entities. The whole reason we are doing this is so that we avoid rewriting code and to make sure we don't have objects bloated with functions and state they'll never use. Try to bear with me, and if there is anything unclear please post a comment and let me know! I'd be glad to help!

Here is an example of a mixin which would keep track of the number of hits an entity has made, just to give you an idea of how they will work. It will also give an example of adding state to the entity via the init function by storing a simple multiplier. You do not need to add this code anywhere, it is just an example of how we are going to use the system.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var HitCounter = {
    name: 'HitCounter',
    init: function(properties) {
        // Add state to the entity and read from the properties
        this._multiplier = properties['multiplier'] || 1;
        this._hits = 0;
    },
    incrementHit: function() {
        // Update state
        this._hits += this._multiplier;
    },
    getTotalHits: function() {
        return this._hits;
    }
}

Ideally we would like to specify what mixins an entity has when we create it via the Javascript object we pass. We will add a field called mixins containing an array of mixins which will be automatically attached to the entity. Once we attach a mixin to an entity, all the mixin functions are available directly from our entity! For example to create and use an entity which had the HitCounter mixin:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var e = new Game.Entity({
    character: '@',
    foreground: 'blue',
    x: 1,
    y: 3,
    name: 'Test Entity',
    mixins: [HitCounter],
    multiplier: 5
})

e.incrementHit();
e.incrementHit();
console.log(e.getTotalHits());

In order to do this we're going to modify our Entity constructor to process this array of mixins. Note that we will also store the name of each mixin we attached in an object so that we can quickly look up if an Entity has a given set of functionalities (similar to the instanceof keyword). So you're going to want to change the constructor to look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Game.Entity = function(properties) {
    properties = properties || {};
    // Call the glyph's construtor with our set of properties
    Game.Glyph.call(this, properties);
    // Instantiate any properties from the passed object
    this._name = properties['name'] || '';
    this._x = properties['x'] || 0;
    this._y = properties['y'] || 0;
    // Create an object which will keep track what mixins we have
    // attached to this entity based on the name property
    this._attachedMixins = {};
    // Setup the object's mixins
    var mixins = properties['mixins'] || [];
    for (var i = 0; i < mixins.length; i++) {
        // Copy over all properties from each mixin as long
        // as it's not the name or the init property. We
        // also make sure not to override a property that
        // already exists on the entity.
        for (var key in mixins[i]) {
            if (key != 'init' && key != 'name' && !this.hasOwnProperty(key)) {
                this[key] = mixins[i][key];
            }
        }
        // Add the name of this mixin to our attached mixins
        this._attachedMixins[mixins[i].name] = true;
        // Finally call the init function if there is one
        if (mixins[i].init) {
            mixins[i].init.call(this, properties);
        }
    }
}

Finally we're going to add a method to the Entity class which allows us to check if a given entity has a given mixin. We're going to make it so we can either pass the mixin itself or just the name, and it'll check the _attachedMixins object in the entity:

1
2
3
4
5
6
7
8
Game.Entity.prototype.hasMixin = function(obj) {
    // Allow passing the mixin itself or the name as a string
    if (typeof obj === 'object') {
        return this._attachedMixins[obj.name];
    } else {
        return this._attachedMixins[name];
    }
}

Now that we've got our entity system all set up, we're ready to create our player! The only problem right now is that we have no functions in the Game.Map object for checking whether we can move and dig through a given tile. Let's go ahead and create that first!

assets/map.js

We simply want to add a function that digs at a given tile. We have to check that the tile is actually diggable, and if so we then convert it to a floor tile!

1
2
3
4
5
6
Game.Map.prototype.dig = function(x, y) {
    // If the tile is diggable, update it to a floor
    if (this.getTile(x, y).isDiggable()) {
        this._tiles[x][y] = Game.Tile.floorTile;
    }
}

As our player will start in a random position in the cave, we're going to add in a function which will generate a random position which has a floor tile:

1
2
3
4
5
6
7
8
9
Game.Map.prototype.getRandomFloorPosition = function() {
    // Randomly generate a tile which is a floor
    var x, y;
    do {
        x = Math.floor(Math.random() * this._width);
        y = Math.floor(Math.random() * this._width);
    } while(this.getTile(x, y) != Game.Tile.floorTile);
    return {x: x, y: y};
}

assets/entities.js

We are now ready to create our player and it's related mixins! The first thing we are going to do is create a mixin for moving. This mixin will simply have a tryMove function which accepts a position as well as the current map and tries to move in a given direction. If the entity cannot move through a tile but can dig, it will dig the tile instead. Finally the function will return true if there was a succesful action (moving or digging).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Create our Mixins namespace
Game.Mixins = {};

// Define our Moveable mixin
Game.Mixins.Moveable = {
    name: 'Moveable',
    tryMove: function(x, y, map) {
        var tile = map.getTile(x, y);
        // Check if we can walk on the tile
        // and if so simply walk onto it
        if (tile.isWalkable()) {
            // Update the entity's position
            this._x = x;
            this._y = y;
            return true;
        // Check if the tile is diggable, and
        // if so try to dig it
        } else if (tile.isDiggable()) {
            map.dig(x, y);
            return true;
        }
        return false;
    }
}

We are now ready to define our player entity! For now we will simply make the Javascript object that is used to create the player a variable in the Game namespace but this will be refactored in a future entry as soon as we want to have multiple entities. This will also show how the raw Javascript objects can act as templates for entities that can be reused:

1
2
3
4
5
6
7
// Player template
Game.PlayerTemplate = {
    character: '@',
    foreground: 'white',
    background: 'black',
    mixins: [Game.Mixins.Moveable]
}

assets/screens.js

We are now ready to change our screen to work with our new Player! The first things we are going to do is remove the centerX/centerY properties and add a player property to the PlayScreen:

1
2
3
4
5
6
7
8
Game.Screen.playScreen = {
    _map: null,
    _player: null,
    enter: function() { 
        // ...
    }
    // ...
}

Now at the end of our enter function, after we create the map, we want to create our player based on our template and then position the hero inside the cave!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Game.Screen.playScreen = {
    // ...
    enter: function() { 
        // ...
        // Create our map from the tiles
        this._map = new Game.Map(map);
        // Create our player and set the position
        this._player = new Game.Entity(Game.PlayerTemplate);
        var position = this._map.getRandomFloorPosition();
        this._player.setX(position.x);
        this._player.setY(position.y);
    }
    // ...
}

Now we have to update our render function for two reasons. First we no longer need centerX/centerY and instead should use the player's position for determining the camera offsets as well as rendering the player! Secondly we have to change how tiles are rendered as tiles now extend glyphs!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Game.Screen.playScreen = {
   // ...
   render: function(display) {
        var screenWidth = Game.getScreenWidth();
        var screenHeight = Game.getScreenHeight();
        // Make sure the x-axis doesn't go to the left of the left bound
        var topLeftX = Math.max(0, this._player.getX() - (screenWidth / 2));
        // Make sure we still have enough space to fit an entire game screen
        topLeftX = Math.min(topLeftX, this._map.getWidth() - screenWidth);
        // Make sure the y-axis doesn't above the top bound
        var topLeftY = Math.max(0, this._player.getY() - (screenHeight / 2));
        // Make sure we still have enough space to fit an entire game screen
        topLeftY = Math.min(topLeftY, this._map.getHeight() - screenHeight);
        // Iterate through all visible map cells
        for (var x = topLeftX; x < topLeftX + screenWidth; x++) {
            for (var y = topLeftY; y < topLeftY + screenHeight; y++) {
                // Fetch the glyph for the tile and render it to the screen
                // at the offset position.
                var tile = this._map.getTile(x, y);
                display.draw(
                    x - topLeftX,
                    y - topLeftY,
                    tile.getChar(), 
                    tile.getForeground(), 
                    tile.getBackground())
            }
        }
        // Render the player
        display.draw(
            this._player.getX() - topLeftX, 
            this._player.getY() - topLeftY,    
            this._player.getChar(), 
            this._player.getForeground(), 
            this._player.getBackground()
        );
    },
    // ... 
}

1 Our last step is to change the move function to interact with our new entity and it's Moveable mixin! Recall that the move function accepts an offset in the x and y direction and so we should recalculate the new position based on these offsets and then call the tryMove method! Also note that the screen automatically re-renders when we handle input, so we don't have to worry about calling it ourselves!

1
2
3
4
5
6
7
8
9
Game.Screen.playScreen = {
    // ...
    move: function(dX, dY) {
        var newX = this._player.getX() + dX;
        var newY = this._player.getY() + dY;
        // Try to move to the new cell
        this._player.tryMove(newX, newY, this._map);
    }
}

index.html

We are almost done! We just have to add our new scripts!

1
2
    <script src="assets/entity.js"></script>
    <script src="assets/entities.js"></script>

Conclusion

We've now done a huge step! We now have a player who can dig around and move around the caves! We've also done something much more important though - we set up a general framework for pretty much every interactive entity on the screen! I'm hoping that this combination of mixins and Javascript objects will turn out to be very practical and I hope it also showed you just how neat Javascript can be. The system can easily be extended to do things such as allow mixin inheritance (for example having a Mixin which extends another Mixin), but for the sake of simplicity and shortness I will try to avoid overcomplicating it.

I hope you enjoyed this post and that you'll stick around for the next part! It's going to get very interesting, I promise you! Remember that all the code for this part can be found at the part 4 tag of the jsrogue repository. Also please feel free to post any comments whether questions, clarifications or criticism!

Thanks for reading,

Dominic

Next Part

Part 5a - Populating the Cave