
Role(s): Level Designer, Tool Programmer
Team Size: 13 person
Game Engine: Unreal Engine 5
Dates: September 2024 - May 2025
Dual Shadows
A combat-focused action game set in a futuristic Asian city
-
While my main job was to design levels, I tried my best to help out wherever I could, from optimization, programming UI, baking lights, and developing designer tools. Ultimately, this project helped increase my overall skills as a game developer.
-
The Phoenix District was agreed by our team to be the best level, and was the level that we decided to show off for our demo. We kept getting very positive feedback from testing, and ultimately I’m very proud of how I balanced the melee and ranged combat while maintaining a good pace.
-
I was able to get our game, which was running between 15-20 FPS on my RTX 3070, to run at 50-60 FPS. I didn’t do any revolutionary optimization tricks, but considering I’d never optimized any game before, I consider this to be a fantastic learning experience!
What I Did Right
-
Our original game was massively over scope for our team’s capabilities and the amount of time we were given. There was a time where we wanted to have 12 different bosses! Ultimately, I think if we got a handle of the scope, we could’ve focused on improving the aspects we already had, as opposed to adding even more levels and bosses.
-
During our presentation, due to the way the projector was set up, it ultimately made the screen look incredibly dark and washed out, which was especially embarrassing as the person in charge of lighting. I should’ve taken a look at how the game looked on different monitors, and adjusted the game’s look accordingly.
-
There were some sprints where I had a ton of work to get done, and others where I didn’t really have that much to do. However, having more time on my hands gave me the opportunity lend a helping hand to other teammates, and learn a bunch of new skills, so it definitely wasn’t a complete negative. I definitely need to work on proper scheduling for a more studio-oriented work environment.
What I Did Wrong
-
I really wanted to implement a heat map system into my levels, where data can be recorded during testing, and I can act on that data to improve the flow and pacing of my levels. I actually was able to create one, but ultimately, it took too much time to fully implement into levels for testing.
-
One of the main optimization techniques that I really wanted to take a shot at was seamless level streaming, where chunks of levels were loaded in and out on the fly. However, we kept bouncing between wanting our areas to be way more open or more linear, so by the time we decided on linear levels, it was too late to really try and implement level streaming.
-
While I had a rudimentary building generation tool working in-engine, ultimately it was too unpolished with not enough features, so our artists used Houdini to create and import custom buildings. Again, it was one of the things that we ran out of time to fully implement, but having a building generation tool would’ve saved a ton of time in the long run.
What I Could Do Better

Dual Shadows is a combat-focused action game set a neon-soaked futuristic Asian city. The main gimmick of the game is swapping between your melee and ranged forms, which each have their own strengths, weaknesses, and special abilities. While my primary role on my team was as a level designer, I ended up wearing a bunch of different hats for this project, including set-dressing levels, designing tools for designers to use, programming UI elements, and optimizing the game to the best of my ability. However, for the sake of a more cohesive read, I’ll limit myself to only talking about some of the stuff I did.
To start, I was in charge of designing, set-dressing, and lighting our first level after the tutorial, based on the general level layout from one of our contractors. My main goal for this level was a balance between trying to get players to use both melee and ranged attacks, while not forcing them to use either, because one of our main pillars was player expression. With that in mind, I transcribed the level layout onto a whiteboard, breaking the level down into 6 sections.
The context of this level is that it is a run-down district belonging to the Pheonix, so when set-dressing, I tried to use a lot of the grungier buildings and flickering lights. Because this location is part of an incredibly condensed city, I stacked buildings as closely as I realistically could, and kept roads fairly narrow. As the player progresses through the level, I started to increase the amount of space and included fancier buildings, to give the sense that the player is moving out of the run-down area, and moving on towards the Phoenix, and eventually to the upscale district where the Dragon lies.
The level starts with a linear pathway to a group of melee enemies (circled), increasing the forward momentum from the tutorial section. The large amount of space before the enemies both allows the player to take their time, but also encourages to hit the enemies with a couple of ranged attacks before moving in for some melee attacks. While they might stick to range for the enemies in their sights, when the player rounds the corner they will be confronted by another group, highly encouraging them to use melee.
Afterwards, the player enters an arena, where they need to take care of another group of enemies, introducing a single ranged enemy to the mix. The ranged enemies are designed in a way where shooting them at range is pretty difficult, so this encourages the player to use melee attacks. This arena is carefully sized to still allow for ranged attacks, but at the same time having the enemies being able to overwhelm the player fairly quickly if they stay still.
At this point, I made a change to the pre-established layout. I thought, for the purpose of player expression, it would be more interesting for the player to pick between an area designed for either melee or ranged. I tried to subliminally message this by keeping a pink motif for ranged combat, while having a blue motif for melee combat. The blue area is just an alley where you get jumped by a group of melee enemies, encouraging the player to use some of their melee abilities, while the ranged area is more open, with few obstacles to block the projectiles that you fire.
From here, the player encounters the first mini-boss, which has moves similar to the Phoenix boss that the player will later encounter. The best way that I was able to contextualize this large, open area with the art assets that we had was to make this area a parking lot, which I think I set-dressed pretty well. Pacing-wise, this is the peak of combat for this level, with the last section serving as a bit of wind-down before facing the Phoenix boss.
The final section is supposed to be a smaller location where the player regains their bearings, defeats a couple low-level enemies, and then continues towards the boss. In order to keep the pacing up, I decreased the size of this area a little bit, as scattered the area with pockets of lower-level enemies, nearly guaranteeing at least one enemy encounter, but still ultimately pushing the player towards the boss.

While working on building and set-dressing my level, I found myself getting annoyed with the amount of manual jobs I was doing that I could figure out how to automate. With that in mind, I developed a multitude of different design tools, but the one I’m most proud of was the automatic sidewalk generator. Before I made this tool, we were placing 2x2 segments of sidewalk manually, and with such a large quantity of levels the amount of time it took to place down sidewalks was pretty substantial.
With a couple hours worth of code, I was able to develop a tool that automatically generated a sidewalk with appropriate edges and corners, that could fill any sized space that our designers wanted. This proved to be an excellent time saver, and a fun test of my coding abilities.
While our game was shaping up and we were going to testing, one main thing continued to bother us - our game was incredibly unoptimized! It was running sub-20 FPS on my RTX 3070 at home, so I asked my team if I could do a little bit of research into optimization techniques we could use to get our game to run better. I started with obvious larger methods to increase FPS, and worked down from there. To start, we decided it would be best for our game to have pre-baked lights. That came with its own set of issues, and plenty of late nights baking but ultimately the results spoke for themselves. After that, I made improvements that ranged from spawning enemies and projectiles in the title screen to reduce shader compilation stutter, to changing the barriers from being transparent to being masked with a dither texture, to batching buildings and trees together on the GPU. It’s not like I discovered a revolutionary way to optimize a video game, but it was a really fun new process, and I was very proud of myself for getting a game to run at 60 FPS, when it was running at 15 FPS before. I thought it was a fun challenge!