Previous Phaser tutorials:
Phaser tutorial: DronShooter - simple game in Typescript - Part 1
Phaser tutorial: custom easing functions for tweening and easing functions with parameters
Phaser tutorial: sprites and custom properties for atlas frames
Phaser tutorial: manage different screen sizes
Phaser tutorial: How to wrap bitmap text
If you ever tackle with menus for your game you know the problem: you need lot of boxes similar in appearance, but different in size. These boxes are usually large in size and storing them all in all needed sizes is just wasting precious space. You can store menu box in one size and then stretch it, but this is not solution as stretched images may not look good. More, your menu box may have some borders and you want to keep them unstretched.
This is where 9-patch images comes to help you. 9-patch image is image that is split with two horizontal and vertical lines into grid with 9 cells. When you need to draw big rectangular box, parts are repeated many times instead of stretching:
As you see, there must be some additional data for computer to know, how wide is left, right part or how high is top and bottom part. Solutions are:
- fixed amount in pixels inside engine that support 9-images. Not flexible at all,
- some metadata drawn directly into image. This is for example Android approach,
- store these data along with other sprite data. This is Unity 9-sliced image, where data are stored in sprite border,
- provide data at runtime - this is approach I used.
As there is no built-in support for 9-images in Phaser, I had to code it myself. Here are examples of achieved results (graphics is taken from our Shards - the Brick Breaker and Deadly Abyss 2 games):
I wanted to make my future class for 9-images flexible, so I decided it can be called with:
- target size of box on screen and code will calculate and draw number of repeats to fit into,
- requested number of repeats of central part of 9-image horizontally and vertically (imagine famous Windows Mines clone with various grid sizes and border around it - how easy to paint board with 9-image like this!)
My first attempt was to create Typescript class that derives from Phaser.Group and contains as many sprites as necessary to fill requested box dimensions. I passed texture frame to it along with 9-image metadata and class did everything for me. This everything means:
- it created additional atlas frames for all 9 parts,
- it calculated width and height of last central part, which may not be draw fully,
- it created lot of sprites to cover requested area with 9-image parts (croping it where necessary)
So far all ok. But problems started when I wanted to scale it like:
It may seem strange: why scaling when we just created 9-image to prevent stretching? But imagine you want to animate your 9-image and let it pop for example. The problem was that there were visual artifacts between individual 9-image parts. Very noticeable and ugly. I did not managed to remove it at any cost.
Hard way with better results
But, hey! Phaser has TileMap support. There must be the same problem when scaled. No, everything there was OK. So I dived into source and found that TileMapLayer is drawn with 1 x 1 scale into canvas. This canvas is then turned into texture and this texture is then drawn on the screen. If any scaling is required, it is done with texture so there are no rounding / interpolation problems between tiles.
From Phaser 2.3.0 it is using component model, where each gameobject is very simple by itself, but it is enriched with components on engine start. So, I decided to create my own Phaser gameobject and do it similarly to TileMapLayer: I will create texture with menu box from 9-image.
I am usually working in Typescript, but unfortunately, I did not find a way how to work with Phaser components in it. I will be very glad if someone knows and can provide example...
Complete listing of nineimage.js source is in the bottom. It works great as you can see from this live example:
This is minimal example how to use new 9-image gameobject:
Call to new NineImage object has these parameters:
- x and y position of top left corner,
- width and height - either in pixels or number of repeats of central part of 9-image (see last parameter),
- key and frame,
- top, left, bottom, right - borders of 9-image in pixels,
- repeats - how to interpret width and height. True = repeats of central part
I am very happy with the result. I am not 100% sure, whether I did everything OK, as this was first time I created new Phaser gameobject. But it works and created objects also responds to things like anchors! Now, it is time to place some text on it. If you are using Phaser's BitmapText, you know, that it lacks wrapping feature. You can use my TextWrapper class that does this (more, it also splits long text into several pages, you can then easily list!!!)
Here is full listing of nineimage.js source: