FrostRunner is a first-person platformer "speedrunning" game, where the player is tasked with rapidly completing platforming challenges before the timer runs out. The project has 13 team members, 3 of which are programmers. I worked on character movement, in-game systems, and UIs.
Role: Generalist Programmer
Genre: First-person platformer
Dev Time: 18 Weeks
Dev Tool: Unreal Engine 4.19
Team Size: 12 (3 programmers)
Movement is Everything is one of our game pillars. Starting from the early prototype stage, I was responsible for implementing several different movement mechanics including Tracer, WarPath, and Tether.
Player moves forward with a certain amount of distance
Player casts a projectile and then activate to follow its trail
Player launches a cable at a hookable object and gets pulled to that direction
As we moved forward to POCG, character movement was nailed down to Tether according to our discussion and feedback as it was satisfying, always in control, and had potentials for skill-based learning. Then the tether mechanics was refined in details and separated into multiple stages, shoot, fling, breakthrough, and release, to bring more fun and speed to players.
There're several restrictions to shoot:
Players can only tether to certain objects which represented as crystals
Players need to aim at the crystal as well as be in the range
There's 3 limited tether count, which will be recharged when players land on the ground
Fling can be activated by jumping (space button) while tethering to the crystal. This behavior removes them from the tether and boosts them upward. Players can tether to another crystal immediately after flinging or passing through a previous crystal to perform a chain tether.
When players collide with the crystal while tethering, the breakthrough removes them from the tether and grants them a small boost forward.
With the help of Unreal’s built-in cable component, the tethering feature takes players to the air as they make their way through the levels. The cable component simulates the feeling of pulling players forward to gain more momentum and helps them to visualize where they are targeting.
In order to integrate the cable component with character movement, we added it under CapsuleComponent in the character’s blueprint. At the beginning of each frame, we hide the cable component by setting visibility to false so that players cannot see it as default. Then we created an event called “StartTether” which was triggered when players shot crystal targets successfully. In the event, we set the cable to be visible and attach the start side of the cable to character’s hand position, following a Timeline that attaches the end side of the cable to target’s location and launches the character into the air. As soon as the character passes through the crystal target or is blocked by obstacles for a certain amount of time, the “ReleaseHook” function gets called which restores character's states and set the cable back to be invisible.
The player blueprint is implemented with Unreal's built-in character movement component which provides tons of attributes to tweak movement feels. And we need players to have different feels in two game mode (FrostRunner and IceBreaker), it made iterations much easier and faster to extract all the attributes we need to adjust into a separate dataTable.
Character movement features are changed accordingly to game modes
Game mode-based leaderboard data
The game consists of 36 levels in total, 30 of them are normal levels while the other 6 of them are insanity levels which are harder and are created for people who want to challenge themselves. Players start from the first normal level and unlock levels in sequence by completing the previous one except insanity levels. Also, they're allowed to replay any of those unlocked levels.
Attributes that are related to the level progression system
Main menu. Starting off a new game will pop up a warning dialogue widget if players already have local saved data.
LevelSelect menu navigates through each level showing player's current progress
All the menus are drawn in front of an animated scene which shows major gameplay elements. Switching between menus is just a rotation to different direction
Pause menu with background blur
In the middle of the screen the crosshair shows how many tether counts left. And the crosshair scales its size to tell players if they are able to reach the crystal
The timer starts counting down as the player starts running. If they have played this level before the ghost icon will appear on its position of the bar
Level complete menu tells players how they did in this level, compare with their best time and people on the leaderboard
A lot of time went to provide hooks for playing sound effects and background music. I created event dispatchers at the location where critical behaviors are performed.
Therefore, sound designers are able to bind sound effects functions to the corresponding dispatcher. As the dispatcher gets fired, those sound effects are played or stopped as well.
Another big issue I addressed working with our lead programmer was the ability to play persistent audio across all the levels including the level transition period. After researching Unreal's built-in functionality we found out they didn't support this feature seemingly because all game settings will be reloaded as we call 'Open Level' method, even including game mode and game instance.
Finally, we did find out a hidden variable, called bIgnoreForFlushing in the audio component which can only be seen in C++. What we need to do is simply set the boolean to true and it works.