top of page

The Tomb

Introduction

Play as an explorer visiting a recently discovered ancient Egyptian tomb and 

But the Egyptians were cunning. Getting into the tomb will not be as easy as you thought. Many dangers also hide beneath the sand.

 

Will you be able to find out the lost secrets of the tomb?

Project details
  • 4 weeks, half-time (4 hours a day)

  • Solo Project

  • Unreal Engine 5

  • Third-Person Puzzle Adventure

  • Plague Tales inspired

  • Focus on Technical and Puzzle Design

  • All scripts and AI made by me

  • Majority of Assets made by me in Blender

  • Assets/Plugins used

    • Blockout Tools Plugin​

    • Good Sky pack

    • Rifle made by Rasmus Westner

    • Motion Matching Animations

    • Mixamo Animations

Overview
Gallery
Top Down
Piece2Overview.png
Puzzle Flow
PuzzleFlow1.png

 Aim the mirror at the second brazier

PuzzleFlow2.png

Shot the gong with the vertical rectangle to light it

PuzzleFlow3.png

Aim the mirror at the boat

PuzzleFlow4.png

Shoot the gongs so all lenses except the horizontal rectangle are in to light the boat

PuzzleFlow5.png

Throw out lighted torches in a line leading from the hook to the boat

PuzzleFlow6.png

Pick up the hook, carry it to the boat and attach it

PuzzleFlow7.png

Shoot the lever and follow the boat back to the other side

PuzzleFlow8.png

Pull the lever and watch the boat crash into the door

PuzzleFlow9.png

Grab a torch, light it and stroll over to the other side an through the door

The Scarabs
The Basics

​The essential function of the systems is that none of the AIs decide where they need to walk. The floor does this through a grid system that determines whether a human target is inside it. Once determined, it makes a path for the AI to take.

For this, I did not rely on the built-in Unreal Navmesh and instead built a flow field pathfinding system.

Cost Field

When I create my grid, it checks whether any objects are inside any grid squares. If an object is in the way, it sets that grid square to impassable so the system will not choose it when making a path. If needed, you can make certain squares less likely to be selected when creating a path.​​

To work with the grid squares more easily, I assigned them to maps so they have unique IDs that I can reference.

Blueprints
Intergration Field

To calculate the best path to the target, e.g. the player, the system goes through all grid squares and assigns them a number. To do this, it starts with the square the target is standing on and sets it to 0. Then it works outwards, setting each of its neighbours to its new number plus what it costs to traverse the neighbour. It continues until all squares have a new value.

This calculation is based on Dijkstra's algorithm.

Blueprints
Flow field

The system starts calculating a path. Every grid square looks at its neighbours to find the one with the lowest value. Once found, it will save the position of that square, making a line towards it. After that, it will have drawn several paths that lead towards the target

This can create a path around impassable squares, as their value is always too high to be considered by its neighbours.

Blueprints
Avoiding Fire

The scarabs avoid the light produced by the green fires. If the AI enters a grid square covered by the light's radius, the square makes the AI turn around and go in the other direction.

The system gets a maximum and minimum index of possible cells that could be overlapped. ​Then, it checks to find cells to discard that are not being overlapped. Cells in the light have an In Light bool set to true, reversing the ais calculations.

Blueprints
AI

Now, the AI can use the paths created to reach the target. When the Scarabs walk into a new square, they ask the square for directions to the next square in the path and turn towards that direction.

To reduce performance drain, the AI only ask for a new direction when switching cells, reducing the number of calls to just a few a frame. This saved me around 5 fps when playing.

Blueprints
Optimisations

To improve performance, I added the logic of only updating the paths once the player enters a new grid square. This eliminated the random FPS stuttering that I experienced.

 

As I used many for each loop, I cached as many variables as possible to reduce the times it had to get these when going through the loops. This increased my frames from around 30 FPS to 50 FPS with 150 individual AIs.

Blueprints
Grid Manager

Having multiple grids in one level was a problem that had to be solved. The solution was to create a grid manager that referenced all the grids in the level so the player could ask the manager which grid they were standing in.

This would also ensure that AI actors existed only for the currently active grid and that no calculations ran on any other grid.

Blueprints
Puzzle Elements
Lens and Mirror

While brainstorming ideas for the puzzles, I came up with the idea of using a mirror to light the braziers. The idea is that only by making a concentrated beam of light can you produce enough heat to light it.

With the lens, I could make it so that each brazier needed a different combination of lenses to light. I used simple shapes to visualize the lenses required to light a brazier.

Blueprints
The Boat

The idea of the boat started with it just being a mobile brazier. If the level had continued, the plan was for it to be something you had to bring with you, as a constant puzzle element and safe zone.

Later, it also developed into a way to solve the problem of entering the tomb by using it as a battering ram to destroy the door. This gave me a good goal for the puzzle.

Blueprints
Rifle and Interactions

I decided to use a gun to interact with objects from a range, which would also add to the theme of a 20th-century adventurer. The rifle can interact with most objects.

The player has to shoot the gongs to slot glasses into the lens. When they hit, they get a small sway effect as feedback. Each gong corresponds to one lens, indicated by the shape of the decal on it. 

Blueprints
Full Walkthrough

Commentary included

Reflections
Another Puzzle Section

My original plan was to have a section after getting through the door. In that section, I wanted to turn things around a little by having a puzzle where the goal was not to avoid the scarabs but to use them to get rid of bodies that were in the way of the boat's progress. So you would have to put out the fire and then start it again to continue forward.

However, some significant bugs in the flow field system took a while to fix, so I decided to focus on polishing the first puzzle section instead.

Introducing Mechanics

One area where I felt I could have done better was in introducing the mechanics. ​​I planned to have an NPC that you would see walking out into the danger area with a torch and seeing the scarabs trying to eat him but failing. He would then pick up the hook, putting down the torch as he does, to signify that you can't carry a torch and an object simultaneously. He would then start walking towards the boat, but because he walks outside the torch's radius, the scarabs will attack and kill him.​ Unfortunately, I did not have the time to implement this NPC, so the onboarding suffered a bit as a result.

Further Optimisations

I worked a lot on optimising the scarabs to see how many I could have at the same time without massive performance issues. At the end of all that, I could reach about 300 individual AIs on screen, all pathfinding towards you.

If I had more time, I would love to work on further optimisations. One of the biggest performance thives that I had was the amount of for each loops I used. I managed to save some performance by cashing the references it gave from the loops, but not much. I also noticed how performance would drop the bigger grids that I had, as there were even more cells that it had to loop through every recalculation

Lessons

Ultimately, I'm very satisfied with this piece and how it turned out, as I learned many lessons from it, especially around optimising my scripts.

One of the significant things I took away was learning how to use and interpret unreal insight. This allowed me to easily find which scripts were causing issues and why they were causing problems and not spend time on anything that was not as heavy on the performance. 

Much of my time in this project was also spent translating C++ and C# code into blueprints, as all information on flow field pathfinding systems I found was often written in these languages, which gave me a better understanding of script-based code. While I never implemented it, I also started researching how to make my own custom blueprint nodes, as moving a lot of my heavy flow field logic to C++ code would significantly improve my performance. Learning something new that I can try out later is also fun.

Thank you for reading!

Erik Wahlström

Email: erikwa@telia.com

I am part of The Game Assembly’s internship program. As per the agreement between the Games Industry and The Game Assembly, neither student nor company may be in contact with one another regarding internships before April 19th. ​

Any internship offers can be made on April 26th, at the earliest.

  • LinkedIn
bottom of page