I recently acquired an Oculus Rift with Touch controllers to develop some VR games. I have not done any VR development before and as such there is a lot to learn and experiment with. The goal of this project is to get familiar with VR game development by creating a 3D stealth game. For the project, I will be using Unity 3D with the Oculus SDK along with NewtonVR, which is a free library to add simple physics interactions with the environment.
- The player plays as an assassin who is equipped with a silenced pistol and is assigned to take out targets who are protected by a lot of guards.
- The player travels by teleporting around the game level and must attempt to stay in unlit areas, which is most of the game level areas, to avoid detection by guards.
- The levels will be non-linear and the player has several options for which path to take.
Hopefully by the end of this course, there will be a single but good level available.
- The player can temporarily slow time to pull off more interesting and satisfying shots.
Possible difficulties that will be encountered:
- Finding suitable models with necessary animations to act as guards
- Setting up the animations in the game, including applying inverse kinematics to make the guards aim at the player
- Creating a pathfinding system for the AI to patrol around + engage the player if they're seen
- Making the game work with both Oculus Rift and HTC Vive
- A lot of custom models are required and the modelling software I have used previously has turned into a commercial product and since I have no desire to buy it, I will have to learn basic Blender.
Milestone 1 (29.09)
- Get Oculus Rift running with Unity
- Test out NewtonVR
- Find a suitable rigged and animated model for use as an enemy
- Get the enemy ingame with animations and perhaps ragdolling
- Create a basic shootable gun
Setting up Oculus Rift with Unity was surprisingly easy, I didn't even have to install anything particular. All that was required was importing an asset package to Unity, provided by Oculus, and it all started working with the default consumer Oculus application.
Next, I played around a bit with the standard Oculus SDK and made some balls fly forward from the remotes. After that, I installed NewtonVR and messed around with it's demo scene. The demo scene used a bunch of super useful assets such as an openable door, drawers, dual wieldable objects, a gun that shot flowers for some reason and an interactable UI canvas in world space.
Next, I started the search for some models to use as enemies. I didn't feel like playing for assets and as such was hoping to find some free animated humanoids with some fighting and movement animations, which was a bit of a stretch. I found a Unity package with some animated humanoids with a bunch of fighting animations: https://www.assetstore.unity3d.com/en/#!/content/76699. I added these to the game and to make shooting them more fun, I also generated ragdolls for them, which will turn them into limp sacks when hit by a bullet. Sadly, I soon noticed that the included animations are for fighting only and there are no movement animations at all. Check it out: https://gfycat.com/EvergreenCautiousEwe
On my search for better enemies, I stumbled on the following asset package: https://www.assetstore.unity3d.com/en/#!/content/31711. It's a collection of 4 rigged bodyguards on the same skeleton. Well, that was all great, but I didn't have any animations. Almost by fate, I stumbled upon a website called www.mixamo.com, which lets you upload a rigged character and lets you apply all kinds of animations from it's database to the model for free! It was originally a paid service, but it was acquired by Adobe earlier this year who made the service free, although they also removed a lot of features and the whole old community forum for whatever reason. Well, either way I had a rigged model and over 2000 animations to choose from. I decided I will need 7 animations for now:
- walking while aiming a handgun
- running while aiming a handgun
- standing while aiming a handgun
- walking casually for patrolling
- idling casually for patrol stops
- being on alert but not aiming a gun
- punching for close encounters
The next challenge was actually figuring out how to get them to work properly in Unity. This took several hours of trial and error of different mixamo export settings and Unity import settings but I finally had a simple guard with an idle animation working.
Milestone 2 (13.10)
- Have some basic pathfinding for the guards - avoid obstacles, walk around a patrol route
- Animate the guards walking/stopping while patrolling
- Apply inverse kinematics to the guards when they see the player - they should stop and aim their hands at the player.
- Create a more interesting scene for testing.
I started by generating a nav mesh for the test level and started learning how to use navmeshagents, with which I had very little experience. After a little while, I managed to have a nice little dynamic system where you can add a list of transforms to a guard and he'll walk around following the path. However, this didn't want to work very well at first and bugs were expected... https://gfycat.com/PlaintiveDeficientHogget. After some ragdolling and animation tweaks, I finally had patrolling guards who can be shot and properly ragdolled: https://gfycat.com/DisguisedPepperyJerboa.
Animating the guards was a whole another can of worms. For animating, I used the Unity's animator controller which was relatively new to me in the capacity I needed it for this project but after a while it was working pretty well for transforming between idling, walking and standing with a gun. The AI was programmed to just follow a path if there is one and if player gets inside the guard's view cone and a ray cast from guards eyes intersects the player without obstructions, the guard will turn towards the player and move to the aiming pose.
My next big goal was to try to apply inverse kinematics(IK) to the guards, otherwise they wouldn't be able to look at the player and point their gun at the player. This took a lot of work, because animations exported from Mixamo were of type 'generic', while Unity currently only supports IK on models of type humanoid. Well, our guards were humanoids and Unity offers an option to convert generic animations to humanoid animations, which I did. This however broke the animations pretty badly - the rotations were wrong and some limbs were wrongly placed and the animations looked kind of funky overall. For example, the "standing with gun" animation looked like this after the conversion:
I will look into it more in milestone 3 and if nothing works, just go with generic animations with no IK.
Next, the current test scene was boring me, so I decided to brush up on my modelling skills and created a simple house and added some more barricades to the test scene. This house can be seen in the gif in the next milestone. I also sketched a few ideas for the first level of the game. It's a big backyard of a mansion with a seashore and the player has to work their way from the dock to the mansion to assassinate a target.
Milestone 3 (27.10)
- Work on game design to give it some character
- Get inverse kinematics to work
- Add guns to enemies
- Add a way for locomotion
Actual work done
For a change, I spent some time sketching the first level of the game and thinking of an art style. Since this is a small game, I decided to take a minimal approach and spend less time on asset creation. Firstly, since it is a stealth game, I picked a nice looking night skybox for the level and plan on making all the gameplay take place during night. Secondly, I picked 3 main colors I will be using. They're all various shades of purple and blue and look kinda neat in my opinion. I won't upload a sketch of the first level yet, because I will hopefully have most of it modelled already by milestone 4. Meanwhile, the color scheme can be seen in the action in the gif in the last chapter!
I looked over inverse kinematics again and finally found the right Mixamo export and right Unity import settings so the animations worked some-what properly enough! I then created a system that makes the guards point directly at the player and turn their heads at the player. Here it is in action: https://gfycat.com/ComplicatedSmoggyIsabellineshrike and https://gfycat.com/MeekTornDogfish
To make enemies more interesting, I added guns to them. It is currently just a pistol parented to their hand and carefully calibrated to point at the player and play a gun shot sound when shot. The player doesn't take any damage just yet though.
For locomotion I looked around for existing solutions. It was apparent really quickly that allowing the player to move directly is a big no-no and causes a lot of motion sickness. The next clear solution was to use a teleporter like a lot of other VR games do. However, in the game you can move to high surfaces which are above yourself and out of sight. As such, just a normal point and teleport method wouldn't work, because your aim point could not be on a surface that you can not see. To solve this, I decided to use a commonly used arc teleporter which basically creates an arc to the place you want to teleport, which can also be on top of a surface you can't see. Writing this from scratch seemed pointless, because it's quite a common feature in VR games and surely there must be a solution out there. After some searching, I found VRTK, a free VR toolkit on github with a lot of different examples. However it had a big flaw - it combined like 50 different demoes and all these demos shared a lot of classes, which led to a lot of redundancy in the code and made everything about 3 times harder to understand than necessary. After a while, I was able to extract the relevant parts and wrote my own teleporter. Here it is in all it's (early) glory, including the new theme for the game: https://gfycat.com/EarlyHighlevelCalf
Milestone 4 (10.11)
- Add rotation ability to the teleporter
- Model some of the level
- Add melee combat
- Add a silenced gun
Actual work done
In the old version, the player could teleport around but the world forward axis never changed. This was problematic since while using a 180 degree VR setup it made it effectively impossible to properly turn around with proper tracking. To solve this, I added an indicator to the teleporter which can be rotated to also change the world forward, which works quite well and seemed to be intuitive enough to use.
I modelled some of the level. Here is a picture of the model from top down:
and here it is ingame:
Next, I added melee combat to the game. Basically you can either punch the enemies or just throw guns at them to knock them out. A relatively simple feature but also very-very fun!
Lastly, up until this point, the player had a normal handgun, which really didn't work very well in a stealth setting. As such, I found a nice sounding silenced pistol sound, added a silencer to the pistol and now it's even more fun to shoot the bad guys.
There are no gifs in this milestone, but since I basically completed milestone 4 and 5 in a row, there is a longer video in milestone 5 that covers all the new awesome features of both milestones.
Milestone 5 (24.11)
- Rework the enemy AI
- Rework the enemy animations
- Add disarming the enemies
Actual work done
In this milestone, I worked a lot on enemy AI. Firstly, I improved the way their sight system works. For example, the enemies don't detect you instantly but require about 500ms of clear sight to notice you. Also, I integrated a lot more states to the AI compared to before (idle, casual walk, stand aiming). The new states include walking towards the player while aiming and being on alert when the player is not seen. I decided not to add running and punching yet, because walking enemies were challenging enough for a start. Next, I upgraded the enemy weapons to actual interactable objects, meaning that if the player got close enough, they could grab the weapon from the enemy and blast them with their own gun. To make enemies more aware of surroundings, enemies now react to the player moving quickly (with either hands or head) in a 1m radius and silenced gunshots in a 10m radius and normal gunshots in a 20m radius. Also, the pathfinding was upgraded in such a way that now guard paths can have stops for a certain period. There are now like 10 guards patrolling around, hoping to stop you. When the guards lose track of you, they will move to your last known position and look around, hoping to spot you.
I also added some new props to the level. But enough talk is enough, let's take a look at this in live action:
Milestone 6 (08.12)
- Add time slowing mechanic
- Make the player able to lose/win
- Improve the level so playing is more challenging
Actual work done
- I decided not to add a time slowing mechanic after all since the game was plenty of fun without it.
- I decided not to implement the whole keycard thing with cameras like in MS4, since it wouldn't add too much to the experience. The player will now win the game if they kill all the enemies and lose if they get shot. There's a counter for enemies left to let players track their progress. There's also a button to toggle invincibility to just explore around the level.
- I added a few new rooms to the level with more enemies.
- I implemented 3 new weapons - a unsilenced and silenced UZI and a shotgun, which are all loads of fun to use.
- Since writing the milestone 6 goals back in September, I've played a lot of VR games and learned some dos and don'ts that I didn't implement earlier. As such, I changed the way teleportation and rotation works. Before, it was coupled into 1 action - hold teleport button, turn joystick to choose the desired rotation. This was not very intuitive to use and was cumbersome. As such, it is now decoupled into 2 actions - a button can be held to teleport to a specific place and the joystick can be used at any time to turn by 45 degrees.
- Additionally, the player will now be actually teleported to the chosen point. Before, the room center was set to the teleportation point but if the player was on the edge of the room, it caused confusion. Similarly, when rotating, the player is rotated around their own up axis, not the center of the room up axis.
- Enemy AI is now smarter - if a bullet flies past them at a reasonable distance, they'll notice it and start looking for the player.
- Added a sound that plays when the player is detected by an enemy.