Elegant Level Changing – ShiVa Engine

Elegant Level Changing

application.setCurrentUserScene ( hScene ) is among the first commands you get to know while learning ShiVa. Called from a User AI, it loads a game scene for the gamer to play in. It is also the most important command when trying to change a level. Most games allow the player to walk through doors or into a certain area to change the level. The goal of this tutorial will be to recreate such a scene and show how to make an elegant level change including features like music and screen fading.

Sensor Setup

In order to capture the collision event between the main player character and the level exit, we have to assign sensors to all the objects involved, the player model as well as the exit blocks.

The Level Change Sensor has an ID of 99 to differentiate it from from other sensor collision events. Furthermore, the sensor boxes have name tags that indicate which level is next.
The collision event is captured on the player AI model:

As soon as the player sensor comes in contact with a sensor box using ID 99, it checks for its tag and sends a notification to the LevelChanger AIModel in the User AIModel Stack.

Fading Away

To make the level changing beautiful, we decided to employ a soft fading black screen and a loading image screen. You can create such an effect in numerous ways. We decided to use the least amount of code possible and instead do the heavy lifting in the HUD editor.
First, we need to create a new HUD (“BlackScreen”) with a screen-filling black label component. It will receive an action (“interpolateOpacity”) which we set as “Initial Action”. This way, the screen will fade to black as soon as the HUD is initialzed, no extra code necessary.

To fade back to the game, we created another HUD (“GameScreen”) that is almost identical to BlackScreen with the exception that the HUD action interpolates the opacity from 255 to 0 and not the other way around.
Later, a third HUD “LoadingScreen” is necessary, which displays the actual loading image or text, which is not animated.

Level Changer

The biggest chunk of logic for the level change is handled within the LevelChanger AIModel. It is a User AIModel that exists outside the scene and continues to run regardless of the events in the scene that is currently loaded. It essentially consists of two Events and two States with a number of helper functions and variables.
Once your player model has collided with the ID 99 box, the onChangeLevel() event is called, which sets the level changing process in motion:

Starting and Stopping

Once the LevelChanger AIModel has received the signal from the player model, a function called this.ChangeLevelFunction() is executed. This function initializes the BlackScreen HUD fade as well as the music fade – not how those things are done elegantly with just one call and not in a loop.

Furthermore, we call the AIModel itself to execute Event onLoadLevel after a delay of 1.5 seconds, which essentially switches states from this.Idle() to this.LevelChangerState().
It is a good idea to disable user input in the time of loading and during the fades. To do that, we need to send and Event notification to the Main User AI that handles all user inputs. You can either send an event that manipulates a variable inside the AI (as done in the example) or manipulate the AI variable directly using user.setAIVariable ( hUser, sAIModel, sVariable, vValue ).
Inside your Input AIModel, capturing keyboard events would have to be encapsulated like this:

--------------------------------------------------------------------------------
function LevelChanger.onKeyboardKeyUp ( kKeyCode )
--------------------------------------------------------------------------------
	if this.isUserInputEnabled() == true then -- only accept input if enabled
		-- input your keystrokes here
	end
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------

A change in two States

The LevelChanger AIModel has two states, Idle and LevelChangerState. Idle runs during the actual game, while LevelChangerState handles all the level loading things.
When you enter the level change, it is always a good idea to save the current game state before you load a new level, in case something goes wrong. This.AutoSave() is a dummy function that allows you to do just that. make sure you save everything you want to save in either a UserAI Table, some XML or an environment.
Tip: Save the new level string this.nextLevel(), so if you load up the save game, the new level will be loaded instead of the old one. At the end, the LoadingScreen HUD is initialized, which is in our case the LOADING sign. Modify that if you want to display images, hints, different text, and so forth.

onLoop handles the actual loading. Since most ShiVa scenes are rather small, we implemented a “grace second” – a timer that counts up into the variable this.loadingtimer until 1 second is over. This means that your loading screen will be visible for at least one full second.

When the state is left, we want to make sure to initialize the Hud that fades from black to the actual game and remove all unnecessary HUDs.

Once you finally get back into the gam (this.Idle() state), start the music again and, most importantly, re-enable the user input!

Conclusion

And there you have it, a simple yet effective and elegant way to change your scenes. To enhance it further, shorten loading times or even do a fancy loading bar, we suggest you look into the PreLoading APIs. You will very likely have models that occur throughout the game, like guns, characters or items, if they are big, you should consider keeping them in memory all the time using the ForceLoad APIs.

Music Copyright

The music files included in this example come from Kevin MacLeod/Inkompetech and are licensed under Creative Commons: By Attribution 3.0.


  • slackBanner