01. Improve the HTML5 game experience
Converting a game to another platform is an excellent opportunity to improve it, fix its issues and increase the audience. Below are few things that can be easily done and are worth considering:
- Supporting mobile devices
- Improving performance
- Fixing bugs and making improvements to the gameplay
Having new developers looking into game's source code can help to fix known bugs or discover new and very rare ones. This would make playing the game less irritating for the players, which would make them spend more time on your site and encourage them to try your other games.
- Adding web analytics
In addition to tracking the traffic, web analytics can also be used to gather knowledge on how players behave in a game and where they get stuck during gameplay.
- Adding localisation
This would increase the audience and is important for kids from other countries playing your game. Or maybe your game is not in English and you want to support that language?
02. Achieve 60 FPS
Non-interactive GUI elements, such as health bars, ammo bars or score counters can be easily implemented in Phaser by using regular images (the 'Phaser.Image' class), leveraging the '.crop' property for trimming and the 'Phaser.Text' class for simple text labels.
Interactive elements such as buttons and checkboxes can be implemented by using the built-in 'Phaser.Button' class. Other, more complex elements can be composed of different simple types, like groups, images, buttons and text labels.
03. Loading custom fonts
If you want to render text with a custom vector font (eg TTF or OTF), then you need to ensure that the font has already been loaded by the browser before rendering any text. Phaser v2.6 doesn't provide a solution for this purpose, but another library can be used – Web Font Loader.
Assuming that you have a font file and include the Web Font Loader in your page, then below is a simple example of how to load a font. Make a simple CSS file that will be loaded by Web Font Loader (you don't need to include it in your HTML):
Now define a global variable named WebFontConfig. Something as simple as this will usually suffice:
Remember to put your code in the 'active' callback shown above. And that's it!
04. Save the game
Saving data is very simple:
Note that in the above example the 'progress' variable, which is a number, will be converted to a string.
Loading is simple too, but remember that retrieved values will be strings or null if they don't exist.
Here we're ensuring that the return value is a number. If it doesn't exist, then 0 will be assigned to the 'progress' variable.
You can also store and retrieve more complex structures, for example, JSON:
There are some cases when the 'localStorage' object won't be available. For example, when using the file:// protocol or when a page is loaded in a private window. You can use the 'try and catch' statement to ensure your code will both continue working and use default values, which is shown in the example below:
Another thing to remember is that the stored data is saved per domain, not per URL. So if there is a risk that many games are hosted on a single domain, then it's better to use a prefix (namespace) when saving. In the example above, 'myGame.' is a prefix and you usually want to replace it with the name of the game.
If your game is embedded in an iframe, then localStorage won't persist on iOS. In this case, you would need to store data in the parent iframe instead.
05. Default fragment shader
When Phaser and PixiJS render your sprites, they use a simple internal fragment shader. It doesn't have many features because it's tailored for speed. However, you can replace that shader for your purposes. For example, you can leverage it to inspect overdraw or support more features for rendering. Below is an example of how to supply your own default fragment shader to Phaser v2.
06. Change tinting method
A custom default shader can be used to replace default tinting methods in Phaser and PixiJS. Tinting in Phaser and PixiJS works by multiplying texture pixels by a given colour. Multiplication always darkens colours, which obviously is not a problem; it's simply different from the Flash tinting. For one of our games we needed to implement tinting similar to Flash and decided that a custom default shader could be used. Below is an example of such a fragment shader:
This shader lightens pixels by adding a base colour to the tint one. For this to work, you need to supply negatives of the colour you want. Therefore, in order to get white, you need to set:
07. Inspect overdraw
Replacing a default shader can also be leveraged to help with debugging. Below we've explained how overdraw can be detected with such a shader.
Overdrawing happens when many or all pixels on the screen are rendered multiple times. For example, many objects taking the same place and being rendered one over another. How many pixels a GPU can render per second is described as fill rate. Modern desktop GPUs have excessive fill rate for usual 2D purposes, but mobile ones are a lot slower.
There is a simple method of finding out how many times each pixel on the screen is written by replacing the default global fragment shader in PixiJS and Phaser with this one:
This shader lightens pixels that are being processed. The number 7.0 indicates how many writes are needed to turn pixels white; you can tune this number to your liking. In other words, lighter pixels on screen were written several times, and white pixels were written at least seven times.
This shader also helps to find both 'invisible' objects that for some reason are still rendered, and sprites that have excessive transparent areas around that need to be stripped (GPU still needs to process transparent pixels in your textures).
08. Why physics engines are your friends
A physics engine is a middleware that's responsible for simulating physics bodies (usually rigid body dynamics) and their collisions. Physics engines simulate 2D or 3D spaces, but not both. A typical physics engine will provide:
- Object movement by setting velocities, accelerations, joints, and motors;
- Detecting collisions between various shape types;
- Calculating collision responses, i.e. how two objects should react when they collide.
There is a Phaser plugin that works well for this purpose. Box2D is also used in the Unity game engine and GameMaker Studio 2.
While a physics engine will speed up your development, there is a price you'll have to pay: reduced runtime performance. Detecting collisions and calculating responses is a CPU-intensive task. You may be limited to several dozen dynamic objects in a scene on mobile phones or face degraded performance, as well as reduced frame rate deep below 60 FPS.
09. Export sounds
If you have a Flash game sound effects inside of a .fla file, then exporting them from GUI is not possible (at least not in Adobe Animate CC 2017) due to the lack of menu options serving this purpose. But there is another solution – a dedicated script that does just that:
How to use the script to export sound files:
- Save the code above as a .jsfl file on your computer.
- Open a .fla file with Adobe Animate.
- Select Commands > Run Command from the top menu and select the script in the dialogue that opens.
- Now another dialogue file pops up for selecting the export destination directory.
It's done! You should now have WAV files in the specified directory. What's left to do is convert them to, for example, MP3, OGG or AAC.
10. How to use MP3s
The good old MP3 format is back, as some patents have expired and now every browser can decode and play MP3s. This makes development a bit easier, since finally there's no need to prepare two separate audio formats. Previously you needed, for instance, OGG and AAC files, while now MP3 will suffice.
Nonetheless, there are two important things you need to remember about MP3:
- MP3s need to decode after loading, which can be time-consuming, especially on mobile devices. If you see a pause after all your assets have loaded, then it probably means that MP3s are being decoded
- Gaplessly playing looped MP3s is a little problematic. The solution is to use mp3loop, read more in this article posted by Compu Phase.
- 5 casual games for designers
- Build your own WebGL physics game
- Understand the Unity asset import pipeline