The other project I’ve been working on is a more ambitious game in comparison to my endless runner, it’s a first-person adventure puzzle game where I dive into experimental gameplay features and drag the player along with me! One of the core features of this game is a world loading mechanic that uses an elevator as the main hub. This is the first feature that I’ve implemented to test how it works since it’s quite central to the overall experience.
What’s the big deal with this elevator?
A simple level loader may not seem that interesting or important at first, but this elevator is a bit different than the typical ones you’d see in a game:
The elevator could essentially have an unlimited number of floors, but I’ve capped it at 999,999 and you can input whatever floor you want. This gives the player much more control in how they want to approach the game. Do they want to just start at floor number 1 and work their way up or find clues leading to new floors? Or maybe they’d work in a group or community to discover floors together? What if they find a late game floor by accident and how would that affect the story? I want to answer all those questions in the design and make this a game that welcomes out of the box possibilities or solutions to the point of changing the outcome of the game.
Objects as floors
This is where the game gets a bit strange! Without spoiling too much, the floors don’t just go to different worlds, but to objects where you can tweak those objects and affect the world that they’re used in. This is one of the central ways to solve puzzles in the game and progress through the story. The kind of objects a floor goes to could be almost anything, characters, items, maybe even messing with a user interface or the game options? The point of this feature is to experiment, fix or even break the game to find a solution, like a physical hacking feature.
Finally, many floors will be randomly generated using a seed while other floors stay constant in multiple playthroughs. This allows replayability in different ways:
- Randomness gives unique experiences for every game.
- As the player learns of the constant floor numbers, they’d be able to play the game out of order and potentially create a different outcome in the story.
- Or they could just randomly pick a floor or go in order, floor by floor, to try to find early secrets. This would be the most boring option but it’s there if that’s how the player wishes to play.
This is also the only way I would be able to populate so many floors with content, because I would ideally have something on every floor. It could be nothing that important but something should be there or the existence of that floor number would feel pointless.
I’m also thinking of possibilities for randomly seeded floors that generate from calculations in a script with each being a piece of a larger puzzle in the game. These optional floors could lead to community puzzles that usually take a whole group of people to work in effort to solve. I haven’t solidified a design solution to this yet and am more concentrating on the main static floors in the game at the moment.
How it works
I have the game set up with a main persistent level in Unreal and then all the other floors are children of that persistent level. I then created an array out of a custom struct that holds the floor number and the floor level name. The level blueprint in the elevator level then searches the array for the floor number that the player chose and then sends the floor name to the blueprint node Load Stream Level (by Name) which is used to load levels.
That’s the basic core of the function but there’s much more to make the transition sophisticated, like performing the unloading and loading of the levels while the elevator entrance is out of view or looping the transition animation until both the level is finished loading and the transition period lasts for a minimum amount of time.
Creating a thrilling experience with the visuals was important for me to test out early, because switching floors will be so common that I wanted to make sure it can be entertaining. A key visual component is not having a door on the elevator to give you a clear sense of scale and movement that’s quite fast and hectic as it flies through the floors. In addition, light flickers and camera shakes were added to further improve to the experience.
The trick here is the elevator actually only moves at the very start and at the end of the loading process. I start to animate the wall texture as soon as the open doorway is out of view and then increase the speed over time until it suddenly stops, which is when the elevator and player teleports to the opposite side and then moves back to the doorway entrance. That part still needs some improvement as the teleportation can cause some flickering.
Some audio was added to increase the feeling of the elevator going at a fast speed. I pitched shifted a pump loop as the elevator moves faster and then added a ding sound upon arrival, finally an idle sound is used for when the elevator is still. Adding audio early was important to discover some issues with my script set up and how it doesn’t allow for more complex sequencing, I’ll get to this in more details at the end of this post.
Improving player experience
It was also important to make the elevator panel convenient to use, so I created some simple things that enhance the ease of use that aren’t that noticeable because of their familiarity of function in the real world, such as:
- Auto clearing the elevator numbers once the player inputs new numbers after transitioning to a floor.
- A must needed clear button for the numbers.
- Up and down arrows that add or subtract by one floor.
I utilized the common designs of keypads and elevator buttons to make this panel function instantly recognizable for most players and it should not need any instruction. Further improvement in the future by adding symbols instead of text will make this even better.
Important player controls
Another feature I designed that relates more to the player controller is that you can right click at any point in time to halt the camera rotation and freely move the mouse around the screen. This feature was clearly important to me in a puzzle game like this and comes in handy when using the panel. Optionally, the player can ignore this feature and just rotate the camera around, I then make the cursor become visible any time a ray trace detects something clickable to subtly communicate what you can click on.
Future improvement goals
I am planning to transition to a portal system, just like the game Portal, as the elevator doorway to allow more freedom in the level design and hopefully solve some visual issues. This will also open up some non-Euclidean geometry possibilities for the elevator entrance, since it’ll no longer take up that space in the level.
As I was implementing test audio, it also became clear to me that this could have been made with Unreal’s level sequencer for easier control to time things like the sound. Currently I have built this with blueprint and used delays and multiple timeline nodes to control timing. This worked as a proof of concept, but I know it will be an issue later on as I add more complexity to the system.
A floor number above the door will be important to add later on to let the player keep track of what floor they’re on as they fiddle with the keypad. It’ll also be interesting to animate the numbers as the elevator transitions to the new floor.
Finally, I’ll have to add a button to call the elevator in some levels where the player may find themselves in a new floor by other means than the elevator. I also have to solve the question of what to put there when the elevator isn’t there? Currently I’m thinking a mirror-like portal to the same world would be a good solution and animating the transition from that to the elevator will look quite cool if I can pull it off.
But for now, the next thing I’ll be focusing on is the level design of the first big area to get an early test of some of the core gameplay and puzzles.