Nautilus is an underwater expedition, where you are the one controlling a submarine and exploring various deep sea environments. The main focus is laid upon the atmosphere and visual storytelling rather than traditional mechanics. Light, sound, and movement guide the experience, creating a sense of isolation and unease. There are no enemies to fight, only the unknown waiting for you to dive deeper.

My roleDuring this project I was assigned as lead programmer. That meant I had a bigger responsibility to make sure we are heading in the right direction and will have time for what we are planning as programmers.For example the game was supposed to be a multiplayer game. But the networking took so much time and we almost didn't have anything playable for weeks. Because of this, I gave the suggestion to make the game singleplayer. Otherwise we would almost not have any game by the end of the project, if we worked in the same capacity. It turned out to be a very good decision. Because even with multiplayer being cut from the game we had to cut a lot of other features too, so that we could get the best possible result within the time frame.Like my other group projects, I mostly took on features that were important and needed for the product rather than what was the most fun to work with. I fixed a lot of bugs in mine and others' code. Put functionality together and fixed the issues that it brought with it. I feel like my ability to work with others and their code has become one of my core abilities in these projects, and has had a big role in what I work on in them.I also became responsible for making prefabs of our scripts with the connections and options that were needed to make it as easy as possible for designers to use.

Overall game loop

I naturally became responsible over making sure the game loop worked properly. And if not, I searched for the problem and tried to solve it. This contained being able to start the game, spawn where you are supposed to. Be able to die and make sure everything that should reset resets and so on. Be able to board the submarine. Be able to move from first to second level and so forth. This responsibility took a big chunk of my time since all the different functionality in the game needed to work together. This meant I was reworking and editing a lot of scripts in the project that I sometimes had worked on myself but mostly others code. As well as playtesting the game in specific situations "what happens if I park the submarine, go outside and die here".A specific thing that was a big problem with the gameplay loop for me was to remake the airlock functionality to work with save files. Because I needed the submarine to be able to be loaded in as open or closed. Where that was not possible in the original code, and the different steps in the sequence depended on each other.With the level streaming, the biggest problem was to figure out how many areas are loaded in at the same time since our levels became fairly big. In the final product two levels are always loaded in. Before a new level loads the oldest are unloaded. First we thought that we could maybe split up the levels in sections, load them in small pieces and only load in the next level when it is necessary to see it. There was some problems with this though. In our levels you often can see the whole level at the same time, and it's just small sections that's not visible. If we then also need to open a door for a new level we would need to have two levels loaded at the same time. We don't want players to notice clear shifts in the performance of the game, therefore we made sure that it's possible to have two levels loaded at all times.I also made a saving system for saving the important data to JSON when reaching certain checkpoints. This was made for if you fall down and die, but also if you want to quit the game and continue later on. The most difficult part of this task was to figure out how to make sure that some triggers and events that should only happen once don’t happen when you reload the save. Therefore I needed to keep track of and save the different triggers and events that have happened.


One time events

I was also responsible for scripting and setting up all the one time events. For example the cave falling apart in level one, opening of the big doors, the jumpscares and the ending. I made these with connected triggers that had a lot of options. Playing sound, animation and vfx, enable or disable selected colliders, adding camera shake and teleporting the submarine. All with the option of delaying the effect, for example time the camera shake to animations and sound more easily.


Submarine Steering

The submarine steering was a challenging task. Both with decision making and execution. First was the question to make the steering stationary as in Subnautica, where you control the ship with for example WASD, same as player movement. And then the other option was to drag the wheels and levers with the mouse. We chose to drag it with the mouse. This was a lot harder than I first thought, mostly because of the steering wheel. When you look at it from the front, you want to be able to make a circular, horizontal or vertical motion with the mouse to turn the wheel. But from the side you only want to be able to make a vertical motion.First I took a look at how others have managed to make something like this. I found that a common solution for a lever dragged with your mouse, was to project your mouse position in world space on a plane that is aligned with the levers rotation axis, and rotates the lever with a LookAt towards the projected position. Lerping the old to the new rotation to make it a smooth lever interaction. Like you can see on this picture, I later changed the pane to a cylinder mesh since it didn't feel good rotating the wheel from the sides with a plane.But the problem with this way of rotating the wheel, is that you can't have it continuously rotating. Because the wheel will always want to rotate to a specific rotation. So to solve this problem, I had to save the difference in rotation between the old and new as a "delta rotation". Therefore it can update directly when you move it. But adding rotations together was more difficult than I thought. I used Euler angles, and because of that I ran into gimbal lock issues, that resulted in the rotation of the object to flip in an unexpected way if you are not familiar with the problem. This has to do with the way Unity converts Euler angles to quaternions, since the engine uses quaternions internally. Therefore now I know why, when dealing with incremental rotations you should use quaternions rather than directly changing the Euler angles.With the rotation of the steering wheel working without snapping, it still didn't feel that smooth. It felt really rigid and stale. I had already been sitting with this for about a week and I was afraid this would bottleneck our overall production. So me and the lead designer took a decision to use a plugin instead. The plugin used hinges instead of setting a rotation, and took the rotation difference from start rotation that returned a value from 0 to 1. This made it a lot easier for us to simulate that the wheel and levers had “weight” and felt better to interact with.I'm not that satisfied with the result. Ideally I would have wanted to spend more time with these interactions, because it sometimes "lags out" and becomes very difficult to use when the submarine moves fast. But I'm thankful I took the decision of leaving my solution and ego behind, for the sake of getting the best possible result for the project.



Prototype steering


Current steering

Submarine movement

I made the prototype of the submarine movement. Separating force in forward & backwards, up & down and rotation to turn. The submarine also stabilizes itself when it's not tipped over as you can see in the video. This is for what would originally happen when the submarine collides with walls or something hits the ship. The ship would then have gotten a push in the direction of the hit depending on its current velocity. You can see this being stress tested in the video by me turning up the submarine's speed and how much it gets bumped.


What I learnedBecause this was the first time I was the lead programmer, the things I learned from this project were far different from the rest of my projects. Practically speaking I learned a lot of how important it is to have a clear plan, with emergency solutions if the planning doesn't pan out the way you thought. And to decide when to cut features and take a new approach is even more difficult than I already thought it was. But to sacrifice perfection to get something playable is often the way to go in these situations.More importantly I learned that when facing issues of tough time restrictions, it's a more durale solution to change the plan rather than overworking yourself. Which often leads to less efficiency in the end. And also affects the whole team mentally, which in the long run will affect the result of the game.


Noa Johansson