Sine Shooter (Global Game Jam)


Intro

This past weekend I once again collaborated with the talented Brent Mitchell for the 48 hour Global Game Jam. The theme this year was Waves.

This jam was quite different than our past collaborations because we worked remotely from each other. We then decided to make it more difficult for ourselves by making a virtual reality game, which only Brent has the hardware (HTC Vive) for currently. And to top it off we also decided to keep up our trend of making multiplayer games! So this was one heck of a challenging game jam for us, but we are quite happy with the results!

VR player view, with Vive controllers used to aim & shoot guns in both hands at AI enemies.

Friday

Friday night we made our design decisions, but this year we kept them vague. We only knew we were making an FPS in VR where enemies and the environment would spawn in waves. For multiplayer, a second non-VR player would be able to view the map from a bird's eye perspective and affect gameplay somehow. While this was intended to be played offline on a single computer, we did not have that luxury since we worked remotely from each other. So we wanted multiplayer to have an optional online component which would allow us to test gameplay together. Brent went ahead creating the gameplay while I worked on multiplayer and UI functionality.

A rather unique part of the gameplay is when the VR player moves around they see buildings, walls, and other obstacles generate across the map periodically in a wave. This is neat because you may be ducking behind cover only to find it disappear and leave you wide open for attack. Alternatively you may be chasing down an enemy AI and find yourself inside a building that just popped up. There was a brief concern about AI pathfinding since the map was dynamic, but Unity's nav mesh handled this no problem. The only limitation was not being able to have dynamically created objects which the AI could move on, such as a ramp or staircase.

Player movement was accomplished using a nifty Unity package called Arm Swinger. You literally just swing your arms as if you're running and the player moves forward. Feels awesome, works well, and we highly recommend using it in your VR game.

VR player view, being chased and shot at by the enemy AI.

I decided to give Unity's new multiplayer service (UNet) a try. I had extensively used their legacy multiplayer service, but UNet is more robust and a major departure from their legacy system. I've also used Photon networking with a few games in the past and I highly recommend it! But I was looking to learn something new and figured it couldn't hurt to try UNet.

It was difficult to find a list of UNet features, which I wanted to see to verify it would suit our needs. The service website doesn't break down this information and the multiplayer dashboard offers very little. My local (up-to-date) Unity docs offered different info than the live docs too; I recommend using the live documentation. If you're searching for that info, the Unity Manual for Multiplayer and Networking is what you want. Take note the docs start by mentioning three approaches to integrate UNet:

  • using NetworkManagerHUD. (simplest, requires no scripting)
  • using NetworkServer and NetworkClient. (high-level, simpler scripting)
  • using NetworkTransport directly. (low-Level, more complex scripting)
TANKS! Networking Demo, created by Unity Technologies.

If you like to learn by example then I recommend checking out Unity's TANKS! Networking Demo. You can see UNet in action, complete with a robust lobby system using the high-level methods. I found it difficult to understand how some features were being accomplished, as much of the functionality is hidden within the Network Manager Component. Unfortunately the documentation heavily references using Network Manager, to the point where it seems to just assume you're always using it. I concluded that most games will want to go beyond the flexibilities of the as-is Network Manager and will require understanding how to override its functionality or build their own entirely.

Saturday

On Saturday I decided to use UNet's high-level methods since I expected it to be the most similar to Photon and their legacy service. I made long strides with this and was able to catch up to Brent's gameplay mechanics. Once the multiplayer code was merged into the project it became apparent that RPC calls aren't as offline-friendly in UNet as they were in the legacy system or Photon. For example, if an RPC method is called while offline, an error will occur and the method is not called. In Photon and the legacy multiplayer service you could build a game for offline and online and not have to worry too much about checking networking. So with UNet I found myself writing 3 methods for networked functions; the main method which checked connectivity, and then the offline and online (RPC) methods which are called by the main method. There is likely a better solution to handle offline/online functionality, but in the heat of the moment during the jam this was my approach.

void PressWeaponTrigger (bool isLeftHand)
{
    if (NetworkMode.IsOnline()) {
        CmdPressWeaponTrigger(isLeftHand);
    } else {
        DoPressWeaponTrigger(isLeftHand);
    }
}

[Command]
void CmdPressWeaponTrigger (bool isLeftHand)
{
    DoPressWeaponTrigger(isLeftHand);
}

void DoPressWeaponTrigger (bool isLeftHand)
{
    var weapon = isLeftHand ? equippedLeftWeapon : equippedRightWeapon;

    if (weapon != null) {
        weapon.TriggerPressed();
    }
}

I finished the networking code but several aspects of it remains untested since testing was difficult and time consuming. We decided it was more important to get the core of the game built so we would have something to show off Sunday afternoon. I created UI menus for selecting single or two player modes, offline or online.

Sunday

On Sunday I focused on the non-VR player experience (second player). While it wasn't shaping up to be what we originally envisioned, I figured we might as well have them do something. So I created the bird's eye camera view, added visuals to the VR player which could only be seen from above, and gave the non-VR player the ability to click on the VR player. Since there was little time remaining I tapped into the health system Brent had created and made it so clicking the VR player made their health go down. Then I made it so when the VR player defeats an enemy, they gain health. This created some urgency to the VR player's experience, encouraging them to defeat enemies quickly.

Non-VR view used by player 2 on the PC, controlling with mouse. Red sphere represents VR player.

The last thing I worked on was adding a health UI in-world for the VR player to see. After some quick experimenting it seemed best to put the health meter right on the back of the guns. This was the first time I had used uGUI to make a world-space UI, and it was incredibly simple.

Some interesting questions arrised throughout our development. Since we were using one computer for both a VR player and a keyboard/mouse user, we encountered issues such as having multiple audio listeners. After thinking about it, any Unity-made VR game we've played which used this same two player setup often just had music or ambience for the computer player. Not having two audio listeners prevents one of the players from hearing sounds unique to their own experience. Another issue, which was quickly solved, is how Unity by default shows the VR player's camera view in the editor while playing. You can fix this by setting the Target Eye property on the non-VR camera to be the main screen.

Conclusions

I haven't given UNet enough of a chance yet, but my first impression is that Photon networking is simpler to use and can accomplish just as much or more. Multiplayer VR is fun, as is mixing it with non-VR players, but be prepared to face new technical challenges and constraints. And finally, it's not the best idea to work on a VR game without a VR rig, especially during a game jam!

You can download the game for Windows only. It requires the HTC Vive or Oculus Rift with motion controllers.