Development
Ternion was built in Unreal Engine 5 as a multiplayer 3v3 FPS. I worked on the project with Hampus Brink and Raphael McCabe, with Hampus focusing mainly on networking and gunplay, Raphael on animation and the map, and me on character movement, abilities, and the skin system.
The game is built around three characters that each emphasise a different part of the FPS experience: movement, strategy, and aim. The three characters are shown in more detail in the gallery above, but I was responsible for implementing many of the systems that make their different playstyles possible.
Character Movement
One of the main parts of my work was creating Ternion's custom movement system. Rather than building the movement entirely from scratch, I extended Unreal Engine's UCharacterMovementComponent in C++. This gave me access to Unreal's existing movement and multiplayer prediction systems while allowing me to add the movement mechanics required by the game.
I implemented sprinting, sliding, dashing, mantling, and wall running on top of the existing movement component. Each custom movement mode was split into checks for whether the movement could be performed and a corresponding physics function containing the actual movement logic.
The multiplayer side was particularly important because these mechanics had to behave consistently for both the owning client and the server. Unreal's character movement system uses client-side prediction and sends movement information to the server as SavedMoves. I extended this system with custom compressed flags so that the server could also reproduce and validate my custom movement actions.
Character Abilities
Each character also has two unique abilities. I initially experimented with Unreal's Gameplay Ability System, but after spending significant time trying to get the base system working, I decided that it was unnecessary for the scope of the project. Instead, I built a smaller custom ability system using Blueprints.
The base character handles the shared ability functionality, including cooldown UI updates, while the individual characters override that behaviour with their own ability logic. This made it relatively straightforward to give each character abilities that supported their intended playstyle without introducing a large framework that we did not otherwise need.
The abilities are demonstrated throughout the character examples in the gallery above, particularly in the sections for Brisk, Brain, and Brawn.
Weapon Skins
I also implemented the weapon skin system, which allows players to select different appearances for their weapons. This involved creating the skin materials, building the equipment UI, and persisting the player's selected skins.
The skins were created as material variations of the weapons' existing materials, allowing their appearance to be changed without replacing the underlying weapon setup. I then created an Unreal Widget-based menu for selecting and equipping them.
The selected skins are stored using an Unreal SaveGame Blueprint class called UniquePlayerData. When the player equips a skin, the system updates the saved weapon data and loads it again when needed.
Working on a Multiplayer FPS
A recurring challenge throughout the project was making sure that systems that feel simple from a player's perspective also work correctly in a multiplayer environment. Character movement in particular required understanding how Unreal handles prediction, replication, and server corrections rather than simply implementing the movement locally.
Working on Ternion gave me experience extending Unreal's existing systems instead of treating the engine as a black box. It also taught me where using an existing framework is useful and where a smaller custom solution can be more appropriate for the scope of a project.
Ternion was my graduation project in 2023, and it remains one of the projects where I learned the most about gameplay programming and multiplayer development.
