Ravenous Sky

Technical Designer

3C & Character Controllers | Debris & Bullet-Time Systems | Dynamic Audio Systems | UE5 C++

Summary


Ravenous Sky is a contemplative adventure game built in Unreal Engine 5 over an 18-person, roughly 9-month FIEA capstone production. The world has been swallowed by a single unending storm. Aya, the protagonist, sets out to investigate it — pulled toward a lighthouse that never leaves the horizon and always seems tied to whatever caused this. The story is carried mostly through environment and tone rather than dialogue or cutscenes.

The core hook is survival against nature itself: there are no enemies, only wind, falling debris, and lightning constantly reshaping the space around the player. On the technical side, I owned the 3C feel of that struggle — gradual wind influence and player-driven bracing counter-force — the full debris system, and a bullet-time debris avoidance system built on real-time trajectory prediction. I was also the sole owner of the game's dynamic soundtrack system.

The project wasn't entered for outside recognition — its milestone was presenting and showcasing the finished build alongside FIEA's full capstone cohort to industry professionals and the public.


Project Details


Content
One large level split into 5–6 sequential sublevels, each introducing its own core novelty (e.g. a wingsuit unlocked on sublevel 2)
14 distinct debris hazard types reacting to the storm's wind and lightning state
No enemies — the environment itself (wind, debris, lightning) is the game's antagonist
Environmental storytelling carrying the narrative in place of dialogue-heavy exposition
In-world journaling system letting the player track discoveries and lore fragments

Systems
3C wind & bracing controller: gradual wind force with player-driven counter-bracing and graduated speed response
Fully owned debris system: pooling, data-driven configuration, and a debris parry shield mechanic
Bullet-time debris avoidance: real-time trajectory prediction triggering time-dilation and UI feedback
Dynamic soundtrack system: state-driven transitions and runtime audio control


Team and Time


Team Size: 18
Time: 9 months (November 2025 – July 2026)
Engine: Unreal Engine 5 (C++)

Goals


Ravenous Sky set out to deliver a contemplative adventure game where the player's understanding of the world comes from moving through it and reading its environment, not from being told about it. The storm needed to feel like a force of nature the player is small against, not a conventional obstacle course — the goal was for players to come away having learned, in the game's own words, that nature is above you.

From a technical design standpoint, my goals centered on gameplay feel and readability under constant environmental pressure. The wind and bracing systems needed to feel physically grounded and reactive rather than scripted, so the player's sense of fighting the storm stayed consistent from the first sublevel to the last. The debris system needed to threaten the player fairly — dangerous, but always readable — which is what drove the bullet-time avoidance system: giving players a fair window to react to trajectory-predicted incoming hits instead of relying on twitch reflexes alone.

The production constraint was an 18-person team working across roughly 9 months, which meant my systems had to stay stable and data-driven enough for designers and level artists to iterate on sublevel content (new debris placements, new wind behavior per sublevel) without needing to touch my underlying code.

Systems


3C Controller: Wind & Bracing

Gradual wind force applied to the player based on the storm's local wind state, rather than a flat constant push
Player-driven bracing: a counter-force input that pushes back against wind proportionally to how it's held
Graduated speed response tuned so movement feel changes progressively with wind intensity rather than snapping between states
Tuning pass focused entirely on gameplay feel — owning the moment-to-moment sensation of fighting the storm

Debris System

Object pooling across all 14 debris types to keep runtime performance stable under constant spawning
Data-driven configuration so debris behavior and spawn parameters could be tuned per sublevel without code changes
Debris parry shield mechanic giving players an active defensive option against incoming hazards
Fully owned end-to-end: spawning, pooling, configuration, and the parry interaction

Bullet-Time Debris Avoidance

Real-time trajectory prediction detecting incoming debris collisions before impact
Triggers a time-dilation ("bullet-time") window paired with UI feedback to telegraph the threat
Built as an extension of the 3C controller work, giving players a fair reaction window against fast, unpredictable hazards

Dynamic Soundtrack System

State-driven transitions between musical states tied to gameplay context (calm exploration vs. active storm pressure)
Runtime audio control layered on top of the transition logic
Solely owned system — sole engineer on the soundtrack's technical implementation

Technical Challenge: 3C Wind & Bracing Controller

The storm needed to feel like a constant, physically believable force the player was actively fighting, not a scripted hazard that only mattered in scripted moments. A naive implementation — a flat force applied whenever the player is in a "wind zone" — would read as arbitrary and would not scale across 5–6 sublevels each meant to escalate the storm's intensity.

The challenge was building a controller where wind felt gradual and reactive, and where the player had a meaningful, skill-expressive way to resist it, rather than just enduring it.

Early on, this is exactly what broke: the first pass applied wind as an instant push whenever the player entered a wind field, which read as magnetic rather than atmospheric — the player snapped into motion instead of being gradually swept.

Solution

I implemented gradual wind force scaling with the storm's local intensity, rather than snapping between on/off wind states. Layered on top, a player-driven bracing input applies a counter-force proportional to how it's held, giving players active agency against the wind instead of passively absorbing it.

Speed response was tuned to change progressively with wind intensity, so movement feel shifts smoothly as the storm escalates across sublevels instead of feeling like discrete difficulty steps.

The fix for the "magnetic" feel was lerping both influences independently by their own velocity: wind's positive (pushing) influence ramps in on its own curve, and bracing's negative (counter-force) influence ramps in on its own curve. Because the two are lerped separately rather than resolved as a single instant force, their interaction stays complex and readable moment to moment instead of collapsing into one snap-to value.

Wind and bracing system screenshot

Outcome

Wind now feels much more real than the original instant-push version — players feel a gradual pushing and anchoring rather than a magnetic snap. Feedback from playtesters and from the people we presented to was positive, specifically calling out how much more natural the wind felt compared to earlier passes.

Technical Challenge: Debris System

With 14 distinct debris types constantly spawning across a large, sequential level, the system needed to stay performant and stable under continuous runtime pressure, while remaining flexible enough for designers to tune per sublevel without needing engineering time.

The initial approach was naive: debris fields spawned and destroyed their own debris instances directly, with no pooling. This drove framerate down significantly and would not have scaled as more debris zones were added.

Solution

I built a single shared pool keyed by blueprint type — a dictionary mapping each debris blueprint to its own pooled set of instances — replacing the per-field spawn/destroy pattern entirely.

Pooling itself is automatic and not designer-facing, but the system exposes the parameters that actually matter for authoring: designers can tune the range of speed and direction variability per debris zone, and can define debris sets that spawn semi-together with a small delay between them to read as clutter rather than isolated hazards.

On top of the pool, I designed a debris parry shield: a timing-based block on a collider that destroys the debris on a successful parry. A cooldown only applies on a missed parry, keeping successful play uninterrupted while still punishing mistimed attempts.

Debris system screenshot

Outcome

Debris became one of the game's core systems and was iterated on until it hit its ceiling. Moving to the shared pool doubled framerate on our test machine, from roughly 40 to 80 FPS. The per-zone speed/direction tuning and clustered spawn sets also gave designers a real lever for gameplay variability across different parts of the level, without needing new code per zone.

Technical Challenge: Bullet-Time Debris Avoidance

Avoidance was meant to be one of the game's core systems from the start — the design idea was that Aya's ability to think fast counters the tension of the debris storm around her. But no one could get it to actually work: triggering bullet-time felt arbitrary the moment multiple debris were in flight at once. The real problem was precision in both directions — how do you trigger avoidance only when it matters, while making sure it triggers every time it matters?

The first iteration, built before I took ownership of the system, checked a sphere radius around the player and triggered avoidance whenever debris entered it. This was too blunt in both directions: it either triggered constantly or almost never, depending on how the radius was tuned.

Solution

My first pass kept the sphere as a periodic check for nearby debris, but added a cone projection from each debris object inside that sphere, with the sphere enlarged to catch debris earlier. If a debris's cone projection intersected the player, avoidance triggered. This was more accurate than the raw sphere check, but the math broke once large debris was introduced — the cone projection assumed debris behaved like points, which stopped holding once debris had real size.

The final version kept the sphere as the initial filter for which debris to check, but replaced the cone projection with a capsule sweep: the player's capsule is swept along the negative velocity of each nearby debris object to check whether the player is actually on a collision path with it. This held up correctly for both small and large debris and is the version currently in the game.

Beyond the trigger logic, avoidance also needed to be balanced against difficulty — the game was too hard without it and too easy with it fully available. I addressed this by lerping the amount of bullet-time slowdown from maximum to zero based on the player's stamina, playing into a "when you're tired, your reflexes slow down" read. This ties directly into the parry shield: a failed parry costs stamina, which in turn reduces the avoidance slowdown available — so misplaying one system has a real cost in the other. Parrying was intentionally tuned to be easier to land than a Souls-style parry specifically because the stamina/slowdown interaction already adds enough pressure on its own.

Bullet-time avoidance system screenshot

Outcome

Avoidance went from an unworkable, arbitrary trigger to a reliable core system through three iterations — sphere-only, sphere-plus-cone, and the final sphere-plus-capsule-sweep — with the capsule sweep solving the large-debris case the earlier approaches couldn't handle. The stamina-based slowdown lerp, combined with its interaction with the parry shield, gave the team a single tunable lever to balance overall difficulty rather than needing to separately rebalance debris density, avoidance strength, and parry timing in isolation.