top of page
DL_Poster_edited_edited.jpg

Duolatera

Synopsis

Duolatera is a VR 2 player Online Cooperative Escape Room-like Puzzle Game built with Unreal 5 featuring interactive Portals that can be physically walked through.
​
After an experiment on a strange artifact has gone horribly awry, you and your partner are marooned in an unknown world. Using mysterious Portals bridging mirrored realities, solve puzzles and outmaneuver the ancient architecture surrounding you and find your way back home.

My Roles

Graphics Programming
Gameplay Systems Engineering
Technical Design & Level Design
Sound Design & Music Composition

Team Size

5

Development Time

Aug 2024 - May 2025

Tools

Unreal 5, VR, C++, Blueprints, HLSL, Unreal Insights, MetaSounds, Perforce, Trello, FL Studio

Portals in Virtual Reality

Portals are the primary mechanic of Duolatera, and can be walked through seamlessly like a door.

 

When moving through a portal, you are taken to an alternate reality that closely resembles the real world, but with some differences that play key roles in the game's puzzles.

​

I implemented the rendering and physics of these Portals. For rendering, I used Scene Capture components which capture the exit portal's view as render textures. Then, in a post-process, I used stencil masking to render the portals with these textures. I also implemented the functionality for drawing a closed shape on the wall to open a portal.

​

There are lots of complications with how this is done in VR, especially with there being two eyes to render instead of one. I wrote a research paper detailing the entire implementation process of VR Portals here.

DL_BG.png
DL_BG.png
Ring Sensor Settings
Door Settings
Result
Button & Bridge Example
Symbols & Door Example

Puzzle Creation Gameplay System

Duolatera's puzzles are all about unlocking new parts of a level to interact with, such as opening and closing doors, displaying symbols, etc. 

​

I wrote a Blueprint API in C++ that designers used to quickly build out puzzle mechanics. This event-based system is divided into:

​

Interactables: Actors that require physical input from the player, i.e. a button. Custom interaction logic can be scripted to invoke its Begin Interact and End Interact events, activating and deactivating Activatable actors respectively.

  • Can set to activate or deactivate an arbitrary number of Activatable actors when interacted

  • Can set if it's allowed to be interacted with

  • Can set if it can be interacted with when physically held (only applies to interactable actors that can be picked up)

​

​Activatables: Actors that can have custom "activation" logic which is invoked via calling that actor's Activation event from an interactable object or any other blueprint, keeping things modular and scalable as dependencies between actors are kept at a minimum.

  • ​Can be customized to invoke activation after a specific number of actors have activated it (called Required Activators)

    • ​Anything that activates an activatable is considered an activator, i.e. all interactables​
  • Can optionally remain activated even after an activator deactivates it

  • Can set whether it stays active when its number of activators goes over the required count (called overflowing) or not

​​​

The first GIF shows a Ring Sensor - an interactable whose Begin Interact executes when the player's hand enters it, and End Interact when the hand leaves. This one is set to activate the door in front of it and another door elsewhere. These doors are set to require only 1 activator (the Ring Sensor) and do not remain active, meaning they will close when the Ring Sensor deactivates them.

​

Another example shown is a Button that invokes its Begin Interact when a player presses it. This button is set to activate a Bridge actor in the 2nd level with 1 required activator, causing it to run its logic that enables collision and material VFX.

​

The last example is a set of 2 symbols that activate a door. These symbols are interactables that invoke Begin Interact when fired at, and the door is set to require 2 activators to open.

Level & Technical Design

We treated levels like Escape Rooms, mixing player experimentation, constant communication, and mechanical skill to create compelling puzzles with replayability.

​

Duolatera consists of 3 main levels. I concepted many of the puzzles for our 2nd level and collaborated closely with another programmer to ensure implementations matched the original vision.

 

I also completely designed and implemented our 3rd and final level, which involved:

​​​

  • Level Design - Built the level's layout. Where levels in non-VR games are frequently designed with player movement in mind, this level was designed with visibility in mind. The playable area should be small to avoid extraneous movement, and important landmarks should draw attention from almost everywhere.

  • Technical Design - Designed and Implemented all puzzle mechanics - more below.

  • Technical Art - Created animated materials and particles serving as visual aides and clues as players interact with mechanics​​

DL_BG.png

Puzzles for this level are categorized into 3 phases.

 

Phase 1 Concept

Introduces two Symbol Sets; sets of 4 symbols separated between the left and right sides of the room. Players are also separated accordingly. Each symbol set is tied to their own Symbol Column in the middle of the room that have a symbol glowing on them. The glowing symbol on the right Column indicates the correct symbol to activate on the left Symbol Set, and vice versa for the other Column, requiring players to communicate what symbols to activate because a player cannot see their own glowing symbol. Activating both correct symbols simultaneously by firing at them causes more symbols to light up on the column; repeating this process 3 more times completes this phase. Activating an incorrect symbol or not doing it simultaneously resets the phase and shuffles the symbols on the columns.

​​​

Phase 1 Implementation

​I made significant use of my Puzzle Creation system, creating Symbol Columns and Symbol Sets as Activatables requiring 1 activator which I set as Ring Sensors. When interacted with, the respective column displays the correct symbol, and deactivating the column hides it. The Symbols on the Symbol Set become interactable as well, and power lines connecting the Ring Sensor to these items light up as a clue to players.​​​

DL_BG.png

Phase 1

Left Side
Right Side

^     ^

Symbol Columns 

Left Ring Sensor Setup
Right Ring Sensor Setup

Phase 2 Concept

Phase 1 completion causes an extra symbol in the middle of each Symbol Set to glow and fall to the ground. They must be picked up and brought to the Underworld​ (the alternate reality mentioned in the Portals section above) and inserted into the middle of the Underworld version of the Symbol Sets. This was implemented via a very small trigger box that snaps the symbol in place when it collides.

​

Once both symbols are inserted, they can now be fired at from the Overworld (the normal world; players' laser tools cannot work in the Underworld) through a portal to activate a Memory Sequence. All 8 symbols on the Underworld Symbol Sets flash one at a time, and players must fire at each one as they flashed in the sequence. Failing resets the phase but does not reshuffle (reshuffling the sequence on failure was too frustrating for players). Completing the sequence completes Phase 2 and lights all symbols on the Underworld Columns, just as Phase 1 lit all symbols on the Overworld Columns.

​​​​

Phase 2 Implementation

​The memory sequence logic was implemented as a single Blueprint actor called BP_SequenceSystem, which shuffles the sequence only once on Begin Play. Again, this is an Activatable with 1 required activator, and the inserted symbols are both set to activate it. This means firing at either symbol inserted into the Underworld Symbol Sets can begin the sequence. The rest of this actor was specific to the sequence logic, such as displaying particles positioned above the Symbol Sets to indicate which one each flashing symbol appeared on, and replicating that visual feedback across the network.

DL_BG.png

Phase 3 Concept

With both Symbol Columns in both worlds fully lit, all symbols on these Columns are now interactable, but they differ between the two worlds except for one. Players need to compare between the Overworld and the Underworld Columns to determine the common symbol. That symbol must be shot in both worlds at the same time to activate them, at which point the rest of the inactivated symbols shuffle. After every shuffle, there is another common symbol that needs to be found and shot simultaneously. This repeats until all 8 symbols are active in both worlds, completing this final phase. Shooting a symbol that doesn't match in both worlds deactivates all symbols and resets the phase.

​

The catch here is that inactivated symbols reshuffle automatically on a timer which gets shorter as more symbols are activated, a true test of coordination and quick thinking. The timer is visualized by shaking the symbols erratically, increasing intensity over time. The intensity resets along with the timer when it hits 0.

​​​​

Phase 3 Implementation

​A lot of this exists as part of the Symbol Columns' functionality. Symbol Columns have a Destabilize​​​ event that, when called, begins their individual timers and handles the shaking behavior. Puzzle behavior specific to this level only, such as the shuffling algorithm that always guarantees exactly one common symbol, is handled in a manager blueprint called BP_ColumnManager (an Activatable). When activated by BP_SequenceSystem (yes, even Activatables can activate other Activatables), this listens for the symbols' Begin Interact events and checks if the two interacted with are on the same side Column in both worlds, the same position (bottom, bottom-middle, etc.), and are the same symbol. If yes, those two symbols activate and cause a reshuffle.

 

When all symbols on a column are activated, it invokes Activation events on all objects it is set to activate. These 4 columns are set to activate the final door, which is set to require 4 activators.

DL_BG.png

Level 3 Results

Player feedback showed that this was not only the most challenging level, but lots of fun to solve! Many players emphasized engagement from the constant coordination between each other needed to complete each puzzle.

 

From a project scalability standpoint, all mechanics created with this interactable/activatable system could easily be reused in other puzzle contexts if desired.  The Symbol Columns, for example, don't have to activate just a door. They can activate anything that's an Activatable and can be activated by anything at all.

DL_BG.png
DL_BG.png

Multiplayer Gameplay Programming in Unreal 5

I handled much of Duolatera's multiplayer networking. We used Unreal's Listen Server architecture and Replication system to maintain network synchronization between host and client. My mindset for best networking practices is:
 

  • Player input should give immediate sensory feedback but should only execute gameplay logic server-side.

  • All other gameplay logic should also happen server-side; only sensory feedback like visuals and audio gets replicated back to the client.

​

After my team adopted this practice, all gameplay functionalities became very straightforward to implement. The client was rarely out of sync with the host and very few players experienced frustration from latency or desync, even after disconnecting and reconnecting mid-session.

Music & Sound Design

I created all audio assets for our game, from SFX to music. All audio was made with FL Studio.

​

Music for each level in the game is adaptive and changes as the level progresses. Check out an example of this implementation using MetaSounds for our 2nd level.

​

Also check out the rest of the music on Soundcloud!

image.png
DL_BG.png
Door_Open
00:00 / 00:02
Door_Close
00:00 / 00:02
LaserFire
00:00 / 00:04
DL_BG.png

Accolades

Our team showed Duolatera off at multiple expo's such as:

​

  • GDC 2025 - I was one of the speakers
     

  • RIT EDGE 2025 - Won Best In Show for Experimental
     

  • ImagineRIT 2025

bottom of page