FrostRunner

Overview

 

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)

  • Download: Steam

1024px-Steam_icon_logo.svg.png

Character Movement

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.

fr_prototype_tracer.gif

Tracer

Player moves forward with a certain amount of distance

fr_prototype_warpath.gif

WarPath

Player casts a projectile and then activate to follow its trail

fr_prototype_tether.gif

Tether

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. 

fr_final_tether_edited.png
fr_tether_chain_edited.png

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.

fr_starttether.png

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.

fr_character_datatable.png
fr_gamemodes.gif

Character movement features are changed accordingly to game modes

fr_leaderboards.gif

Game mode-based leaderboard data 

Level Progression

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

UI Implementation

Main menu. Starting off a new game will pop up a warning dialogue widget if players already have local saved data.

fr_levelselect

LevelSelect menu navigates through each level showing player's current progress

fr_mainmenu_rotation

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

fr_pausemenu

Pause menu with background blur

fr_hud_aim

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

fr_hud_timer

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

fr_endgatemenu

Level complete menu tells players how they did in this level, compare with their best time and people on the leaderboard

 
 
 

Sound Functionality

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.

fr_soundfunc.png

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.

 

fr_persistentaudio_blueprint.png