Overview
ELVERA is an indie third-person PvP action game. Two factions fight for control across a rich world, and every match plays out differently. A diverse roster of heroes, each with unique abilities, combined with round-based events and on-the-fly strategy choices means no two games feel the same.
I built this entirely on my own, from the very first prototype to the Steam release. Every system, every line of code, every design decision, all me. Released on January 15, 2024.
Systems & Design Showcases
Think of this as the behind-the-scenes look at how I built the game. Below are the core systems, the logic, and the design choices that make it all work.
Ability System
ELVERA’s Ability System is anchored by a central base class called Ability_Base. This class stores the core data and functions for every ability in the game, establishing the foundation for a multi-tiered inheritance hierarchy. Through a structured approach, it ensures efficient management and consistent behavior across all abilities. Beyond its foundational framework, the system offers overridable functions, facilitating tailored behaviors for each ability. Integrated elements such as input bindings, activation logic, and multiplayer compatibility using Unreal Engine’s replication make it a comprehensive and dynamic system.
Design Approach: The system is categorized into three distinct ability types: Primary, Secondary, and Ultimate. Each type is a derivative of Ability_Base, preserving common data and logic while allowing for child-specific functionality.
Core Data: Central to the system is the Ability_Info structure. It captures core parameters for abilities: name, icon, category, cooldown, cast conditions, weapon requirements, animations, and a suite of behavior flags dictating contexts and constraints for ability usage.
Overridable Functions: The system provides flexibility with functions in the base class that can be overridden by child classes, enabling tailored logic or entirely new behaviors for each child.
Ability Association: Every in-game character is equipped with a set of three abilities, one from each type. These children, affiliated with their respective types, ultimately trace back to the foundational Ability_Base. This layered approach facilitates both global control at the base level and nuanced adjustments in specialized subclasses.
Ability Assignment Mechanism: The base character class has designated slots to bind specific abilities. Upon assignment, integrated logic extracts and utilizes this ability data across various game systems, from tooltips and cooldown indicators to sound cues and gameplay mechanics.
Cleanup Mechanisms: Every ability has a customized ForceEverythingAbilityRelatedDestruction() function. This function clears any leftovers an ability might leave in the game world. Its core use is between rounds to ensure a fresh start without lingering ability artifacts from previous rounds.
Multiplayer Compatibility: The entire architecture is integrated with Unreal Engine’s replication system, ensuring all players receive real-time, synchronized ability data for a smooth multiplayer experience.
Input Bindings: In the base character class, three distinct input actions are dedicated to abilities: Primary, Secondary, and Ultimate. Each ability is linked to its unique data asset input action, mapped to a data asset input mapping context and initialized in the player controller once the player connects.
Activation Process: Each ability type is bound to a specific key. When activated, a series of conditions are checked locally to ensure the ability can be used validly. Then, using a server RPC, additional verifications happen to make sure there is no attempt to bypass the system and that the server agrees with the client. Once cleared, an actor is spawned at the player’s current location. This actor is not a tangible entity in the game world but serves as a logic carrier for the ability.
Ability Logic Execution: On actor spawn, specific abilities initiate their corresponding logic. For example, the JumpPad ability involves spawning the static mesh representing it, setting up collision overlaps, defining its behavior (launching players once overlapped), its accessibility (allies or enemies), and its duration. All of this is accompanied by sound cues and other elements that enhance the ability.
Attack System
ELVERA’s Attack System is an intricate yet modular system designed to manage and execute characters’ basic attacks. Grounded in a combo-based design philosophy, it allows characters to perform a sequence of attacks with different weapons. It seamlessly integrates with the game’s character stats, items, and other systems to ensure dynamic gameplay, responsive mechanics, and visually appealing combat.
Design Approach: The entire melee and ranged attack logic is encapsulated within a dedicated Basic Attack Component. This component can be attached to the base character class, ensuring every character inherits its combat capabilities. This component-centric approach makes the system flexible, scalable, and easy to debug or extend.
Foundation: The system’s core is a combo-based mechanism tracking the sequence of attacks and resetting accordingly. It is enriched by an enumerator that tracks and classifies equipped weapons for correct execution logic, differentiating between one-handed weapons, two-handed weapons, bows, dual blades, and unarmed combat.
Core Data: Character parameters comprise fundamental details like attack speed, attack damage, attack range, and the attack’s area of effect, plus several additional variables that may affect each attack accordingly.
Animation Integration: Recognizing the combo counter and weapon type, the system selects the fitting attack animation. Dynamic animation slots are linked to specific portions of the player’s skeleton, enabling concurrent movements like attacking while running or jumping.
Melee Mechanism: An integral part of the melee combat is a dynamic collision box attached to each character. In its default state, the collision box assumes the character’s position. Upon the player’s first attack, the system pulls all vital information like attack speed, range, AoE, and other character stats. It then computes how to adjust the collision box’s location, dimensions, and orientation. The direction it faces is determined by the player’s input and location, ensuring accurate and responsive combat interactions.
Ranged Mechanism: For ranged combat, the logic uses a Line Trace by Channel system for precise hit detection. The core involves determining a direction vector by subtracting the camera’s location from the targeted location. This vector, normalized to a unit length, is scaled according to the weapon’s specified range. The result defines the line trace endpoint, ensuring precise hit detection that adapts to various ranged weapons and their distinct parameters.
Validation Process: Several local checks run preliminary validations, ensuring attack conditions are met. Upon passing local verifications, a server RPC adds another layer of validation to prevent mismatches or cheating.
Damage Processing: After hit detection, the system evaluates damage, type, and associated attributes, then feeds that information into other in-game systems such as UI (Kill Tracker, Healthbar, Damage Pop, and more).
Audio-Visual Augmentation: Integrated sound and visual cues, including animations and particle effects, amplify each attack for a more exciting combat experience.
Inter-system Cohesion: The Attack System collaborates seamlessly with the character’s stats, items, weapons, enchants, and other game mechanics.
Multiplayer Compatibility: The system replicates essential data across clients, offering fluid and synchronized combat actions.
Interaction System
ELVERA’s Interaction System was designed to simplify and unify player interactions within the game world. At its core is the Interactable Actor interface, serving as a universal foundation for most interactions. This approach ensures streamlined gameplay, reduces redundant logic, and provides players with an intuitive mechanism tied to specific keyboard inputs.
Design Approach: At the heart of the system lies an interface named Interactable Actor. This interface is equipped with functions that track interaction types, verify whether the actor is within range, manage the interaction process, and facilitate cancellation and successful completion.
Base Class: Any actor intended for interaction inherits from the InteractableActor_Base class. This base class goes hand in hand with the interface, enabling it to use its functions and data accordingly. It holds the InteractableActor_Info struct, which stores information like name, distance for above-head widget visibility, interaction range, interaction type, base interaction time, tick frequency, and more.
Types of Interaction: The system has two principal types: Instant and Progressive. Instant interactions finish immediately on activation. Progressive interactions require players to hold the interaction key for a set duration. The latter is susceptible to interruptions such as crowd control, death, displacement from range, or the player releasing the button prematurely.
Interaction Process: Once a player presses the mapped key, a server RPC checks the overlapping interactable actor for the presence of the interface before invoking OnInteract(). The shared logic for this function is defined in the base class, though all children can override it to accommodate their needs.
Start of Interaction: Once OnInteract() passes all checks, HandleStartInteraction() comes into play. This function sets parameters including identifying the interacting character, updating the interaction status, and creating relevant UI elements such as the interaction widget.
Post Interaction: Upon successful completion, HandleSuccessfulInteraction() clears timer handles, resets values, removes UI elements, and more. While this function contains general logic suitable for all interactive actors, it can be overridden for each child if needed.
Checks: The system has several checks in place: allowed teams, the player’s current interaction state, the interactable actor’s current state, and others.
In-game Specific Interactions: The game contains a wide range of interactions, from sabotage of certain objects and repair tasks to other interactable elements across the map.
Multiplayer Compatibility: The system replicates essential data across clients, offering fluid and synchronized gameplay interactions.
Buffs & CC System
ELVERA’s Buffs & CC System is a comprehensive component attached to the character base class, designed to manage and apply various buffs, debuffs, and crowd control effects. It integrates seamlessly with the character’s statistics structure, ensuring that buffs, debuffs, and CC can dynamically modify a player’s stats and states during gameplay. Through unique identifiers and organized tracking arrays, the system ensures efficient application and removal of effects without overriding or clashing.
Design Approach: I went a bit off-standard with this one. It uses a unique dual-purpose design that allows buffs to take on positive or negative values, serving as buffs or debuffs respectively. This reduces the complexity often associated with distinguishing between the two. Additionally, the system is tied closely with CC management, which is handled in a very similar way.
Character Stat Structure: The system works in tandem with the character stats structure in the base character class. Divided into base and bonus stats, it ensures a clear distinction between static attributes (influenced by weapons) and dynamic attributes that respond to gameplay elements like buffs and debuffs.
Buff Application Logic: The most notable function is ApplyBuff(). Using this function, buffs can be added by recognizing parameters like buff type, value, and source. According to those input parameters, a struct entry with all the relevant info gets created inside the dedicated array that holds all active buffs.
Buff Tracking and Removal: An internal array called Buffs provides the backbone for buff management. Several recalculator functions use the information from the array and update the character’s stats accordingly. Since each array entry stores the globally unique identifier (GUID), it enables efficient tracking and precise removal when needed.
Crowd Control Mechanism: Drawing inspiration from the buff management, the crowd control mechanism uses ApplyCC() and RemoveCC() functions. A dedicated enum differentiates various crowd control types. This interfaces with the state structure in the base character class, which captures current conditions using flags: IsMoving, IsRotating, IsInAir, IsCasting, IsAnchored, IsInteracting, IsInvisible, and IsDead.
Simultaneous Effects: The game can layer multiple crowd control effects on characters simultaneously, such as stuns, roots, and silences. The system’s architecture guarantees no overriding, allowing effects that do not interfere with each other. The same applies to buffs, where one player can have dozens applied at the same time without any issue.
Universal Application: Beyond abilities, other game elements such as weapons, enchants, and other aspects can also apply buffs, debuffs, or crowd control, showcasing the system’s adaptability and broad use.
Multiplayer Compatibility: The system replicates essential data across clients, offering fluid and synchronized combat actions.
Character Selection
While developing the Character Selection System for ELVERA, my main goal was to ensure a seamless, fair, and strategic introduction to the game. Drawing inspiration from League of Legends, I aimed for a streamlined yet comprehensive experience.
A crucial element is connection verification, essential for a synchronized game start and for eliminating discrepancies. Each player is systematically assigned an order index and team upon server travel to character selection from the lobby, enabling a turn-based selection process. As characters are chosen, they become unavailable for others, emphasizing uniqueness in gameplay roles.
A highlight of the system is its adaptability, capable of accommodating varied team sizes, from 1v1 matches to larger 3v3 showdowns. It automatically adapts to the number of players traveling from the lobby.
Design Approach: League of Legends was a core inspiration, with a primary goal of facilitating strategic decisions, promoting teamwork, and providing a seamless transition from lobby to gameplay. The system prioritizes user experience, ensuring players have enough time and information to make informed decisions while being adaptable to various match scenarios and team compositions.
Dedicated Selection Environment: A separate level includes its own unique game state, game mode, player controller, and player state for an undistracted character selection experience.
Connection Verification & Synchronization: A timer mechanism verifies all player connections from the lobby, ensuring every player is on the same page before the game starts.
Character Availability Tracking: As characters are chosen, they are marked unavailable in real time, avoiding duplicate picks and ensuring diversity in gameplay roles.
Dynamic Character Preview: Before and after making a selection, players can preview characters and their capabilities, helping them understand abilities. Especially useful for new players making informed decisions.
Adaptive Timers for Selection: A dynamic timer system indicates the time left for each player’s selection, including text and progress bar cues to avoid unnecessary dodge situations.
Penalty Mechanisms: If a player does not make a selection within the allotted time, the session is canceled to avoid gameplay disadvantages for either team. That player receives a rating penalty. If the “naughty” player is the listen-server host, the penalty is doubled.
Integrated Chat System: The character selection level incorporates a chat system with team and all-chat modes for player communication.
Modularity and Adaptability: The system dynamically adapts to different player counts, from 1v1 to 3v3 scenarios. Everything is designed to be dynamic and not hardcoded.
Comprehensive Player Data Struct: A PlayerInfo_CharacterSelection structure in the player state stores information like assigned pick index, team, selected character, and other crucial details, used for gameplay initialization upon travel to the gameplay level.
Multiplayer Compatibility: The system replicates essential data across clients, offering fluid and synchronized combat actions.
Technical Details
- Engine: Unreal Engine 5
- Languages: C++ and Blueprints
- Networking: Unreal replication system with Steamworks SDK integration
- Architecture: Data-driven hero/ability system, modular event framework, component-based combat
- Platform: Steam (PC Windows)
- Build Pipeline: Automated builds, Steam upload, branch management
Design Approach
My approach to ELVERA was always gameplay-first. I’d prototype a mechanic, get it playable as fast as possible, then iterate based on how it actually felt in-game. Community playtesting was a huge part of the process. I ran regular sessions with players, collected feedback, and used that to shape everything from hero balance to round pacing.
The faction system and round events were born from wanting each match to feel unpredictable. I didn’t want players to solve the game after a few rounds. The combination of hero variety and dynamic events was my answer to keeping things fresh.
Balancing a PvP game as a solo developer is tough. I relied heavily on data from playtests, tracked win rates across heroes and factions, and made incremental adjustments rather than big sweeping changes. It’s not perfect, but the process taught me a lot about live balancing and reading player behavior.