The theme lent itself well to various interpretations revolving around the concept of losing and finding something (Not Found), as well as the technical details of the HTTP protocol and status codes.
I had a few ideas for a WebXR game, including:
A Beat Saber-like game, in which the player must hit incoming notes to create the music for the game.
A game in which all the colors or textures are missing, and the player's goal is to bucket-fill the world back to normal.
A platformer in which parts of the level are missing and the player must help the AI-driven character reach the exit by reconstructing the level using a palette of replacement props.
Check out Not Found and An HTTP Story which implement a variation of this idea in a way that I really liked!
ROAR was my second game submitted to js13kGames 2020.
Since we went with the more straight-forward interpretation in Oh No!…, I felt I had the liberty to get a bit more wild with my second game.
One idea that really liked was to treat 404 as the description of the input. 4 buttons on the left, 0 buttons in the middle, and 4 buttons on the right. A hint of this idea made it to Oh No!… too, where the game looks like it's running on a Nintendo DS.
I then thought about mapping this idea to real life: 4 fingers or 4 claws on each hand, and a roaring open mouth breathing fire?
And that's how the core idea for ROAR was born!
Constraints
The size limit of 13 KB zipped was the obvious and the most important constraint. Since I wasn't going to use any of the third-party 3D libraries, my idea had to be simple both in terms of the gameplay and the art direction. This resulted in:
An uncomplicated gameplay loop (search & rescue).
A procedurally generated map.
Just 3 minimal UI screens (title, victory, failure).
Primitive meshes (cube and tetrahedron).
Tiny textures: 8x8 and 16x16 pixels.
Basic sound effects.
Another interesting constraint — and a challenge! — was the fact that there's no DOM nor Canvas 2D in WebXR. All UI in VR must be presented through either meshes or textures.
I couldn't afford either of these approaches due to the size limitation.
I did consider for a moment, however, anchoring elongated cubes as camera's children. Since they'd move together with the player's head, only one side would eve be visible and they could be made to imitate health bars :)
Once I got to implementing the UI, I had so few bytes left that I also didn't want to experiment with creating textures dynamically from a canvas element or SVG.
I ended up building all UI in regular DOM outside the immersive WebXR session.
While in VR, there's no UI at all.
When the win or lose condition is met, the game programmatically exits the immersive mode and shows the appropriate screen to the user.
This surely isn't a good practice in VR. It breaks the immersion and might be surprising to users. It was the best I could have done given the size limits and the fact that I didn't use third-party library.
Early on I decided that ROAR would only target devices capable of 6-degree-of-freedom VR.
In particular, I've only tested ROAR on my Oculus Quest.
It was again due to the fact that I hand rolled my own WebXR support, together with everything else: meshes, shaders, the rendering pipeline, physics, etc. I didn't have any bytes left to add keyboard, mouse, or gamepad controls.
I'm sad about this decision because I knew it has severely limited ROAR's audience.
I still had to include a perspective camera for the title view (which is displayed outside the VR mode). So at least I made it possible for users on desktops and mobile devices to start the game and view the city from a camera rotating above it.
Gameplay
Once I settled on the core idea of playing as a monster laying waste on a city, I started to try to define the core gameplay loop more clearly.
My goal was to emphasize the following themes, which I think work great in VR:
Physics-based gameplay.
Sense of scale.
Grabbing and throwing.
Three major ideas for the core gameplay kept coming back.
Destroy everything with as much energy as you can muster, or within a time limit.
Simple and uncomplicated.
I think it would need to rely on some kind of UI to let you know how well you're doing.
The amount of damage you deal to buildings.
Indicators for combo multipliers.
Timer count-down.
I could probably work around this one with audio cues rather than textual UI.
As I mentioned above, building a UI visible in the VR session would require extra effort and code.
Find something hidden in the city (an egg?) while avoiding getting killed by the missiles.
I liked the simplicity of it, and the fact that it doesn't require a lot of explaining.
Plus, it offers a stub of a narrative: something has been taken away from you and you need to fight to find it back.
In order to make it work, I'd either have to expect the player to have a really large room (so that they can walk around the city freely), or add some kind of locomotion controls.
Survive wave after wave of missile attacks, by avoiding them or destroying them with your hands.
This sounded more action-packed than the search-and-rescue idea.
I'm a big fan of Pistol Whip and the idea of having to dodge the incoming missiles appealed to me a lot.
With grabbing, I could also make it possible to defend against missile by using grabbed buildings as shields, or by throwing them at the missiles.
I experimented with a stationary gameplay in which the player was standing in the middle of the city.
It was a bit disorienting when the missiles where coming from all directions.
Another problem was that the most valuable defensive resource around the player would deplete quite quickly: the buildings!
One idea I had to fix this was to move the player to a new city after they successfully defended from a wave of attacks.
Another idea, which I ended up prototyping, was inspired directly by Pistol Whip: move the player automatically through a city and only spawn missile in front of them.
I thought this would be a lot more fun than it turned out to be.
I think the main reason it didn't click for me was that I wouldn't be able to afford (size-wise) having a catchy soundtrack.
The music and the beat are what makes Pistol Whip and Beatsaber great games.
I also realized that it was taking away the player's focus from exploring the city and laying waste at their own pace.
Destruction is fun!
It's also a great way to showcase the possibilities of WebXR.
I'm glad I prototyped this idea and tested it with other people.
In the end, I decided to focus on the destruction, and add a lightweight narrative to it.
The main innovation in ROAR is that it's a full blown WebXR experience in 13 KB with no dependencies. I felt I would be excused if the gameplay wasn't super innovative.
But it still had to be fun!
For the narrative, I added a simple and tried hook: the "government" kidnapped your baby (called baby-zilla) and hid it somewhere in the city.
I was originally planning have the player search for an egg or something like that.
Michał gave me an idea to reuse the paw blueprints to create a model of a small monster.
I loved it, and created a cage around it to cover up the fact that it only had the paws ;)
When talking about the ideas for the narrative with Michał, we came up with a simple Oh No! test.
Summarize the story in a single sentence starting with Oh No!
The idea for the test came from our other game we made for js13kGames 2020. The title of the game is literally: Oh No! All The Textures Are 404!
The sentence is supposed to tersely explain why the player is doing what they're doing.
The baby-zilla narrative passes the test in flying colors:
Oh No! My baby has been taken away!
Before the baby-zilla idea, the hook was a bit less compelling :)
Oh No! All the buildings are still standing! doesn't have the same ring to it, does it.
Balance
Balancing ROAR consisted mostly of trying out and testing different values.
Many decisions were bound by the rendering performance requirements, which made them easier to make.
Example questions I would ask myself a lot during the development:
How many buildings should there be?
How tall the buildings should be?
How much damage should they withstand?
How often should missiles be launched at the player?
How much health should the player have?
I was struggling a bit with the right balance of the fire breath.
If the fire breath destroyed buildings, then it would be too powerful. The player would be able to just blast their way through the city by breathing fire all the time.
I considered making the fire breath a limited weapon, one which requires some kind of fuel.
I experimented with adding power-ups which would replenish the fuel once collected.
I think it would work quite nice with the auto-movement idea: as the city generates in front of you, new power-ups would appear as well for you to collect.
It was also a way to solve rendering performance problems related to particles through design rather than technology.
The alternative was to make the fire be more of a visual cue than a means of destruction.
But then, is it still fun to use it?
In the end, I found some middle ground.
The fire breath doesn't destroy buildings right away, nor does it blow them away.
It sets them on fire, which lasts for a few seconds, and then is put out.
The fire slowly reduces the lifespan of a building.
A single fire is not enough to destroy a building.
If the lifespan drops to 0, the building is destroyed.
Initially, I naturally assumed that the player should be able to survive a few missile hits.
I.e. the player should have hitpoints.
The UI was a problem again. I wouldn't be able to just show the number of hitpoints left; there's no textual UI in ROAR.
I experimented with a few alternative solutions:
Representing the remaining hitpoints with a colored cube anchored to the camera such that it always stayed visible exactly in the same position relative to the camera.
It would effectively look like an elongated rectangle.
I would scale it according to the player's current health.
Scaling the player down when they were low on health.
I love playing with scale in VR.
The player would shrink down to the street-level as they got hit.
However, this wouldn't work well for a few reasons:
The physics engine assumes equal mass of all entities. The fact that the player would be shrunk would only reflect in how they perceive the world.
They would still be able to grab entire buildings even in the smallest form possible.
The game would get easier the more wounded the player was.
The missiles would have trouble hitting a shrunk player.
They would hit the surrounding buildings first, instead.
It was a really interesting idea, one that I'd like to explore further in the future.
Reducing the saturation of the scene.
The lower on health the player was, the more desaturated the world would be.
At the last hitpoint, the world would be entirely in grayscale.
It was a neat visualization but I felt that it didn't explain well to the player what was going on and why the colors were changing.
The final solution was also the simplest one.
A single missile is enough to kill the player and end the game.
I.e. the player starts with a single hitpoint.
Now the missiles are dangerous enough that the player always has to be aware of where they're coming from.
However, they're infrequent and slow enough to make them fairly easy to avoid or destroy.