Role: Game & Level Designer
Tools Used: Unreal Engine 5, C++ Blueprints, GitHub, Miro, Jira
Timeline: June 10th - *Currently on hold*
Responsibilities Include:
Using Jira to keep track of project tasks and progress.
Using Miro for mood boards and flow charts.
Using GitHub for version control.
Designing and Implementing modular levels.
Programming the level generator system using C++ Blueprints.
Designing each skill.
Programming the skill system using C++ Blueprints.
Programming AI functionality and interactions using C++ Blueprints.
To create a rogue-like prototype inspired by Hades, with the skill-swapping mechanic from The Elder Scrolls Online, made using Unreal Engine 5.
Since finishing University, and after playing Hades II and The Elder Scrolls Online, I was inspired to create this project, currently using a temporary name called "Project Skill".
While playing Hades II, I enjoyed how distinct the skills and abilities were from the original Hades. However, like the original Hades, when you choose your weapon you're primarily locked into one play style for your run.
On the other hand, The Elder Scrolls Online offers players a system where they can easily swap their skills and weapons in between fights and encounters in dungeons and other content.
Project Skill is a stylised, dark fantasy, rogue-like with RPG elements, that aims to combine rogue-like gameplay with the freedom to change skills to better suit combat with different enemies, allowing players to play in a way that they enjoy.
Although narrative design isn't the primary focus of the project, I knew it would tie the player character, the world and the game mechanics together so I wanted to try to create a simple narrative to help me keep a clear vision for the game.
In Project Skill, the player is infected with a curse that takes the primary form of a black claw with red energy coursing through it. This curse adapts to the player character's needs but has taken away their memories. Using the adaptability of the curse to switch abilities mid-run, the player character aims to use the curse to explore a dungeon-like laboratory in which they were infected with the curse to discover its origins.
The game world is a dark fantasy setting, with hints towards larger advances in alchemical technology, that lead to the creation of the curse.
Originally the player character was trying to escape the laboratory from which they got the curse. However, I felt that this narrative was too similar to Hades, in regards to escaping a "prison". I also felt that once the player had escaped the facility, discovering its secrets as they do so, the player character would have no reason to return. With this form of narrative, I felt the game would be better off as a linear RPG rather than a rogue-like, which I was not interested in creating that kind of game for this project.
The player can press K or Tab to bring up their Curse Skill menu.
Using this menu, the player can switch between their available skills.
From their menu they can drag and drop their skills into their action bar.
These skills can be activated by pressing their corresponding button or by pressing the skill in the action bar.
There are currently 5 skills in the game.
Curse Blast
Rupture
Fear
Curse Armour
Dash
Each skill has a name, a description, an energy cost, a cool down duration, a cast time, and two bools, if they are interruptable, and if they require a target or not.
A video of each skill and its details can be seen below.
Name: Curse Blast
Description:
Shoot a blast of cursed energy towards your target dealing 50 damage on impact.
Cost: 5 energy
Cool down: 0.5 seconds
Cast time: 0.5 seconds
Is Interruptible: true
Requires Target: true
Name: Fear
Description:
Fear nearby enemies with your curse. All feared enemies cannot move for 3 seconds.
Cost: 15 energy
Cool down: 3 seconds
Cast time: 0 seconds - Instant
Is Interruptible: false
Requires Target: false
Name: Rupture
Description:
Break an enemy's defences with your curse. Afflicted enemies take double damage.
Cost: 15 energy
Cool down: 1 second
Cast time: 1 second
Is Interruptible: true
Requires Target: true
Name: Curse Armour
Description:
Cover your body in your curse for 15 seconds, reducing all incoming damage by 10.
Cost: 10 energy
Cool down: 15 seconds
Cast time: 0 seconds - Instant
Is Interruptible: false
Requires Target: false
Name: Dash
Description:
Move forward with a burst of speed.
Cost: 0 energy
Cool down: 0.1 seconds
Cast time: 0 seconds - Instant
Is Interruptible: false
Requires Target: false
Each skill is a child actor of the primary Skill actor. There are also 5 sub-categories of parent skill actors for each skill type.
Projectile skills - eg. Curse Blast
Area of Effect skills - eg. Fear
Buff skills - eg. Curse Armour
Debuff skills - eg. Rupture
Movement skills - eg. Dash
Each skill is a child of their respective parent skill.
The primary skill parent and its functions are detailed below.
When the skill is used, event begin play is called.
The skill actor is attached to the caster (player character).
For later use the third person character, the third person controller and a custom controller are then cast to and referenced.
The begin casting function is then called.
Later after other functions:
On a successful cast there is a delay of 0.2 seconds before the Cast Success event dispatcher is called for its listeners.
Begin casting is called.
The check energy function is called from the player actor. Using the skill cost from the skill details (these vary from skill to skill).
If the player has enough energy a check is made if the skill has a cast time or not.
If the skill has a cast time, the cast bar is displayed.
After a successful cast, once the cast time has finished, the cast ability function is called.
If there is no cast time, the cast ability function is called, without a need to show the cast bar.
The cast ability function is called.
The skill actor detaches from the player.
The spend energy function on the player is then called and the energy needed to cast the skill is then spent.
The Successful Cast custom event is then called.
The Interrupt Cast function is called.
The skill actor on the player is destroyed.
The event dispatcher of Cast Interrupted is called.
The interrupt cast is called from the player actor if the player moves while trying to cast.
The Activate Effects function is not called from the primary skill actor. It is instead called from individual skills for their individual effects, such as adding velocity to the player when the player uses the dash skill.
To get an idea for how I wanted the levels to feel, I looked at references from various rogue-likes and fantasy Role Playing Games. I primarily referenced the Tartarus and Erebus zones from Hades. They have a built-for-purpose feel to them, and have large open spaces for the player to fight enemies in.
I also want Project Skill to have a strong environmental narrative to fit the faster pace of rogue-likes compared to RPGs, so I found references like enemies in Elden Ring and the Dwemer ruins in Skyrim to be helpful.
Finally, I wanted to consider an art style. I decided to go with a low-poly art style, similar to Firewatch, as I wanted a contrast to the dark fantasy themes.
To make the rogue-like rooms for the level, levels would have to be split up into tiles.
I started off by drawing a rough sketch of each level tile on paper, followed by using Inkarnate, a tool for creating maps for tabletop RPGs, to map out the tiles so they could be easily understood and for changes to the design of the room before Whiteboxing.
During this process, I also broke rooms into one of two categories. Combat and resource rooms. In combat rooms such as the melee or ranged enemy room, the player will have to fight enemies. In resource rooms like the cage room, the player can find resources like an energy potion that fuels their abilities. The the laboratory room is a combination of the two, offering the player a challenging combat with the reward of a health potion.
This room changed the least, with items removed after Whiteboxing.
A barricade was removed.
Two additional pillars were added.
Indicators for where enemies would spawn were also added.
Enemy spawn indicators were placed and a shelf was added.
This room stayed the same.
Compared to other projects, I didn't need to use Unreal Engine 5's modelling mode because the level tiles were simple in shape, and were not complicated. Any detail needed could be implied with a material applied to cubes to represent what it was in the Whitebox.
Melee Enemy Room
Ranged Enemy Room
Laboratory Room
Cage Room
To get a better idea of the levels I wanted to add assets to the prototype. These are primarily placeholders, but give a strong sense of atmosphere to the level.
I used an asset pack titled, FANTASTIC - Village Pack, by Tidal Flask Studios on the Unreal Engine Marketplace for adding assets to the tiles.
While adding assets I also iterated slightly on the design of some tiles.
A pillar was removed from the Whitebox and replaced with barrels creating a barrier.
Pillars were also moved to opposing corners.
The potion of healing was also removed as I wanted to make the laboratory room more important.
Two additional pillars were added.
Each pillar was moved to a corner of the room, to give the player more space to avoid ranged attacks.
The back and left side entrances to the room were also opened so that this room better matched the melee room.
This room stayed the same from Whitebox to Asset Implementation.
It was made more important by being the only place to find a healing potion.
This room stayed the same from Concept to Asset Implementation.
To generate the level to be similar to other rogue-likes, I created a random dungeon generator using C++ Blueprints.
The room generator actor creates a simple room tile with no assets and 3 exits, followed by generating a random room tile from one of its exits.
Each exit, including exits from new tiles, are added to a list. An exit is randomly chosen from this list to generate the next tile from. Once all room tiles have been generated, all exits will be closed off.
The number of room tiles that are generated, and the delay in seconds between each one generating can be edited in the details panel of the Dungeon Generator actor in the World Outliner.
The C++ Blueprint is broken up into seven parts.
Event Begin Play.
Spawn Start Room.
Spawn Next Room.
Check for Overlapping Rooms.
Delete Latest Room if Overlapping.
Close Gaps.
Level Generation Failsafe.
Each part is detailed below.
When the player starts the game, the custom event Spawn Start Room is called.
The custom event Start Dungeon Timer is then called.
Lastly, the custom event Spawn Next Room is called.
From the Spawn Start Room event being called, a Basic Room actor is then spawned in the world at 0,0,0.
The children (exit arrows) of the Exits Folder are each added to an Exits List, so that their exit points can be used for spawning new rooms.
When Spawn Next Room is called a random exit point from the Exit List is set as the location for the next room to be spawned.
A random room tile is chosen from the room list, this includes all the above rooms.
The chosen random room tile is then spawned at the set location and is cast to the Master Room.
This room is then set as the Latest Room.
There is a delay of seconds equal to a float called Room Spawn Delay, the default is 0.1 seconds. This also helps prevent the game from crashing.
The custom event Check For Overlap is then called.
After the custom event Check for Overlapping Rooms is called, another custom event Add Overlapping Rooms to List is called.
Using a for each loop, all Box Components of the Overlap Folder from the Latest Room are checked.
If any of these Box Components are the same as any of the previous rooms, they are added to the Overlapped List.
If the Overlapped List is not empty, and has Box Components that are overlapping previous rooms, the Overlapped List is then cleared and the Latest Room is Destroyed, and Spawn Next Room is called to create a new room.
If the Overlapped List is empty, it is then cleared as a failsafe.
The integer Room Amount is decreased by 1.
The exit that the latest room was created from is then removed from the Exits List.
A new exit to generate a room tile from is then chosen from the Exits List.
If the Room Amount is greater than 0, a Spawn Next Room is called.
If the Room Amount is less than 0, the custom event Close Gaps is called.
Dungeon Complete is then set as true and the dungeon timer is invalidated so the failsafe is activated.
When Close Gaps is called using a For Each Loop, each exit in the Exits List then has a Gap Fill actor spawned at their location.
After the Start Dungeon Timer event is called, a new event and a timer are started.
The Check for Dungeon Completion event is called.
If the current game time is greater than or equal to the Time to Make Level float, the dungeon not completing is true.
The level is then reopened and the level generation process restarts itself.
Ranged Enemies - currently there are no ranged enemies in the ranged enemy room. I would like to start working on this soon.
Tab-Targeting - to hit an enemy accurately you need to target it. I plan to allow the player to switch targets by using a button.
Melee Skills - all skills encourage a ranged playstyle. The next skill I plan to add is the Cursed Claw skill.
Dash - currently the dash skill just adds velocity, making it look like the player is slipping on ice. I would like to change how the dash skill is programmed or the physics of the player to fix this problem.
Energy Maintaining - energy is used up quite quickly, and it is up to random chance if any energy potions will spawn. I plan to change this by giving the player energy back for killing an enemy.
Rupture Particle Bug - the rupture particles stay after an enemy dies. I plan to fix this bug so the effect disappears when an enemy dies.
Banner Image: Vampiric Claw - [2D VFX] Some simple VFX practice, by Bastian Köth.
Narrative Image 1: Lilith Nelson, by Death Is No More.
Narrative Image 2: Carnage resdesign, by brakken-spideyverse.
Narrative Image 3: Wanuki Akria, by unknown.
Level Assets: FANTASTIC - Village Pack, by Tidal Flask Studios.
Skill Icons: Ability Icons, from The Elder Scrolls Online.