This is the first time I’ve actually used the Unity engine for anything substantive. It’s also the first time I’ve made an FPS. All in all, I think things turned out pretty well. Here’s a quick rundown of what went right and what went wrong.
I’d written some pretty simple stuff in Unity a month ago. This is what I started with as a base:
Not the most promising start, perhaps, but it was a start. My plan was to see how far could I get using free 3D assets from the Unity Store. I started pulling down some random ones that looked good, with the intention to - at some point - cobble them together into a working game.
One of the first assets I found in the store was Painterly Nature. I was taken by the screenshots, and I quickly put together a scene to see what it looked like. After I had done that, though, I kept thinking “there’s no way I can do this justice”.
I went back to the drawing board and tried to focus on a more low-fi game, but as time progressed, my mind just kept coming back to Painterly Nature. It’s an absolutely gorgeous asset, and it was completely free! I was incredibly inspired by it, and couldn’t stop thinking about what kind of a game I could include it in. After a while, I simply gave into my urge, focusing on my first-person prototype.
The idea from there was a Serious Sam-style shooter. I’d throw in a few silly enemies, a gun, and give the reason a player to shoot things. First, I fully converted my third-person scripts into first-person ones. It was surprisingly simple.
It took me a little bit to figure out how to correctly leverage Unity’s components for movement. At first, I tried using character controllers for everything, but I quickly ran into issues. By far, the biggest one is that they’re restricted to capsule colliders. That’s okay for the player character and my mushroom model, but how about non-humanoids like the horse?
Furthermore, there are effects you can’t achieve with character controllers. For example, the “rolling” effect that the mushroom, skeleton and PC share when they’re killed can’t easily be achieved without the rigidbody’s physics. So, with those considerations in mind, I went with rigidbodies.
They certainly had their downsides, but I worked around them eventually. To anyone that’s facing a similar conundrum, here’s a couple tips on using rigidbodies:
- Freeze rotations on all axes. Set
transform.rotationyourself in your scripts if you need to rotate the object.
- Contrary to what the docs tell you, directly setting
Rigidbody.velocityevery frame is fine. It may not be as realistic as adding forces, but it makes your controls and AI much more consistent.
Quaternions, please. pic.twitter.com/1ONXGb3K3W— Edward Lu (@Chaosed0) July 14, 2015
Getting the AI to work right was also a bit of a chore. For pathfinding, I started out using the free version of Aron Granberg’s excellent A* pathfinding project. However, as time went on, I was less satisfied with the performance and look of A. Long story short, I eventually broke down and bought the paid version of the project so I could use recast and graph navigation. I slightly regret it - I could have worked around the issues with A - but I figure I’ll probably use the library again in another project.
At this point, I had some infinitely-spawning enemies that would follow you around. You could destroy them, and that was fun, but they couldn’t hurt you; they just kind of huddled at your feet. I integrated player health fairly quickly, using
OnCollideEnter() and the enemies’ hitboxes.
The codebase was a bit of a mess here, so I did a bit of cleanup. I made the player and enemies share a single component for health and factored out the player-specific functions into its own component.
The final pieces of the game were the story bits. In my experience, things like the tutorial and the intro/outro are huge pains in the butt: entirely new scripts and systems you have to set up just to fill the first couple minutes of the game.
This time around, they were still a pain, but I took a different approach. Instead of trying to architect everything exactly the way I wanted it, I bulled through and implemented them in the most straightforward way I knew how. I put hooks into the
Player script that I knew would be one-time use only, and I scattered references to specific objects everywhere. Afterward, the codebase definitely needed some work, but it got me through this phase.
With the tutorial, intro, and outro done, the game was feature complete, but there was still yet more I wanted to do. Many of the scripts that I’d intended to be generic were usable only with Crash Landing. They referred a lot to the tutorial and game-specific systems. Ideally, they could simply be taken and used with another game, so another round of cleanup was in order.
In the meantime, I sent the game out to a few friends. They gave me valuable feedback for the next phase: putting in polish. I put a particle dust cloud down at the crash site. I implemented gun bobbing. I tightened up the movement and tweaked the gravity. I adjusted the monster spawner timings until the difficulty felt right.
Finally, after incorporating the feedback, the game was done! All that remained was building it for different platforms and making sure all was good. It was a momentous occasion when I posted this:
My first FPS game. What a rush.
I have to really give thanks again to all the people whose free assets I ruthlessly pulled and edited; they’re credited in the
attrib.txt file included with the game. You guys are awesome, and you make awesome stuff. Again, I cannot say enough good things about Painterly Nature. It’s pretty safe to say that without that pack, Crash Landing would never have been what it is now.
Finally, huge thanks to my friend Jeremy Crafts (Art-Zen), who did the music. I haven’t had music this good in any game I’ve ever made before!
That about wraps it up. Looking forward to the next game.
12/8/2015: Revised a few minor issues with the post.