37 Find the Gnome

A peek into the beautiful low poly level design, a sketch of the game’s intro, and more.

I have been working hard the past four weeks, so I skipped a bi weekly update. But that s because I have enough stuff to work on. A good sign I think!

So enjoy this weeks content.

Video

A both technical and story peek this time: I am demonstrating the use of additive loading of my scenes, and you can see parts of the intro scene (the sketch version).

Low poly level design

Here is a screenshot of work-in-progress on a city themed level:

Find the Gnome city themed level WIP

I am working with a few different artists currently. This design is from Syoma. He really nails the diorama vibe combined with the low poly techniques I want to use.

The game is currently planned to launch with 4 themes and 3 levels per theme, with the city levels being the largest (and last).

The gnomes in the city are more crazy than the earlier gnomes, not only lost but also possessed by the worldly goods they found here. Of course explained with a beautiful intro scene.

Intro scenes

Speaking of intro scenes. In the video of this blog you could see parts of the main introduction we are working on. Its a cartoon combined with some parallax effects.

For now its a sketch only, so we can see if it works and then move on to draw the final images and color them.

There will be 5 cartoon scenes in the story flow, and probably 2 to unlock if you find special objectives.

These cartoons are from a official cartoonist, so the game is already worth playing for getting to see the cartoons! See his other work on meinder.nl.

Additive scene loading

It took me a few attempts to get it working, but I have additive scene loading in my game now.

A bit of an insight into how I solved this. For the technical people that read my blogs. And I know that a lot of you, my readers, are technical minded people. So here you have my take on this!

So what was the problem, the promise, the solution and lessons learned?

The problem

I have created a few games already. And every time after a certain amount of work, I get the need in my game to automate going from scene to scene. Most of the times I create a data object somewhere to record what level is tied to what scene (file), and then use a manager of some kind to load this level on demand. This manager also knows a bit about menu’s and other places so it can direct you there. But it needs to fully unload the current scene to get you there.

Most of the time I also have another problem thats starting to appear: a level load sequence. (And level unloading). Just using the awake, start and the other object lifetimes in Unity is very limiting. Especially if you want to do some save state loading, or dynamic object discovery, you need more steps in the loading process. Creating your own signals and then managing what signal to hook on is quickly getting a mess, especially if you want it to work while in the editor as well as in the official build. And don’t add singletons to it (like ScriptableObjects) because this will make your game explode into a fountain of very hard to track bugs.

And if this isn’t enough, I tend to get into re-usability issues very quickly. I want some objects, like the UI, on all scenes of a specific type. For instance, levels need the level UI. Or I want a Debug UI to load and be always available. Or I want a loading screen to be visible while unloading the old scene and loading the new scene. And like I said, scenes fully unload at the end. So I don’t want these specific UI elements to unload. And yes I know this can be manually solved in Unity. But then you have to account for certain objects being around after the lifetime of a scene and not keeping ties to the (then unloaded) scene and cause problems… so in the end you need to manage this (proper tying and untying) anyway, so why not make that everything can be loaded/unloaded on demand?

The promise

Additive scene loading is the promise. And its often advertised as a best practice.

Additive scene loading comes with a few benefits. And you don’t need to use all of them, but its very easy to use these if you have these additive scenes working:

  • Seamless level transitions (without loading screens)
  • Much more easy to manage asynchronous level loading
  • No irritating UI that gets in the way while working in the editor
  • Less massive scenes and thus the chance for merge conflicts while working on scenes
  • Better decoupling because for this to work you need to implement a proper event subscribe/unsubscribe system

The solution

A scene can very easily be additive loaded by just stating to Unity load this scene additive .

But for this to work seamlessly you have to implement some sort of state machine to know whats happening. Previously you knew where you where by just looking at the scene’s name. But now you need an overarching machine that keeps track of where you are and where you want to go to.

I added a few additional layers on top of it to also address the other issues I faced.

  • A level sequence object that I can ask: ‘what are the available scenes for this game’. I have levels, intro shots, and 1 map. And fill this sequence object with directions on whats available in the editor with custom tools.
  • A level transition object that I can ask: ‘go to the next story scene’. Or ‘oneshot this level and then return to the map’. (It uses the level sequence combined with savestate to determine what unlocked and where the player is at story wise)
  • A state machine that consists of a few parts. (all custom code, not the Unity state machines)
    • The state machine itself. This keeps track of the current state it is in, initiates transitions, and keeps actions atomic. Uses IEnumerator to make it asynchronous (well, that is Unity-style async, not .Net async lol).
    • A state class model. 1 class for a start-game state, 1 class for a level state, 1 class for an intro shot state, 1 class for a map state, 1 class for a game-exit state. Each state has 2 main functions ‘`RunOnEntryLogic(transition info)’ and ‘RunOnExitLogic(transition info)’, both IEnumerator to support chaining actions inside the logic and to wait for stuff to happen. Each model has its own series of events on it so you can fine-tune the needed amount of events per state. These events are called in the logic functions with yields and such to keep the ticks flowing in Unity.
    • A static class with instances of each one of the a fore mentioned classes. So scripts can reference these from anywhere to hook themselves up to the events of their liking.
    • A transition object. Very simplistic, just to get basic info like ‘Start level 1.1’ or ‘Start map’ to the states.
    • A few smartly placed calls to ‘ensure loading screen’ and ‘hide loading screen’ and ‘pause game’ and ‘unpause game’ in the states. To make it possible to prepare stuff without the user seeing artifacts of this preparation.
  • A scene specific for the state machine. There is only 1 script on this scene, and it initiates state transitions. This scene is always around.
  • A startup sequence script. It knows what scenes to additive load. And triggers the state machine.
  • An editor version of the a fore mentioned startup sequence, that primes the scene as if it was started normally (and thus loads all needed additive scenes on play and sets the state machine to the correct state).

On the additive UI scenes: I have a bunch of additive scenes that are always on. Most of them look for certain events and/or state (transitions) to enable/disable parts of itself. (So its a reactive system, much easier to maintain) And most of the objects on these additive scenes have scripts that use OnEnable and OnDisable to hook and unhook events.

For more info, find me on GameFeeling’s Discord on the #game-dev-talk channel. There I can easily share some code and more insights. (And, if there is enough interest, create a full article on it with code and such)

Lessons learned

It works like a charm!

  • The state machine combined with the startup sequence scripts is sooo helpful. I now can be sure events are fired in the right order with the right systems loaded and prepared to the right state. Even with no difference between the editor and the official build.
  • It looks cool. In the editor. With all these scenes loading and unloading on demand. And it all runs without synchronous code that takes ages to complete and prevent certain parts of the code to continue.
  • I have a few ScriptableObjects for singleton behaviors and better decoupling, and normally these are hard to manage the state off. Because these don’t fit in with the normal game object lifetimes. But now these can be hooked up perfectly to state transitions to give them better boundaries, but at the same time not mess up the decoupling.
  • The class based static scene setup is very easy to use and maintain. And to understand. And thus to work with, reason about, and improve upon. Thats worth the downsides of this system for me. (Downsides being that its not using Unity’s preferred patterns and components, and another downside is the service locator antipattern of all these static singletons)
  • The IEnumerator is a bit of a pain to work with. Especially if you pause your game by setting Time.timeScale = 0, you then don’t want to use yield functions that wait for the next realtime tick to happen. You want to use WaitForSecondsRealtime instead.
  • And another thing on the IEnumerator: it needs to be started as a Coroutine on a script that is kept around, even when unloading stuff. So you don’t want to call it as a Coroutine from the scene that is being unloaded, but instead call a script on a scene that will be around that on its turn calls the Coroutine. Thats why I have a dedicated state machine scene now that first to be alive on start, and then manages the state (and scene) transitions from there.
    I have spend hours and hours locating a bug because of this. I wanted to transition away from the starting scene but the code just stopped executing at a certain point in time. Until I found out that the Coroutine is bound to lifetime of the MonoBehaviour, and I did fire it from within the starting scene.

Published by Erik_de_Roos

Erik de Roos is a Freelance software developer.

Leave a comment