Spellfire
Weapon system for FPS
Unreal Engine
My Role
Programmer
Team Size
3 during pre-production
5 during production
Time Spent
4 weeks production
Year
2023
Spellfire is a 3v3 team deathmatch game with short-duration upgrades to your weapon. You play these upgrades from a hand, requiring you to decide when and where to commit your resources.
​
All upgrades work together as you'd like them to: you can make your bullets exploding, bouncing, and slow-mo all at once.
​
I made the system that handles weapons and their bullets as well as ensuring they're replicated over the network.
Weapon system
Our weapons consist of modular pieces divided into categories:
-
Spawners spawn bullets.
-
Constraints handle requirements such as ammo and fire rate.
-
Modifiers apply changes to the bullets one by one.
​
When the player presses fire each of these categories gets to process the input signal in order.
​
-
Constraints check if their requirements are met, if so the signal passes to the next constraint in order. If no, the firing attempt fails.
-
After all constraints have passed, the spawner decides which projectile to spawn, how many, and in which pattern.
-
The spawned bullets are passed to the modifiers. Each modifier goes through each bullet one by one, then passes them to the next modifier.
-
When all modifiers have gone through the bullets, we're done.
.png)
Modifiers implement the effect of all upgrades. A bouncing modifier ticks the bouncing boolean in the projectile's movement component. An exploding modifier adds a component that handles the effect on hit.
Modifiers may also have constraints that affect when they fire and when they pass the bullet unchanged. This allows for a modifier that affects every third bullet, or every 5 seconds, e.g. They also expire after a set amount of time.
​
Constraints can implement any function that returns true or false. They can also hold internal state, and are allowed to process their state once per firing attempt that reached them.
All three classes are intended to be inherited from in either blueprints or c++. New behavior is implemented in c++ and tweakable parameters are handled in blueprints.
​
Implementing a new class only requires overriding one or two higher level functions. An example is the spread spawner class, which overrides the SpawnProjectiles to generate multiple locations and rotations in a spread, and then uses them for the parent class' inner spawning method.
​
In general, new content is left for designers in blueprints, and new behavior is implemented in c++ where possible.
​
This image show the class hierarchy for the weapon system.
.png)
Networking
For the current prototype the game operates over LAN with one of the clients acting as a listen server. For movement replication and prediction we used the built in Unreal Engine systems.
​
There are three additional pieces of information specific to our game that the client needs to receive from the server:
​
-
Player stats (health, speed, and damage statuses)
-
Active modifiers with their durations
-
The cards in hand
​
Since the Unreal replication system is built around actors and actor components, I made three components which were responsible for one of the above, respectively. In this way, the specifics around replication as well as behavior is compartmentalized away from the character class into these components.
.png)
This proved an effective strategy for player stats and effects as well as weapons. By re-initializing these components on respawn after death values are set to normal starting conditions.
​
The card system instead requires the players hand to remain consistent. Current goal for implementing cards over the network utilizes storing card information in the player state which is then read and manipulated by the server.
What I learned
As our sole c++ programmer, I had a lot on my plate. My responsibilities included: weapon systems, upgrade systems, status effects, networking, and teams. This was my first substantial project with c++ in Unreal and the first time considering network functionality in my code.
​
I've now gotten familiar with the Unreal networking system and the logic behind server-authority networking models. Having to implement a modular weapon system that communicates appropriately over the network also forced me to get familiar with new parts of the Unreal ecosystem, especially in details surrounding object initialization and garbage collection.
​
Perhaps the most interesting lessons I've learned revolve around how to structure my code architecture with extensions and blueprint content in mind. Having to maintain core systems while ensure that my code was ready to be consumed by three other members on my team taught me the value of consistent and clear abstractions in my architecture.