Z Mission was the game my team developed during one of InnoGames game jams about 1 year and a half ago. It was a simple puzzle game with zombies, with the goal for the player to get out of wherever he is by evading zombies and luring them out of the way and trapping them behind doors. We used the at the time latest version of Rayne as game engine and while I didn't bring a VR headset to the game jam, we did develop it with VR in mind.

When Oculus released the Oculus GO a bit later that year I wanted to prepare Rayne for the Oculus Quest by remaking Z Mission as Project Z for the GO, which just like the Quest uses Android. I thought I could turn this into a full little game within maybe 4 - 6 months, as always that estimate was very wrong :).

This was also a good opportunity to get the Vulkan renderer working and to feature parity with my Metal and D3D12 rendering. But because of just a few random hints of the GO getting support for Vulkan but no actual support yet, I started out implementing it on Windows first which worked out quite alright. I am sure there are a lot of things that can still be optimized and some I already improved and I am not taking advantage of multithreading in the renderer yet, but most things are just very similar to D3D12 but with more consistent naming. The one big annoying thing with Vulkan is shader compiling. Because while it is of course possible to include a shader to spirv compiler in the engine, it's not exactly part of Vulkan which just wants spirv memory blobs. With my system of having an Übershader and enabling features by recompiling it with different defines turned on, this was a problem. As a result I ended up writing and assigning specialized shaders that I precompiled by hand (using a spirv compiler obviously). Which was turning into a lot of work to maintain... I solved this recently by automating the process of having one HLSL shader that gets recompiled for all possible permutations for the 3 different rendering APIs (more about that in another post maybe).

While the Vulkan rendering was starting to work decently what I really wanted was making it work on the GO.

First I tried the Vulkan samples for android on the GO. They just worked which was a good start, but because there was no support for the Oculus SDK it didn't do anything VR and was just using the GO as a single screen and not using any of the sensor data. This gave me some hope on finding a workaround so I started porting the engine to android. It took a day or two until it was all kinda working. But still no VR.

Looking at the available Vulkan extensions it turned out that there was some functionality to share memory to OpenGL ES 3.0. I did get this to render into an OpenGL surface, but the Oculus SDK wants to handle the swap chain textures for me which somehow ended up complicating things more than I wanted to.

Around the same time or maybe earlier, Oculus released experimental Vulkan support for Unreal on GO. Turns out it was part of their latest SDK release at the time but they didn't include any headers yet. After a day of scraping the symbols for it and trying to turn it into something that would work, I gave up and contacted their developer support. As a member of their Oculus Start developer program I am entitled to special developer support and apparently these support tickets are very useful. A day later they got me in contact with the developer who was actually implementing the Vulkan support and I got all the headers and information I needed (which became part of one of their SDK releases a month or two later).

Their Vulkan support seems to be using the same shared memory technique I was trying to use, but as it's implemented on their end it allows them to copy less data around then I would have had to do. Anyway the result was fully working Vulkan support on the GO! BUT performance with MSAA was very bad and there is no support for fixed foveated rendering with Vulkan. Also no debugging tools have been working for Vulkan at that time. I decided to just accept those problems and carry on with what I had.

0:00
/0:39

I created a first set of levels and had some friends and family try it, but it turned out to be too hard and frustrating, so I came up with even easier first levels and only very slowly making it more complicated. Not being good at level building slowed my efforts down a lot. I considered making a simple editor for these levels a couple of times but always decided to just go with blender as my requirements were very low. I am definitely regretting this decision now as it would have improved my productivity a lot and gotten me more and better levels in the end. Maybe even an editor to include in the game for users to create even more levels. Anyway, my motivation to create more levels was very low (and still is).

A month or two later I went to Oculus Connect 5, the Oculus developer conference to spectate Echo Arena, talk to some Oculus developer support people and watch some talks. I scheduled a support session (and included the things I wanted to talk about), but when I went there most of them were gone and nobody specific to my problems was around (mostly MSAA, but also some other things). The guy I talked to did write down my email and said he'd get back with some answers (but never did). Fortunately when I was just about to leave someone else came in who had some ideas about why my MSAA was being slow (I reused a quite big render target that could fit both eyes and while it didn't seem like it was fully resolved twice, he said it there may be an unresolve pass before the second eye renders which can be very slow. Anyway I eventually split it into two eyes, which improved performance a lot) and were to find someone else that could help me who was just doing a talk. I went to see most of that talk and then talked to him. He mostly just confirmed things I already new, but maybe he remembered me when they made RenderDoc work with Vulkan on GO earlier this year.

When a friend asked me about Linux, I updated the Linux support Rayne used to have and also tried to make the game work with SteamVR on linux, but it kept causing a random crash, so eventually I gave up (may get back to it in the future). While very slowly working on the first 10 of the 15-20 levels I wanted to have, I also started updating a UI module that Sidney started a few years ago and made it work with in game textures. It's using Skia, which is a UI library from google, which was or still is used on android and for Chrome some way and it has a CPU, OpenGL and Vulkan backend for the rendering. It's somewhat low level, but has basic text rendering and can do all kind of shapes and images. For simplicity I am using it's CPU rendering, which after some performance issues with transfering the data to the GPU has been fast enough for what I need. I initially wanted to implement my own fully hardware accelerated vector rendering, but just getting the data prepared for it seemed like a lot of work.

0:00
/0:38

The levels were still the thing holding me back and I spent some time on prototyping other projects:

  • A multiplayer boxing game with a multiplayer audience that could walk and talk outside of the ring and sign up for matches which would then teleport them into the ring when ready. It's ugly, very limited, but a decent proof of concept based on the code I already had for Swords.
  • An asymmetrical multiplayer horror game for VR, which I intend to spend more time on after finishing Project Z.

But because I really want to eventually finish Project Z and release it mostly for GO, but also for other VR headsets before really working on something new, I started posting requests for someone to help me create good looking levels for the game based on the levels I already had. Eventually I found someone who agreed to make them for the low price I was willing to pay. He eventually gave up but gave me a very high quality base to work with, but I ended up putting most of it together myself and baking the lights and everything. The actual modeling and texturing work he did do was very good.

Now I am stuck with levels again. I did finish putting together those first 10 levels I had and decided to only do 4 more levels which I also put together already but with some flaws I want to fix. Which is again slowing me down as I am too much of perfectionist apparently... Not in terms of making the game perfect, but in terms of fixing overlapping polygons, small holes in the geometry and getting the shading just right without too many artifacts.

And some more information about the game itself:

  • There are 4 different Zombie types: A melee zombie, a ranged attack zombie, a zombie that can break through doors and a zombie that attacks other zombies as well as the player and also gets attacked by them if too close.
  • There will be 14 levels, most very short, some bigger and harder though.
  • I do intend to change the Zombie model and recently implemented the animation system I had in old Rayne into the new Rayne. As a result zombies can be animated now.
  • Total play time for a first playthrough is probably gonna be a bit more than an hour (I can do it in 10-15mins).
  • Zombies may or may not end up glowing in the end, it doesn't look great but it tells the player where they are and makes the game less frustrating.
  • There are some quite useless stats shown in the menu for each level such as total number of deaths and fastest time (all for local player only, stored on device).
  • I intend to sell the game for 4.99€ on all platforms.
  • It's currently not taking advantage of positionally tracked controllers as grabbing door handles and pulling/pushing them takes a lot longer than just getting close to a door and pressing a button and would make the game a lot harder.

I hope to get it released before halloween.