Beginnings

I’m excited to share that I’m working on something new – a solo game dev project built in Unity. It’s been a while since I’ve made anything in engine, and I’m taking my copious free time to keep my skills sharp and hopefully further my knowledge and experience.

A lot of my prior development experience is in creating action games; this isn’t really surprising, considering how saturated the market is with action games. Plus, I love action games! Titles like Hades and Hollow Knight have greatly influenced me as a designer, and I grew up playing Halo. Interestingly though, I’ve never worked on a first-person shooter. Throughout my education I was always told they were hard to do well, but now I can fail with fewer consequences – so I’ve decided to try my hand at the genre.

I’ve spent the last few weeks building a very rough framework in Unity – first-person movement and mouse-look controls, implementing a shooting mechanic, and giving the player something to shoot at. I’ve also prototyped gravity-lift style mechanic to explore gameplay beyond basic combat. I don’t have a strict design I’m following – instead, I plan on implementing mechanics and iterating based on testing to find what’s fun and engaging.

Movement

Getting a capsule to move in Unity is fairly straightforward. Getting one to move exactly how you want is a fair bit trickier. While I could likely find a pre-built implementation of first-person movement, I really wanted to build the basic systems of my game on my own. I have a fair bit of experience scripting in C# for Unity, so this wasn’t a major stumbling block for me. I childed the main camera to a capsule, gave it a rigidbody and a character controller, and hooked up input axis to a transform function – nice and simple.

Next was handling mouse-look – by default, Unity ties the cursor’s movement to axes just as it does for certain key inputs, so using the X axis to rotate the player left and right is pretty easy. Doing the exact same thing for the Y axis causes problems, however – moving the mouse up and down shouldn’t actually rotate the player, but the player’s head, represented here by the camera. This is simple enough to fix, but still worth noting. Additionally, the mouse’s X axis input actually translates to rotation around the Y axis, while Y axis input translates to the camera’s rotation around its X axis.

Unity Object Rotation Axis First Person Shooter

Rotating the capsule along the Y axis (left) works, while doing the same around the X axis (right) clearly doesn’t.

So now the player can move forwards and backwards, strafe left and right, look up and down, and turn left and right (which changes the relative movement directions). I also want the player to be able to jump, further opening up the potential for verticality within the game. In the real world, jumping is effectively a force applied to a person in the opposite direction of gravity (an oversimplification, but it’s all we need here). Unity can do the exact same thing with relative ease - forces can be applied to rigidbodies and scene-wide gravity is on by default for objects with this component. I implemented a “ground check” function that runs in an Update function – it draws a sphere slightly below the player and checks if any object tagged on the layer “ground” is within it. If so, the player can jump, and vice versa. This prevents jumping while falling or double-jumping – if I want to change this later, I’ll have to come back and re-implement some of it.

Shooting

A bit of digging into the specifics of how shooters work will likely bring up the question of “hitscan” versus projectiles – whether or not a weapon simulates an actual projectile with travel time. Both implementations have value on technical and design fronts. Without knowing where this project is going, I chose projectiles somewhat arbitrarily, knowing I could probably change later.

To start, I needed a prefab object for bullets – it got a collider and a script that moved it forwards every frame, along with a public variable for its speed. When instantiated, I passed the rotation of the player’s gun object to the bullet to ensure it traveled in the right direction. This setup worked for now, but would later cause huge problems down the line.

I also wanted early visual and audio feedback for firing a weapon; I accomplished this with a muzzle flash, a firing animation, and an audio clip of the weapon discharging. It’s simple and likely needs refinement, but effective enough for a rough prototype. I also added a simple ammo system and ensured that the player couldn’t fire while reloading, along with audio for reloading and attempting to fire the weapon while it was empty.

Muzzle flash and visual recoil for firing the weapon. The effect is accompanied by a flash of light.

Another piece I wanted to implement was recoil; requiring the player to pay slightly more attention to firing their weapon seems like a simple way to make the shooting system more engaging. My initial implementation checked how frequently the player was firing; if two or more shots were in quick succession, the bullet’s rotation was slightly adjusted based on a random value within set bounds. The result is a weapon that can be rapidly fired at full effectiveness at close range, but that loses accuracy at range if the player doesn’t time their shots.

Lastly, I created simple capsules with colliders and health values; when bullets collide with these, the health decreases, the bullet is destroyed, and a simple particle effect spawns. When a target’s health reaches zero, it is also destroyed.

I found two major problems with my implementations, which were frustratingly inconsistent. First, bullets would occasionally spawn above the intended position – this happened about half the time, and I probably spent too much time trying to figure out why (I eventually found the solution, but I’ll get to that in due time). Second, bullets weren’t consistently colliding with their targets, even when it was obvious that they should have. I had some better leads on this problem – lower speeds yielded more reliable collisions, but I still didn’t know the actual cause of the problem. I looked into the differences between discrete and continuous collision detection, which can be important with fast-moving colliders, but adjusting these settings accordingly didn’t solve anything. Eventually I decided I needed to move on, and that I’d revisit these problems another day.

Buttons

I took a break to implement another mechanic – interactable buttons. This was simple enough to do and remarkably satisfying, and having toggleable switches tied to doors or bridges in the environment opens up plenty of opportunities for fun level design. I implemented this system with wide-scale compatibility in mind – rather than having a separate script for every type of object that could be attached to a switch, I created a single “reaction object script” that toggles a trigger in an animator on the same object, letting the animator handle the effects of interacting with the switch.

Switches in the environment can open and close doors, among other functions.

I also made sure that a single toggleable object could be controlled by multiple switches.

I’ll have more updates in the coming days – what I’ve shown here is only the beginning of this project, and I intend to keep working on it to see where it leads me.

Previous
Previous

Abilities & Enemies