This is a write-up of the creation of my WebXR game, Get Back From Robot City, for JS13K 2019 competition.
I liked the idea of creating an environment large enough that you needed to move around and explore whether this was in first-person or controlling a third-person character.
My first idea was controlling a third-person character, helping them move back down a mountain, avoiding or interacting with obstacles along the way. My main concern was how I would go about making this as immersive as possible while keeping within the 13KB limit. In the end I to make a first-person game and focus on making this as immersive and as easy to control as possible.
Last year I created an escape-room game, but this year I wanted to create a game that you may want to come back and play a number of times. In order to make the game replayable the layout is based on a 7x7 grid and buildings and robots are assigned to random tiles within this grid. I also added easy, medium and difficult game modes to help increase replayability.
The main thing I needed to make sure of is that you couldn’t get blocked in by a poor positioning of buildings. I worked around this by keeping a separate array of tiles which needed to be kept clear. Each time a building is added, the tile adjacent to the door is added to the keep-clear array.
The final game idea is a relatively simple take on the theme for this year — “BACK”, but hopefully the concept is clear enough so people can understand and start playing the game fairly quickly.
I have recently been using Babylon.js for a work project (non-VR), and I have been impressed by its flexibility and performance. I did some tests in VR but I could only get it working in Firefox Reality by using the pointer-events polyfill that Babylon recommends. Unfortunately, minified and zipped, this came to 5KB, which was just too much of the 13KB budget. I tried some alternative polyfills but I couldn’t get them working successfully. This is something for me to look at in greater detail for next year, but as I wanted to support both Oculus Browser and Firefox Reality I decided against using Babylon this year.
I hadn’t had any previous experience using Three.js, other than through A-Frame, but as I have used A-Frame a number of times I opted to use this in the end. I am always impressed with how easy it is to get started creating VR content with A-Frame and it was a pleasure to use again for this project. I would like to look into Three.js in more detail at some point, whether within A-Frame or standalone.
My primary target platform was the Oculus Go, but I also wanted to make sure the game was playable on desktop, so anyone without a VR device could also get a feel for the game. The keyboard controls are fairly standard, but for VR I decided to give users a choice of how to move around.
As a VR user I am a big fan of being able to teleport around an environment, whether this is to a pre-defined location, or any viable location by selecting a point on the ground. I decided the latter was the best option for my game so you can creep around corners, hide behind buildings etc.
I know teleporting isn’t for everyone, so I have also given users direct control over movement by using the touch-sensitive button to move forwards. This meant I had to implement collision-detection to ensure players can’t move through walls, but as I had to do this for desktop too I could share this code. I did have initial concerns about blocking users movement in VR, but after testing it didn’t feel jarring at all.
I spent quite a bit of time working on performance to make sure the game was comfortable in VR. The first thing I looked at was combining geometries where possible to limit the number of draw calls. At one point I had over 600 draw calls, but in the end this was reduced to well under 100.
I started off with an 11x11 grid, 20 buildings, and 26 robots. This felt too large and I gradually reduced this until we ended up with a 7x7 grid, 12 buildings, and 13 robots. Though I didn’t reduce this primarily for performance reasons, it helped a great deal in this respect.
Most of my textures are generated through canvasses, and I made sure these were as small as possible. It is really just the textures containing text that I had to make larger than I would have liked, everything else is pretty small.
One other thing I aimed to optimise where possible was the component tick functions. By default these fire every frame, but I was able to throttle these to run less often for certain components, e.g. the robot AI.
There was one place where my optimisations didn’t go to plan. The buildings were made from a collection of box geometries. I realised I didn’t need all six sides, so I created a separate box function to create boxes out of 6 planes, and only create the sides I needed. This reduced the number of triangles within the scene considerably, but it actually reduced the frame-rate and increased the load time so I abandoned this idea. I think this is due to the increased number of A-Frame entities and with more time I expect I would have found a more efficient way of doing this. Something to look at for next year.
One other thing I would like to look at for next year is the materials. Three.js has four different types of materials, while A-Frame just uses the Basic (cheapest) and Standard (most expensive) material. I used the basic material where possible but there are several places I could have used a simpler material than the Standard material (e.g. MeshLambert). Maybe this would have improved performance further.
Sounds / Music
I used SoundBox for all music and sounds for the game. The interface looks a bit daunting at first, but I was really pleased with the sounds and the flexibility it offers. And the end file-sizes are pretty small. I realise the background music may not be to everyone’s taste, so I put in an option to switch this on and off at the start of the game.
I asked a few friends and family members to help me test the game. The feedback I received as a result was invaluable. This helped me to decide where I needed to focus my efforts, and also reassure me where things were already working well.
Originally the robots didn’t re-generate, but after three different people all suggested that they should regenerate I took their advice. This made the game both more challenging and more interesting. Sometimes the robots can regenerate right in front of you or behind you, but I feel this adds to the fun of the game.
The final game size is 12.8KB zipped. Last year I didn’t get anywhere near the 13KB limit, so this time I felt I made the most of this. I could have squeezed a bit more in with more time, but I am happy with the final result. I would have liked to put different floors in some of the buildings, and added some features to some of the blank tiles to add more interest. My to-do list for the game is still very long, so maybe I’ll look at doing a post-game version at some point in the future.