1. January 2019

How to write game with Vue.js – Sokoban – Part 2 – Display level as graphics

In the previous article, we set the foundation for building a clone of Sokoban game. We displayed level in form of text. This form is good for ASCII-art fan. Let’s take a look at how to make it more user-friendly by replacing characters with graphic tiles.

We’re going to implement the following principle. Each tile will be represented by span with fixed height and width. Also it will have fixed coordinates which could be achieved by setting top and left attribute to proper value. Then we will use CSS trick to display graphics tile from one image using CSS background attribute.

Let’s start with CSS for our game in file css/game.css.

.tile {
    width: 64px;
    height: 64px;
    position: absolute;
    background: url("../data/images/gfx64/tiles.png") 0 0;
}

The trick with background URL will pick the 1st tile from tiles.png file which begins at coordinates 0 0.

Warning: Do not forget to use units in CSS definition. In our case it is px. When you define dimension without unit you may end up with very strange results.

Here is the image with tiles which we will use in our game.

Now we need to load CSS in index.html.

<link rel="stylesheet" type="text/css" href="css/game.css"/>

Let’s update the template for playground component so that tiles are displayed instead of letters.

    <div v-for="(tileRow, rowIndex) in levelMap">
        <span class="tile" v-for="(tileName, tileIndex) in tileRow"
            :style="{ top: rowIndex*64 + 'px', left: tileIndex*64 + 'px'}"></span>
    </div>

What is new in this template definition?

Clearly class=”tile” which will apply the style defined in game.css file to html element.

The second new thing is the definition of style. We can notice colon before word style. It’s shorthand for v-bind:style. This special syntax will tell Vue.js that the value of the attribute should be computed. In our case, we’re composing map which corresponds to syntax in CSS. If we look closely at the syntax it will render something like this:

{ top: 64px, left: 128px }

The question is how to map letter to from level map to tile stored in PNG file. The answer is simple. We will create a special class for each letter which references tile in PNG file. Then this class will be written into HTML code.

Let’s look at the first piece in css/game.css.

.tile {
...
    background: url("../data/images/gfx64/tiles.png") 0 0;
}

.tile-w {
    background: url("../data/images/gfx64/tiles.png") 0 -192px;
}

The pair of numbers indicates the start of tile from the top left corner. In CSS it’s recommended to use negative values for referencing coordinates to get the same experience across browsers.

Now, it’s necessary to update the code of template just a little bit.

        <span v-for="(tileName, tileIndex) in tileRow"
            :class="['tile tile-' + tileName]"
            :style="{ top: rowIndex*64 + 'px', left: tileIndex*64 + 'px'}"></span>

We’ve added :class which is abbreviation for v-bind:class. In this case we’re composing string which will be interpreted by web browser. So the result might look like: ’tile tile-w’

The result should look like this:

The source code of this article is stored at Github.

In the next article, we will add player’s avatar and box as game objects.

You can find more HTML5 games at https://georgik.rocks/tag/games

Back to tutorial Sokoban in Vue.js