Sokoban Series: Part 1, Getting Everything Up and Running

Sokoban

In this series we discuss our Sokoban clone, written in Phaser 3. The game is available on CrazyGames.

For those that are not familiar with Phaser, it is a nice framework to develop (mainly 2D) HTML5 games. Phaser 3 has been in development for some time now, and has been deemed stable for a couple of months.

Sokoban is an old Japanese puzzle game from the 80s. Your character is a warehouse employee that needs to push crates into the correct location. You can only push a single crate at the time, and must be careful not to get stuck.

The focus of this writeup lies on the implementation, and we’ll show a lot of code snippets. The reason for this is that, while the implementation of Phaser 3 itself may be done, it is still lacking some documentation and more advanced code examples. Nonetheless, the documentation and examples pages are invaluable resources, and something I always had open during development. We try to highlight some of the issues we encountered while developing Sokoban, and how we solved them.

Some of the details of our implementation are left out to increase readability, and to narrow the discussion to Phaser itself. It is possible that some inconsistenties can be found in these snippets due to this cleanup.

Table of Contents

This is a multipart series, where we discuss the following topics:

This post discusses the first part: Getting Phaser & Typescript up and running.

Getting Started

In this section we discuss how to get Phaser 3 up and running with Typescript, and get a nice development environment where we can test our game during development.

Getting Typescript up and Running

We start by getting Phaser 3 up and running with Typescript. Typescript is a typed version of Javascript that compiles down to Javascript. I prefer working with Typescript as you get features such as tab completion, type information which is very handy with a large framework such as Phaser 3, and potential errors get caught early by your compiler.

Phaser 3 has support for Typescript, even though the type definitions do not cover Phaser 100%. Type definitions state what arguments a certain function takes, and what the return type is. Instead of setting up everything ourselves we can start from this skeleton project.

We clone it, rename the folder to Sokoban, remove the .git folder and import it into our code editor. In our case this is Visual Studio Code. Next, we edit the package.json file, and ensure we’re using the latest version of Phaser 3. You can see the latest version by going to npmjs.com. Installing all the dependencies is done by running npm install.

We replace the phaser.d.ts typings file with the latest version found here. We move everything from the src/boilerplate directory into the src/ directory, and remove everything else. Remove the comment at the top of game.ts that refers to the Phaser typings. Typescript should detect the typings without any assistance. Finally, we edit webpack.config.js so that entry points to ./src/game/ts.

When you try to run your project (npm run dev) you should get redirected to your browser and greeted by your game. It’s possible you get some warnings, or you have to remove some additional comments in game.ts. You can developer your game while running this command, and your game will automatically refresh when it is modified.

Getting Assets

Before we can start developing we need some assets we can work with. I prefer not to spend too much time on creating my own assets, at least not in the beginning of a game. I bought the Kenney Bundle, which includes assets for Sokoban. The assets are better than any asset I can produce myself, and I prefer to program over editing in GIMP or Photoshop. But feel free to create your own assets. In the beginning you can even start with simple colored squares that represent in-game objects.

In order to import the assets into Phaser we create a sprite sheet. A sprite sheet turns all a set of images into one big image, and tells Phaser how to divide the big image back into the indivual assets. The advantage is that you only need to import one image instead of hundred small images. To this end, we use Texture Packer. They have a nice tutorial how to create spritesheets. Add a smart folder with the Sokoban assets, and export them as a Phaser (JSONHash). I prefer to select trim sprite names, which removes the extension of your individual assets. This means you do not need to worry whether your asset was a .jpg or a .png, or you can even replace them with a different format.

texture packer

Creating a Tile Map

Our Sokoban level can be represented by a tile map. Tile maps are perfect for topdown maps for many oldschool games such as Bomberman, Pacman, and also Sokoban. Tiled is a free tile map editor that is easy to use and comes with a wide series of features. Install Tiled, and create a new tile map. Next, import our sprite sheet that we previously created. Make sure to select “embed spritesheet” and not save it as a separate file. Finally, draw a map and export it as a json file. Save everything into your assets directory of our project.

tiled image

Getting Everything in Phaser

Let’s try to get everything in Phaser. We start by cleaning up the last parts of the skeleton project. Remove everything in assets (except for our own stuff). Then let’s import our map. Let’s edit mainScene.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export class MainScene extends Phaser.Scene {
private tileSet: Phaser.Tilemaps.Tileset;
private tileMap: Phaser.Tilemaps.Tilemap;

constructor() {
super({
key: "MainScene"
});
}

preload(): void {
this.load.atlas('assets', './assets/assets.png', './assets/assets.json');
this.load.tilemapTiledJSON('level', `./assets/levels/level.json`);
}

create(): void {
this.tileMap = this.make.tilemap({ key: 'level' });
this.tileSet = this.tileMap.addTilesetImage('assets');
this.tileMap.createStaticLayer('Tile Layer 1', this.tileSet, x, y);
}
}

In our preload() function we load our spritesheet and tiled map. In the create() function we create the actual objects. When we start our application again we should see our tilemap, although not much interesting will be happening.

Conclusion

In this episode we installed and set up Phaser 3 with Typescript. We used an available template project that handles most of the setup for us. Next, we created (well… bought) and imported assets that we will use for the rest of our game. In the next episode we will convert our tilemap into actual game objects that can move.