Building a Racing Game in Unity

Comments

Since 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.

Learning Blender

Comments

One thing I've always felt was a bit limiting for me as a programmer wanting to create games is a lack of artistic assets. Most games require some kind of art work: images, drawings, music, etc. And I have pretty much no experience creating art. I never even took a single drawing or sculpting class in school. I figured that if I were ever going to create a full game by myself, it would probably need to be something like Geometry Wars so I wouldn't need much art. I do love Geometry Wars, but there are lots of other types of games out there.

Fortunately, I recently realized how fun and useful 3D modeling tools can be. I guess it started when I was learning SketchUp for a woodworking project I was doing. Maybe I'll talk about that project or about SketchUp some other time, but today I want to talk about how I've started learning Blender. When I started learning Unity, it really became clear how critical it is to have 3D models (or 2D images) to work with, even if they're just placeholders that might be replaced by better ones later.

I wanted a lovebird model for the bird game I was working on, so I went looking on the Unity asset store and managed to find one that I liked. But it was $20 and I wasn't sure I was that serious about the project yet to spend that much on a single model. I decided to try to make a placeholder myself. Then if the game did become a serious project, I could buy a good model and replace it later.

I started learning Blender just from just from the tutorials on Blender's website, until I started hitting the ones that required a Blender Cloud subscription. At that point, I started watching tutorials on YouTube, including this basic one and this one about creating low-poly animals. Those actually got me pretty far, and I was able to create something that did resemble a lovebird. But they also showed me how much there was to learn.

After watching those videos I kept seeing ads for online courses. I eventually clicked on this Blender course on Udemy. I'd never used Udemy before or bought an online course before anywhere else. But I decided to buy this one after watching the free sections. It was only $10 for new users when I bought it and it has 48 hours of content, which seemed like a pretty good deal to me. I'm a little less than half way through the course and, so far, it's pretty good. I've made a bowling ball, bowling pins, chess board, and all the chess pieces.

I've already learned a lot and I'm excited to continue learning more. Even if I'm never able to create anything better than placeholder-quality models, I think this is a skill that will serve me well in the future. Plus, the fewer excuses I have for not creating games the better. I've already started using some of the models I've been creating. I'll talk more about that later.

Learning Unity 3D

Comments

As I mentioned in my last post, video games are why I started programming and I'd like to get back into game development. So I recently installed the Unity game engine and started going through some of the tutorials.

I started at the beginning with the Roll-a-ball tutorial. Although what you end up with after completing that tutorial may seem simple, I was pretty impressed. Having done game stuff without the benefit of an engine before, it's pretty amazing what a complete beginner can do in an hour with Unity.

I had an idea for a simple game prototype that's not too different from that tutorial. I have a pet parrot and he has a game — I use that term loosely here — he likes to play where you put his toys on top of his cage and he runs around on top of the cage and pushes the toys off onto the floor. He then stares down at the toys on the floor and demands that you pick them up for him. My idea was basically just to create this game with the player in control of the bird.

So I started by just adding a plane and a sphere as in the Roll-a-ball tutorial. The plane represented the top of the cage and the sphere represented a ball toy. Then I added a roughly bird-sized green cuboid to represent the bird (our bird is green). At first, I tried to control the cuboid the same way the ball is controlled in the tutorial. But that was just tipping it over instead of pushing it. So I switched to using a CharacterController instead of a Rigidbody and that worked well. Once I had the cuboid moving around, I just needed to be able to push the sphere. I was able to get that working with code based on the answers in this Unity Answers post.

Again, what I ended up with was very simple. But I was able to make something in two or three hours that I believe could've easily taken weeks if I were writing it completely from scratch. The main reason I think it would've taken so long from scratch is the physics. Even for simple shapes, the math for collision detection and response can be pretty complicated, depending on how correct/accurate you want to be. My hope with learning Unity is that I'll eventually be able to create something closer to a full game (that's actually fun to play), rather than the tech-demo-type things I've created in the past. And while this is still just a tech demo, the fact that it took so little time to create is a good sign. I'm just getting started with this bird game, so I hope to talk to about it more in the future.

Continuing with my Unity education, I also completed the space shooter tutorial. That one is more in-depth and leaves you with something closer to a full game at the end. It took me a couple days to complete. Again, I was impressed with how much can be accomplished so quickly. In high school, I built a game from scratch that was very similar and it took me months. Of course, I was inexperienced at the time, but it would still take me a while to do that from scratch today.

I've noticed that programmers often have a tendency to want to build everything from scratch. We like being able to understand and have complete control of all the details in our programs. And, of course, it's good to understand how things work at a fundamental level. But if you insist on doing everything yourself from scratch, you'll be severely limited in the scope of your projects. I have to remind myself of that occasionally and let myself embrace higher-level tools. And that's exactly why I'm learning Unity.

But Unity isn't the only tool I'm currently learning. One point that the Unity space shooter tutorial really drove home for me is how important it is to have artistic assets available to use. It's only because the tutorial provides those assets that you can create the game so quickly. I can imagine that creating the assets might take as long as the game itself. Because of that, I've decided that I need to learn how to create some simple assets for myself. I've started learning Blender, which I'll talk about in my next post.

Video Games: How I Started Programming

Comments

Video games are pretty much the reason I originally learned programming. The first game that really interested me was Paratrooper, which I played for the first time on my uncle's DOS computer. I asked him how people make games like that. I knew you could tell a computer how to do things with simple DOS commands like "dir" and "cd", but I couldn't wrap my little (probably less than 10-year-old) head around how one could tell a computer what a helicopter was or to make that helicopter fly across the screen. Unfortunately, my uncle couldn't explain that to me, at least not in a way that I found satisfactory. I was still curious, but I didn't pursue it further at the time, even after my family got our own DOS computer.

A few years later, when I was about 12 years old, my favorite game was Banjo-Kazooie. Before the game came out, I downloaded all the preview gameplay videos I could find, tying up the phone line for hours with the dial-up connection. I remember that the game came out in June and it seemed like an awfully long time to wait from the last day of school sometime in May. I was pretty obsessed. Anyway, at some point I remember visiting the website of Rare, the game's developer, and looking at their jobs page. It seemed like the main skill required was C++.

I didn't exactly know what C++ was, but I almost immediately went and told my dad that I needed to buy a C++ book. We bought Sam's Teach Yourself C++ in 21 Days. It came with a CD that contained a compiler. Although that probably wasn't the best way for a beginner to learn programming, it was enough to get me started. I remember being so excited about that book that I had to restrain myself from reading through it too fast. I tried to only let myself read one "day"/chapter each day and did all the exercises.

Of course, I was eager to apply my new knowledge to games. I think the first real program I made that wasn't an exercise from the C++ book was a Tic-Tac-Toe game with ASCII graphics. I had a lot of fun making that game and creating the opponent "AI". But after doing that, I decided that I needed to learn how to draw real graphics.

I bought another book and this one was specifically about creating games. I learned how to control the graphics card using VGA mode 13h. I was so excited the first time I was able to draw a simple square on the screen. And I was even more excited when I could move that square around using the keyboard.

I started trying to make a clone of Paratrooper. In that game, you can rotate your gun's turret using the keyboard. I tried to trace out a circle, but I didn't really know how to do that. I took a guess at what I thought must've been the distance formula: x + y. Of course I had no idea that what I was looking for was called the "distance formula" or that the formula I'd used was Manhattan distance rather than Euclidean distance. But when my circle ended up looking like a square, I figured I better go learn some more math. I started reading my dad's old trigonometry book. It was a bit of a challenge for me since I hadn't taken Algebra yet, but I was able to find what I needed. I'd credit that experience with helping to spark my interest in math.

By the time I entered high school, I already had a pretty good grasp of the fundamentals of programming. And my projects got more sophisticated as I learned about Win32, DirectX, and 3D math. I created a simple, yet fully-functional top-down 2D space shooter and then a 3D version of the shooter. But once I entered college and started doing summer internships, all of which involved writing other sorts of programs, it seemed like there just wasn't enough time to work on games as much anymore.

Over the last 9 years of my career as a professional software engineer (outside of the game industry), I've occasionally started a new game project here and there, but never really gotten very far on them. I'd like to get back into game development, even if it's still only just a side project. I've recently started learning Unity 3D and Blender, but I'll talk about that in a future post. This post actually started off as an introduction to that post, but I got carried away and just decided to make this its own post.

The Bird Door

Comments

My girlfriend has a pet lovebird. When I was a kid, I had parakeets. But I was careless with going in and out of the house while the birds were out of their cage. One day, they flew away and I never saw them again. When my girlfriend and I were planning to move in together, I was very excited about having a pet bird again, but I didn't want to repeat that mistake. I knew we'd both be coming and going from the apartment at different times. And with a very adventurous, curious bird that needs at least two hours out of its cage every day, that was going to be a problem.

I figured other bird owners must have this problem too, so I searched online for solutions. I wanted to have a double door of some kind to keep the bird safe. I wanted something like what zoos have for their free-flight bird exhibits. Since we're renting, it would have to be something that could be installed temporarily. However, I wasn't really able to find any products that I could buy.

At first I was thinking about using something like a curtain rod. There are ones that hold themselves up with friction by pushing against the walls. I thought I might hang "strip curtains" from that. But ultimately, I decided that curtains might not be secure enough. I decided to try building a real door using the same principle of the curtain rods of pushing against the walls.

Push clamps

I didn't know how to achieve the pushing against the walls. I started searching for "push clamps", not even knowing if those existed (they do, apparently). But I eventually decided I could do what I wanted with just two blocks of wood, a threaded rod, and a nut. I screwed the threaded rod into one of the blocks, but not all the way through. Then I drilled a hole all the way through the other block, large enough to let the rod pass through freely. By putting the nut on the rod in between the two blocks, I could control the distance between the blocks by moving the nut.

Prototype

Although my pushing mechanism seemed to work pretty well, I wasn't sure if it would really hold a door in place securely enough. I needed to build a full prototype. My idea was to build a frame just large enough for the door and then have the "push clamps" on the sides to hold the frame in place.

As you can see, the frame sits on the floor, so the clamps don't have to actually hold the weight of the frame and the door. All they need to do is keep the frame from sliding out of place. And they seem to work well for that.

I was actually hoping the prototype could just be used as the final product, but I didn't know yet where we were going to be living once we moved in. My apartment at the time was just about the perfect layout for this idea. It had a long hallway upon entering the front door, which gave me the two walls I needed to push against. But I knew wherever we moved into might not be so ideal. So I just did my best to make the design very general.

Materials

One thing I needed to do was make sure that the materials and parts I was using would be safe for the bird. There was no chance that the bird wouldn't end up chewing on the door eventually. For the wood parts, I used untreated Douglas fir 2x4s. For the metal parts, I used stainless steel. The only exceptions were parts that would be out of reach for the bird because they're on the opposite side of the door.

Here are some links I found helpful in selecting parrot-safe materials:

The door itself

The door itself is simply a hollow rectangle of 2x4s. The 2x4s are connected with half lap joints and glue. I had pretty much no woodworking experience when I started this project and very limited tools. But after watching a lot of Paul Sellers videos on YouTube, I decided to try making the joints by hand with a hand saw and a chisel. It took a long time, and I wasn't able to get the faces of the joints very flat, but it worked out. Even with the big gaps I had in the joints, they are very strong and rigid.

Frame

The frame that holds the door is also just a rectangle of 2x4s, but larger and with the boards rotated 90° so that the frame is "deeper" than the door. I got lazy and just used butt joints with screws for the frame — no glue. This is not great, because the frame is a bit wobbly. But it worked alright because my push clamps hold the frame in place and keep it from wobbling.

Closer

The last thing I did with the prototype was install an automatic closer. I went and bought the cheapest one they had at Home Depot, which was around $10 or $15. It was pretty easy to install. I don't think I had really planned out where the closer would go when I started the project, but fortunately I had room to mount it on the frame without it getting in the way of the door. To stop the door from swinging beyond parallel with the frame, I simply nailed a small piece of wood to the top of the frame in the right spot.

Final location

When we decided where we were going to live, I wasn't sure that I'd be able to make the bird door work there. It's a townhouse and the entrance leads immediately to a set of stairs. There isn't really a good place for the door at the bottom of the stairs. At the top of the stairs, the wall on one side ends right at the top, so I can't use my push clamps against the walls like in my previous apartment.

Since I don't have two walls to push against, I decided to use my clamps on the ceiling instead.

Clamping against the ceiling worked fine for keeping the door in place. However, the door no longer closed properly because the frame around the door was sagging out of square. I hadn't realized that when I was using my clamps against the walls they were keeping the frame from sagging side-to-side. The ceiling clamps, however, don't prevent that.

Wall grabber

The solution I came up with is something I call the wall grabber. It's basically an 'h'-shaped piece of wood that cantilevers off the end of the wall. This effectively extends the wall a bit, allowing me to use that wall to hold up the door frame and keep it from sagging to the side. As with the rest of the project, the grabber is not permanently attached to the wall. I built the grabber to fit the thickness of the wall as closely as I could so that it would mostly just hold itself up. But to make sure it stayed in place, I also just propped it up from the bottom with a 2x4 that leans against the wall.

This works surprisingly well, even though the grabber isn't really attached to the wall or the frame in any way.

BirdBlock

The final thing that needed to be done was block the holes between the frame and the walls, and in the center of the door itself. I used a product called BirdBlock, which is pretty much like chicken wire, except it's made for gardening and it was cheaper because it's plastic.

I wasn't sure if the holes in the BirdBlock would be small enough to keep the bird from sticking his head in. I'm still not sure, actually, because he's never tried to do that. I was also wondering whether he'd be able chew through the wire, since it's pretty thin. Again, I can't say for sure because he doesn't really try to do that, but it seems like it might be too flexible for him to chew through it easily.

To attach the BirdBlock, I just cut it to the right size and then stapled it into place (using stainless steel staples). Since I didn't want holes in the walls, I just used tape to attach it to the walls. Surprisingly, the tape has held it on pretty well.

The only problem is that since the wire is so thin, it breaks easily. So if you accidentally get snagged on it on the way into or out of the door, you're likely to break it where it's stapled into the door. But we've only broken it in a couple places so far and it's nothing another staple or two couldn't fix.

Finished

Here's what the final product looks like.

Lessons

After having used the bird door for the last year, I'd say that it's worked out even better than I imagined. It allows us to come and go without worrying about the bird's safety. I'm especially pleased that I haven't had to do any repairs, adjustments, or maintenance at all to the door during that time. Since I've never made anything like this before, I was expecting something to have to deal with some problems when we started using it on a daily basis. But it really has held up quite well.

If I were going to start over and do it again, there are a few things I'd consider changing:

  • I'd add another 2x4 going horizontally across the middle of the door so that you have something to push against. As it is, you can't really push the door open with your body when you have your hands full because there's nothing to push against except the BirdBlock.
  • Speaking of the BirdBlock, I'd consider using something stronger. The fact that it's so easy to break is a little annoying. However, whatever I replaced it with would still need to be flexible enough to wrap around corners. Also, it would probably need to be light enough to allow being taped to the wall.
  • I wouldn't cut the half-lap joints entirely by hand. That took forever. Since I did that, I've learned that the more typical technique would be to cut a bunch of slots with a circular saw, knock out the remaining pieces with a hammer, and then clean it up with a chisel. See https://youtu.be/179pW3p7RI8?t=188
  • I would probably use real joints (i.e. something other than a butt joint) for the frame so that it would stay rigid on its own, without the clamps holding it. However, that would also mean I'd have to be more careful to make the frame and door the right size and keep them square.

This was a pretty fun project for me. I'm a pragmatic guy, so I enjoy building things that are going to be useful for me. And this is something that I use every day. Plus, the constraint of not modifying our apartment presented some interesting problems to solve. Another reason I liked this project was that I got to learn a lot about building physical stuff, which is something I don't have much experience with. I also accumulated several new tools that I can use on future projects.

Anyway, I hope you found this interesting. Thanks for reading!