Back to projects

University team project

A Little Lost

An atmospheric 3D exploration game built in Unreal Engine 5 by a team of eight.

  • Unreal Engine 5
  • C++
  • Blueprints
  • Team of 8
Lumi travelling by boat through the fog-covered world of A Little Lost.
RoleGameplay & Systems Programmer
EngineUnreal Engine 5
Team8 developers
FocusInteraction, dialogue & progression

In motion

Gameplay and systems

Selected moments from the team's gameplay recording, showing the systems and player-facing features in context.

Systems contribution reelA silent 67-second edit connecting my Unreal C++ work to the interaction, dialogue, and progression systems running in game.
Lumi standing at the back of a small boat in a foggy flooded landscape.
Journey through the flooded worldLumi travels between islands by boat, using distant lights and landmarks to navigate through the fog.
Gameplay highlightsA 74-second edit from the team playthrough, covering exploration, boat travel, NPC dialogue, and the lighthouse sequence.
StoryFlowManager C++ state definitions open in the Unreal Engine development environment.
Story state implementationThe StoryFlowManager defines readable states that coordinate objectives across the home area, islands, and lighthouse.
Lumi speaking with the Gatekeeper NPC beside a lamp-lit dock.
Dialogue in contextNPC conversations respond to progression and provide narrative guidance without interrupting the atmosphere.
Lumi exploring an island while an objective counter is visible.
Exploration objectiveCollected items and solved objectives update the shared progression state that controls what happens next.
Lumi speaking near the illuminated lighthouse at the end of the journey.
Lighthouse finaleDialogue, objectives, collected items, and level events converge in the final lighthouse sequence.

Overview

Project concept

A Little Lost is an atmospheric 3D exploration game about Lumi, a small creature who leaves home to search for a missing loved one. The player travels by boat through a flooded and mysterious world, visiting islands shaped by the memories and grief of their inhabitants.

The experience is built around calm exploration, environmental puzzles, crafting, and visual storytelling rather than combat. Warm lights and inhabited spaces contrast with cold water and fog, creating a world that feels inviting and unsettling at the same time.

Role

What I worked on

I worked as a gameplay and systems programmer in a multidisciplinary team of eight. My original responsibility covered the interaction and dialogue systems, but it grew into coordinating much of the game's narrative progression as the project became more story-driven.

I created a reusable Interactable Actor base that allowed the player to talk with NPCs, collect objects, and use world elements through a consistent interaction flow. I also developed the dialogue framework, including speaker names, multi-line conversations, short gameplay messages, and dialogue selected from the player's current progress.

To connect these features across the full game, I built the ProgressionManager and StoryFlowManager. These systems tracked completed events, selected objectives, unlocked routes, responded to inventory changes, and ensured that dialogue, puzzles, and level transitions occurred in the correct order.

Design focus

Core pillars

Exploration over combat

The player advances through observation, travel, conversation, and environmental problem-solving rather than fighting enemies.

Narrative progression

NPC dialogue, found objects, puzzles, and new destinations work together to guide the player through Lumi's journey.

Atmosphere with purpose

Fog, water, sound, and warm points of light support a quiet, melancholic world without interrupting exploration.

Implementation

Technical contributions

Reusable interaction framework

Built a C++ InteractableActor base and specialized interactions for NPCs, pickups, docks, doors, the gramophone, puzzle panels, and the lighthouse engine.

Data-driven dialogue

Created dialogue assets with speaker data, multiple lines, progression requirements, blocked states, completion flags, and support for automatic cutscene dialogue.

Progression and objectives

Implemented flag-based state tracking and objective updates that connected conversations, collected items, crafting, puzzles, and island access.

Cross-system integration

Integrated the story flow with Blueprints, inventory events, boat travel, cutscenes, level transitions, interaction prompts, and systems owned by other programmers.

Process

Implementation notes

Conditional conversations

NPCs evaluate required and blocked progression flags, then start the first valid dialogue entry. A conversation can set a new flag when it ends, allowing narrative events to drive the next objective.

Story state coordination

The StoryFlowManager translates many small gameplay flags into readable story states for the home area, three islands, the second level, and the lighthouse finale.

Player-facing feedback

The dialogue manager handles short messages and longer conversations, locks movement when necessary, supports input-driven or timed advancement, and restores the interaction outline when dialogue ends.

Code samples

Selected C++ systems

Excerpts from systems I contributed to during the project, lightly trimmed for a focused portfolio presentation.

NPCInteractable.cpp

Progression-aware NPC dialogue

Selects the first dialogue entry whose required flags are present and whose blocked flags have not been set.

bool ANPCInteractable::DoesEntryMatch(
    AProgressionManager* Progression,
    const FDialogueEntry& Entry) const
{
    if (!Progression &&
        (!Entry.RequiredFlags.IsEmpty() ||
         !Entry.BlockedFlags.IsEmpty()))
        return false;

    for (const FName& Flag : Entry.RequiredFlags)
        if (!Flag.IsNone() && !Progression->HasFlag(Flag))
            return false;

    for (const FName& Flag : Entry.BlockedFlags)
        if (!Flag.IsNone() && Progression->HasFlag(Flag))
            return false;

    return true;
}
ProgressionManager.cpp

Small, shared progression API

Keeps story state accessible to C++ and Blueprints through a focused set of flag operations.

void AProgressionManager::AddFlag(FName FlagName)
{
    if (FlagName.IsNone())
        return;

    ProgressFlags.Add(FlagName);
    UE_LOG(LogTemp, Warning,
        TEXT("Added progression flag: %s"),
        *FlagName.ToString());
}

bool AProgressionManager::HasFlag(FName FlagName) const
{
    return ProgressFlags.Contains(FlagName);
}
StoryFlowManager.cpp

Event-driven story refresh

Responds to inventory pickups on the next frame, updates the narrative state, and refreshes player objectives.

void AStoryFlowManager::HandleItemPickedUp(
    FName ItemID,
    bool bFirstPickupEver)
{
    GetWorldTimerManager().SetTimerForNextTick(
        FTimerDelegate::CreateWeakLambda(this,
        [this, ItemID]()
        {
            CacheRuntimeReferences();

            AProgressionManager* Progression =
                GetProgressionManager();
            if (!Progression)
                return;

            TryShowAllItemsFoundDialogue(Progression, ItemID);
            UpdateStoryFlow();
            UpdateObjectiveSystems(CurrentStoryState);
        }));
}

Reflection

Challenges

The largest technical challenge was that dialogue, inventory, puzzles, travel, and objectives all depended on the same evolving story state. As the project grew, a change in one system could easily affect several others.

The original design considered both single-player and local co-op. Removing co-op was an important scope decision because it would have affected cameras, input, interactions, dialogue, puzzle design, and testing across the entire game.

Learning

What I learned

I learned that a dialogue system is not automatically a story system. Narrative gameplay also needs explicit ownership of state, objectives, dependencies, and the rules that decide what can happen next.

I also gained practical experience integrating systems written by several programmers, debugging dependencies, and keeping shared interfaces understandable enough for teammates to use safely.

Next steps

Future iterations

I would begin a future narrative project with a more data-driven quest structure and clearer boundaries between dialogue, progression, story flow, and individual interactables.

I would also rely more consistently on delegates and gameplay events so the story reacts to changes instead of checking the complete state every frame.