The game
Ternion is an online 3v3 FPS built in Unreal Engine 5. It was my graduation project at Forsbergs, made with Hampus Brink and Raphael McCabe over ten weeks, and we put in a lot of overtime to get it done. Hampus mainly worked on networking and gunplay, Raphael on animation and the map, and I did the character movement, the abilities and the weapon skins.
Each of the three characters is built around a different part of playing an FPS. Brisk is about movement, Brain about strategy and Brawn about aim. Most of what makes them play differently runs through the movement and ability systems I built.
We released it on Steam as Project Ternion. It's still buggy and unpolished, because none of us had the time to keep fixing it after the project ended.
Character movement
I built the movement by extending Unreal's UCharacterMovementComponent in C++. That kept Unreal's own movement and multiplayer prediction, and let me add the mechanics the game needed on top: sprinting, sliding, dashing, mantling and wall running. Each one is split into a check for whether it can happen and a physics function that does the actual movement.
Unreal's character movement uses client-side prediction. The player's machine moves the character straight away and sends each move to the server as a SavedMove. I extended that with custom compressed flags, so the server could reproduce and check my custom moves as well.
Character abilities
Each character has two abilities of their own. I started with Unreal's Gameplay Ability System, but I spent a long time just getting the base of it working and decided we didn't need it for a game this size. So I built a smaller ability system in Blueprints.
The base character handles what every ability shares, like the cooldown and the cooldown bar in the UI. Each character then overrides it with their own ability logic. Brain's primary ability, for example, calls the parent, checks the cooldown and then runs a scan.
Weapon skins
I also built the weapon skins. Each skin is a material variation of the weapon's existing material, so it changes how the weapon looks without touching the weapon itself. Players pick one from a menu I built with Unreal's widgets. The choice is saved in a SaveGame Blueprint class called UniquePlayerData and loaded again the next time the game needs it.
What I took away
Everything I built also had to work in multiplayer, which was the hard part of most of it. The movement had to behave the same on the server as on the player's machine, so I had to learn how Unreal handles prediction, replication and server corrections.
The ability system taught me that a big existing framework isn't always worth it for a small project.
It's still one of the projects where I learned the most about gameplay programming and multiplayer.
