Frest (WIP)

Unravel a forgotten world. Discover your power. Decide its fate. When Riley stumbles across a mysterious portal in her backyard, she’s transported to Nekojima—a mystical world teetering on the edge of collapse.

Timeframe: Ongoing since August 2024 - Currently in Alpha
Team Size: 13 people
Roles: Gameplay Programmer
Genre: 3D Platformer Collectathon
Scope: 30 - 45 minute experience, featuring 10 levels, nine areas, six unique mechanics, multiple collectibles, and a lore codex.
Download Link

responsibilities


  • Various interaction mechanics

  • Level Sequences

  • Optimization and Debugging

Interactions

My assignments in Frest covered progression tracking, world mechanics, and stitching together gameplay spaces using Sequencers.

My work always starts with questions about all possible interactions and a sketched out system. I confirm with designers that my system will work as they intended before starting to implement in engine.
When implementing, I make sure to avoid hard-coded variables so we can finetune the feeling of a mechanic. Once it’s functional and playable, I playtest with designers to ask where polish needs to be added.
Taking that information, I implement all models, SFX, and VFX required, and retest them with designers for additional revisions. This is repeated until we agreed on the quality of the mechanic.

Push Block


There were two ways to go with the Push Blocks, physics or sequencers. It was first decided to use physics to keep control on the player the whole time. After the first round of revisions, we realized that the system was too difficult to polish. Bugs would appear to be random and reoccuring, and it was harder to finetune the physics values to work the way we want.

Following a round of revisions we swapped over to sequencers. This was decided as when we referenced the sketched system and all planned iterations, the block only needs to go forward and backwards, so we swapped to using sequences.

The Push Block checks if the player is pushing forward or backwards and plays the appropriate sequencer - if at either end of an array it just cancels. It uses dot products of the player character’s forward vector and the cube’s pre-determined advance vector to decide to move forward or back.

Goo pod


Unlike the push block, the goo pod’s production process mainly focused on polishing and bug testing.

The player uses the goo pod to allow wall climbing on regular walls. The pod is picked from a source plant and explodes on impact after being thrown. It leaves behind a bright, sticky substance.

The goo plant spawns a pod when interacted with, attaches it to the player’s hand, and disables interactions. This pod has a reference to the plant, which it uses to reload the plant. When thrown, its collision is activated, and on impact spawns multiple area-of-effects. Within these areas (seen in-game with the Goo Decal), the player can climb and maneuver. After 10 seconds of no interaction, the areas will despawn.

Time slow


Since our game isn’t physics-based, the time slow needed to be implemented per mechanic. Things affected by the time slow include: the Ice Push Block, Falling Platforms, and some Sequences.

The time slow follows a similar setup to the Goo Pod, with a source pickup that can be interacted with and reloads on use of the spawned item.

When used, the hourglass will look for objects that can be slowed down, denoted by the implementation of an interface. This interface is pinged and returns the size and length of the slowdown, which influences the size of VFX and how long the timeslow will last.

The class called is then responsible for slowing down any timers, sequencers, or per-update functions until the time is up or the player dies.

Reset manager


The player respawning and then being stuck waiting for things to respawn, so we implemented a manager that resets sequencers, source pickups, and deletes spawned gameplay objects like the Time Slow VFX.

Sequences

Sequences were the primary way we stitched together the game from being a string of levels with no emphasis. We were able to bring a new level of polish by showing the main character impacting the world regardless of the player’s input.

I was given free rein over the direction of the sequencers, but was given a basic description for each sequence. From this description, I thought more about what the player will be seeing and how they will process the information, and created a sequence around the delivery of that information.

There were three kinds of sequencers we used: Platforming, Reuseablity, and Cinematics

platforming


Our designers got creative when they thought of slowing down time. The best way we say to work it was with repeating sequences to establish a pattern that our players will recognize and traverse after slowing down time.

This sequencer type is used heavily in World 3 to use with our slow-down mechanic. The sequencer is intended to be looping to teach the player the rhythm of the section so they can know when to time their activation.

Reuseability


This type of sequencer was used mainly in our Boss Level, where we needed large groups of actors to travel downward after being hit by Ben’s laser blast.

Since level layouts are subject to change, I parented the actors under an empty one and cut down the sequencers to use only the Z-location and the Rotation channel. Then no matter how were oriented, they’d follow the same movement.

cinematics


To enter side areas, we decided to show the player travelling off the beaten path with a sequencer for each level. This showed me how to use dynamic binding and per-sequence spawning, and in implementation, allowed me to use a proxy player to direct movement and animation, and then use the real player in the level.

Our other cinematic for the final boss works similarly, where we grab the player’s pawn as a reference and manipulate it’s animations and movements so we don’t have overlapping player models.

Optimization

Nearing the end of the project, we needed to hit key performance targets for low-end hardware, and stability targets for more capable hardware. The work shown taught me a lot about pinpointing issues using traces, and how to tweak the engine to match artistic goals.

performance


Given our game’s low-poly aesthetic, our first thought was to strip Unreal of its enhanced capabilities.

From there, we benchmarked and set target hardware for:

  • Minimum: 4gb of RAM, 4gb of VRAM, and generic integrated graphics for 1080p@60fps Low

  • Recommended: 4gb of RAM, 8gb of VRAM, and an RTX 3050 for 1440p@120fps Ultra

To hammer down performance, we used Unreal Insights to pinpoint key functions that needed to be reworked to save on cost. We first identified whether it was an engine feature or a script. If it was an engine feature, it was disabled or edited to match our aesthetics and goals. If it was a script, we tried to remove it from the Event Tick and use custom loops to replace its costliness.

Following this, we traded virtual shadow maps for regular shadow maps and baking, turned off Nanite, and disabled runtime ray tracing. On the code side, we managed to get about 10% faster by refactoring our code.

settings


Unreal’s systems for settings and scalability sucks, so we made our own. On initial load, it reads the player’s chosen settings with High as the default.

Using the settings level, it reads variables from a data table and calls multiple console commands to set the engine’s settings to our finetuned settings.

Reflection


Frest was my first major project in Unreal. I learned not just the engine, but how do adapt my programming and Unity knowledge to Blueprints and Unreal.

I got to put to the test what I’ve been taught and see how flexible those techniques are by using them with an unfamiliar and very different programming system.

It’s also given me a great chance to increase my breadth of knowledge, working with artists for materials and VFX, making sequencers and level tools with designers, and my producer and creative director on how to construct a proper team.