Building a Racing Game in Unity
2017-10-31Since I've been learning Unity, I decided it would be a good idea to try to do a simple game project from start to finish. I wanted to have some concrete, achievable goals and a definite schedule to hold myself to. I decided to do a racing game. I figured the actual game itself wasn't as important as just finishing something, so I just picked a racing game because it seemed like it would be pretty easy. I gave myself one month to complete the project, and I set four one-week milestones to keep myself on track.
Week 1: The Basics
My goal for the first week was just to have a single vehicle racing around a single simple track. I decided on a computer theme for the game, so I made the vehicles be hovering computer mice. I tried to create a mouse model in Blender, but that turned out to be a bit harder and more time-consuming than I thought it would be, so I ended up with just the half-finished basic shape.
I spent some time making the vehicle float with a springy motion. I also played with the movement controls a bit to try to find good values for the rate of acceleration and turning. But I'm not happy with the way it feels. I can imagine that getting the controls to feel crisp would require a lot of tweaking.
I created the simplest possible course I could imagine. The ground is just a plane with a texture that I drew. I added some walls to the inside of the course so that you can't ignore the road entirely.
I also implemented the system for counting laps. I did that by placing invisible trigger collision volumes at locations around the course as waypoints. Then I just count the number of times a vehicle hits all the waypoints in the correct order.
Week 2: Multiplayer
The goal for the second week was to add splitscreen multiplayer. Doing splitscreen turned out to be easier than I thought it would be. I didn't even have to bother going to look for a tutorial. Nonetheless, I'm thinking that I might make a tutorial for how to do that, just in case it might be helpful. I spent most of the time for this week on the UI and configuration work needed for multiplayer:
- Adding a menu for choosing the number of players
- Controller and keyboard configuration for two players
- Making the basic game logic work for a variable number of players (e.g. different internal lap counters for each)
- Allowing each player to have a separate heads-up display
Another interesting item from this week was calculating the place/ranking of each player while the race is in progress.
Week 3: AI
The third week goal was to add AI players. When I started the project, I hadn't really given any thought to how I'd accomplish that. But at some point, I happened to stumble across Unity's navigation system, so I decided to give that a try.
It was pretty easy to get the NavMeshAgent to navigate around the course. However, with the AI vehicles being controlled that way, their motion is very mechanical — as if they're on a rail. I wanted the AI players to follow the same movement rules as human players. So rather than letting the NavMeshAgent control the motion, I just used its steeringTarget property to get the coordinates of the next point to drive to and wrote a simple steering algorithm. The algorithm first rotates the vehicle to point it in the right direction, without moving forward. When its orientation is close enough, it simply moves forward at full speed, while continuing to make smaller steering corrections. This algorithm isn't great, but it's sufficient to allow the AI to complete the course in a reasonable amount of time without getting stuck.
Week 4: Items
My goal for the final week was to add some basic items/power-ups to the course. I wanted to add boost pads and also a single collectible item. Getting the boost pads working was easy. I placed them just slightly above the ground and then used a downward raycast to determine whether the center of the vehicle was directly above the pad. If so, I just increased the vehicle's thrust.
The usable item I added is something I'm calling the "overload bolt". You pick it up and then you can fire it at the other player. If it hits them, it causes them to lose all power (thrust, steering, and floating) for a couple seconds.
I used the leftover time for the week to play with the lighting in the scene. I made everything darker, added a light beneath each vehicle, and made the overload bolt and boost pads glow a bit. Those lighting changes just made things a bit more visible and allowed me to use those lights to provide some visual feedback to the player.
Release
I'm releasing the game on itch.io. It's a distribution platform targeted at allowing developers to easily share their projects with each other, without the expectation that those projects are necessarily finished or polished. This game is certainly not polished, and not really even fun to play. But I'm releasing it anyway just for the experience of doing it and to give the project some closure so I can move on to the next one.
What I Learned
The whole point of building this game, of course, was for me to learn more about game development. And I've definitely learned a lot over the past month.
At the beginning of the month, I barely knew anything about Unity's UI system. I knew how to display text, but that was about it. Now I've learned enough to create buttons, menus, and more sophisticated dynamic layouts. I spent a fair bit of time just on creating the UI for this game, but hopefully I'll be able to do that much faster next time. I think having some basic UI like a main menu and a pause menu really makes a project feel more finished, even if that UI isn't very pretty.
Another important lesson for me was the degree to which multiplayer complicates things. The fact that it makes things more difficult is obvious, of course, but it was still instructive to see firsthand just how much it complicated things. If you count creating the AI players, I probably spent about half of my time for the whole project on multiplayer.
I think possibly the most important thing I've learned this week is that I can successfully set schedules for myself. And, crucially, that I can stick to those schedules and get quite a bit done. I look forward to doing another project and seeing how far I can get with that, now that I have a bit more experience.