Full Sail Capstone - Re-V0lt
Re-V0lt was my final Capstone project at Full Sail University. My team and I worked on this game for four months and plan to continue working on it until it is ready for release.
Re-V0lt is a third-person extraction shooter inspired by Escape from Tarkov. Players must gather weapons and ammunition to fight their way through several unique levels and extract to ensure their safety.
Project Overview
Throughout this project, I held several roles, such as technical gameplay designer/programmer, UI designer, and level designer.
-
As a technical gameplay designer/programmer, I was responsible for many of the core systems of our game.
I personally created our interaction system, inventory system, and save/load system.
I also collaborated with other team members to create our weapons/equipment system, extraction/level select system, along with several other systems.
-
As a UI designer, I was responsible for the functionality and layout of our game select menu, settings menu, and settings submenus.
I was also responsible for the functionality and layout of our player HUD, inventory UI, stash UI, and equipment select UI, extraction UI, and several other UI’s.
-
As a level designer, I was responsible for the creation of part of our first level.
I was also responsible for ensuring all placed loot was fully up to date with our current loot systems.
Table of Contents
Game Engine:
Unreal Engine 5.1.1
Scripting:
Blueprint
Development Dates:
August 23 - Present
Build Link:
Interaction System
For our game’s interaction system, I wanted to create something more than just a simple “press E to interact.” I wanted there to be an amount of risk to interacting with something, and for that risk to be different depending on the item. Therefore, I decided to create a system that required the player to hold their interact key to interact with the world.
Our interaction system first sends out a short range trace to determine if the player is looking at an interactable object in range. If they are, then the object will be highlighted and a small message box will appear describing the interaction.
If the player chooses to interact with the item, they can hold down their interact key (bound to E) for a set duration. As they hold down their interact key, the message box will fill showing their progress to a successful interaction. Should they end the interaction early, progress will reset to zero and the interaction will fail.
Should they complete their interaction, one of two overridden functions will trigger. These two different functions allow this system to be used in situations where an object has the same functionality every time (like an item pickup or console activation), or if something different needs to happen every other time it's triggered (like a door).
The line trace and interaction functionality are programmed in an actor component that is tied to the player character. The overridden functions, message box, and set duration are programmed in a base interactable object, which is used as the parent for all future interactable objects.
Inventory System
I was inspired by Escape from Tarkov’s spatial inventory system when I was designing our system. I appreciated how it used varying sized objects with a limited inventory grid to force the player to carefully consider what gear was worth looting. I also enjoyed the small minigame of carefully sorting the inventory to ensure room for future raids.
The first part of this system I designed was the grid. While I wanted an inventory system as described above, I wanted a simpler system to reduce confusion among newer players. Therefore, I decided to give the player a rectangular grid for the inventory, rather than a shaped grid depending on the gear equipped.
However, I still wanted a player’s gear to have an effect on the grid. Therefore, I decided to add backpacks that would expand the vertical size of the inventory grid. This required redrawing the grid every time a backpack was equipped or unequipped. I also had to force items to drop whenever a backpack was unequipped and the items would no longer fit in the inventory.
After designing the grid, I needed items to populate this grid. I made a base “lootable object” actor that pulled the functionality of the interactable objects previously mentioned. This lootable object then created a new blueprint object, which my inventory was designed to hold. This blueprint object held all necessary information for the actor and inventory, such as the actor’s class, the inventory icon, and the size in the inventory.
This blueprint object was then placed into an array based on its size. This array’s size was determined based on the number of rows in the grid multiplied by the number of columns. The item would always be placed into the top left most available slot. If the item was unable to be placed, it would automatically rotate the item 90 degrees and attempt to place it again.
After an item was placed, the player can able to move the item anywhere else in the inventory by dragging the item. They are also able to rotate the item 90 degrees to better fit it into a full inventory or drop the item by dragging it out of the grid.
The player is also able to equip weapons and backpacks by dragging them from their inventory onto certain slots. The items that can enter these slots is determined by a custom tag, which is set for every item in the blueprint object. Should the tags match, the weapon or backpack would become equipped. Should the tags not match, the item would reset to the top-left-most inventory slot, or drop on the ground if no slot was available.
Weapons
For our weapons system, I collaborated with another member of our team (Holden Doerksen) throughout development. I focused mostly on integrating the weapons with the inventory system, as well as designing some of the more unique weapons.
The first challenge we encountered was how to pull the equipped weapon information from the inventory in a stable and reliable manner. To accomplish this, we decided to add a new structure to our inventory object blueprint that stored all relevant weapon information, such as damage per bullet, magazine capacity, and weapon range.
Ammo was handled in a very similar fashion. We added an ammo information structure to the inventory object blueprint again and created several functions to handle that information. However, ammo was more complicated as I wanted to have the inventory handle ammo management so that the player wouldn’t need to constantly re-stack their ammo supplies.
I designed several weapons for our game, but I would like to showcase two of the more complex weapons. Our sniper rifle presented a unique challenge. I wanted the rifle to use a first-person scope while aiming the weapon, but our game was a third-person shooter. To accomplish this, I adjusted the camera’s FOV and distance to the player to hide the player from view. I then added a unique crosshair that covered the entire screen to simulate a sniper rifle scope.
The projectile held the unique boomerang code. This projectile had two different areas it used to check for overlaps: a Track Zone and a Hit Zone. The Track Zone looks for any enemy AI characters overlapping it’s zone. If it detects one, it sets the projectile to automatically home onto the overlapping AI. The Hit Zone then looks for an overlap with the enemy AI. This was used as we found projectiles to be unreliable in testing, so I used this to increase the hit radius to a more reliable size.
Integrating Weapons and Ammo with our Inventory System
Designing Unique Weapons
This allowed us to create several functions in the inventory component script for handing the information for equipped weapons. These functions would pull the weapon information from the equipped weapons and send that information to our weapon component script for further handling.
This meant that the functions I created to handle the ammo information would need to automatically pull ammo from the smallest stack in the inventory, move to the next stack if necessary, and delete empty stacks. I accomplished this by sending a request integer to a function and re-running the function with a while loop until that integer was satisfied. In the while loop, I retrieved the smallest stack of the correct ammo type, removed the ammo from the stack while adding it to a new temporary variable, and deleted the stack if necessary. Once the integer was satisfied, I then sent that information to the weapon component to add the ammo to a weapon’s magazine.
The other weapon I would like to showcase is our exploding boomerang. This was a fun weapon idea that was given during a brainstorming session that proved to be a very interesting challenge. First, I had to create custom code for firing the weapon. All of our weapons up until this point used line traces to determine if something was hit. I used a different function to spawn a projectile.
While the boomerang is not detecting any AI, the following path is followed. The boomerang projectile flies in a straight line slightly angled from the player. After a set time period, it then begins to rotate back towards the player. Once this rotation is finished, it then homes in on the player’s position. Once it gets near the player, it will return to it’s original equipped slot or add itself back to the inventory.
Equipment
For our equipment system, I once again directly collaborated with Holden Doerksen for its design and development. I created the base system for our equipment and our game’s grapple hook.
For our equipment system, I wanted these to be skills the player used, rather than items in their inventory. This would restrict them into only bringing in certain equipment items, rather than them potentially bringing in all equipment and using it whenever they wanted.
Since I didn’t want players to be able to switch equipment on the fly, I created a custom UI for switching equipment. This UI is capable of displaying any number of equipment items, displays only unlocked items, allows the player to equip two different items, and also allows the player to reset their loadout if they made changes they didn’t like.
Rather than allowing the player to grapple wherever they wanted, I wanted to restrict the grapple to specific points to help guide the player along a path. To choose these points, I perform a line trace to each target, then look at the angle to each target. The active target is the one closest to the player’s crosshairs.
Base Equipment System
Grapple Hook
While designing the equipment, I wanted it to be visible on the inventory screen, but not interactable. Therefore, I created a unique UI widget that would read the equipment information from the equipment component script and display that information to the player.
While designing our grapple hook, I wanted something simple for the player to understand, while still providing the player a unique movement option. This led me to use a pull-to-point style of grapple hook, rather than a momentum-based style as seen in games like Titanfall and Spider-Man.
Once the best target is chosen, the player can attempt to grapple. Assuming the ability is not on cooldown and the player is on the ground, the grapple line is thrown out towards the target. Once it is near the target, the player is launched into the air and pulled towards the target. As the player approaches the target. they are launched again to ensure they land on top of the target and the grapple ends.
Save/Load System
For our saving and loading systems, I encountered several challenges while learning Unreal Engine’s built in save/load systems. Most of these were simple bugs and issues, but integrating it with our inventory system was particularly challenging.
For our save/load system, I wanted it to use an autosave feature, rather than manual saves. However, I only wanted it to save at certain points, so the save system could not be used to make our levels easier. Therefore, I carefully decided when and where the game would save and load information.
Load points were easier to decide. I wanted the game to load the player information whenever the player enters a level or opens the game. This allowed me to retain all player information between levels and game sessions.
To solve this issue, I created a new structure type that stored all relevant information about our inventory objects. I then deconstructed each inventory object and stored it in an array of these structures. Upon loading the game, new inventory objects are reconstructed based on the data stored in this array. I found this to be a very stable solution to this unique problem.
Save points were the most challenging to decide. I wanted the player to be able to save the game at any time in our HUB world, but only have the game saved at certain checkpoints in our levels. I also decided to save the game whenever the player changes their equipment or exits a level.
As mentioned above, I used object blueprints to store all information in our inventory. These objects use references to communicate their information throughout the game. However, Unreal Engine’s save/load system cannot save these object blueprint references between game sessions.
To allow the player to utilize multiple save slots for a game, I created a custom UI for loading into games. This UI is the same for starting a new game or loading into an existing game, but has different functionality for each state. In the new game menu, the player can start a new save, delete an existing save, or overwrite an existing save. In the load game menu, the player can load into an existing save or delete an existing save.
Extraction/Level Select
For our extraction zones, I was once again inspired by Escape from Tarkov for how they functioned. However, I was also inspired by the Sniper Ghost Warrior Contracts games for additional functionality.
The extraction point itself is a custom set area that the player must remain in to successfully extract. As the player is in this area, a bar will begin to fill on their screen. Should they leave the area for any reason, the bar will slowly lose progress. If they re-enter before the bar has completely emptied, it will resume filling from its current position.
Should the player continue with the level, the UI will disappear and the extraction point will become inactive for a period of time. Then the player can continue playing the level as normal.
When they are ready to redeploy, they can use the level select console to deploy into a level. The first time they enter a level, it will automatically spawn them at the original player start location. Every subsequent time they choose that level, it will showcase every locked and unlocked extraction point. They can then choose to deploy at any unlocked extraction point.
Once the bar is completely filled, the player will be able to extract from the level. At this point, the extraction point will be considered unlocked for future use. A UI will appear allowing the player to continue with the level or extract from the level.
Should the player decide to extract, they will be returned to the HUB world with their entire inventory. Here they can resupply on ammo, store valuable weapons they looted, and exchange their equipment.
To keep a sense of progression, all levels are locked except for the first level. To unlock all levels, the player needs to stand in each extraction point long enough to be able to extract. They do not actually need to extract from the level, only have the UI appear on the screen.
Other Contributions
One quality of life feature I added for playtesters was a “Testing Mode” for our game. This mode unlocked all maps and equipment so playtesters could easily test any aspect of our levels without needing to progress through the entire game. It also unlocked our Toybox level to playtesters could easily access and test every weapon, equipment, and mechanic of our game in one location.
For my level design, I designed the very end of our Area 51 level. This is a small military compound that the player must traverse to fully escape the level. This was originally intended to be our game’s tutorial level, but was reworked to be the end of our first level during the final stages of development.
I also collaborated with Adam Conard and Holden Doerksen to design our game's settings menu. I mostly worked on the functionality of the menu. I programmed the audio settings, video settings, and game settings for our game.
In addition to the above systems, I also contributed on other system designs, level designs, and UI designs.
Testing Mode Inactive
Testing Mode Active
I was also responsible for the base avatar for our AI and player character. The blueprint itself is very simple, only a character mesh, movement component, and health variable. However, this provided us a platform to easily make major changes to all characters in our game.
Finally, I collaborated with Adam Conard to design our game’s player HUD. I set up part of the HUD’s layout and worked out most of the difficult scripting, including our objectives information, inventory information, and equipment information.