Adding multiple levels to your Game

A common first question once you become comfortable with creating your worlds and adding content is 'How do I add multiple levels to my game?'

While there are a wide range of ways that you can load multiple levels, trigger level loads, run missions and so on, the basic fundamentals of getting a sequential level load working in your game is fairly straightforward.

In fact, the Empty Project template that ships with GameCore includes the basic structure out of the box that we can use to build on, and the remainder of this tutorial will use this project as an example.

To get started, create a new project using the Empty Project template.  Obviously to load multiple worlds, we'll need a couple of worlds created, but I'll leave that part up to you, with the exception of the actual 'level complete' trigger elements, which I will explain in more detail in a moment.

If you run the Empty Project template, when you click 'play game' you will notice that the initial screen that shows up is the Level Selection dialog, shown below:

What this dialog does is scan the 'worlds' directory of your project and list all of the available worlds so that you can pick which one that you wish to play.  This is meant to provide a straightforward interface for you to use while testing your game, but probably won't suffice for most game types.

Open up the main.gsl script (in the 'media/scripts' folder of your project).  By default, the main.gsl script in the Empty Project template looks like the following:

// main game execution
void MainGame()
{
    GameManager@ game = GetGameManager();
    if (game.GetPlayerCount() == 0)
        Error( "Error: No player object defined. Make sure the 'Make Player' checkbox is checked for the player object.");

    Player@ player = game.GetPlayer( 0);
    game.SetPlayerInputRemapping( "Player", player.GetName());

    Viewport@ viewport = game.GetViewport( "Main");
    viewport.SetViewToPlayer( player);

    Object@ goal = game.GetWorld().GetObject( "Goal");

    while (true)
    {
        // check to see if we reached the level goal
        if (goal != NULL)
        {
            if (goal.GetControllerVariableBool( "Activated"))
                break;
        }

        // this delay is needed to allow the other game processes to run
        Delay( 0.01);
    }

    // we passed the level
    CloseGame();
    NewWorld();
    SetRelativeMouseMode( false);
    ShowForm( "LevelSelectDialog");
}

The part of this script that we are interested in is the section within the  'while(true)' loop:

    Object@ goal = game.GetWorld().GetObject( "Goal");

    while (true)
    {
        // check to see if we reached the level goal
        if (goal != NULL)
        {
            if (goal.GetControllerVariableBool( "Activated"))
                break;
        }

        // this delay is needed to allow the other game processes to run
        Delay( 0.01);
    }

In plain english what this script says is:

Object@ goal = game.GetWorld().GetObject( "Goal");

we have a Trigger in our world called 'Goal'

while (true)
{
}

repeat this section of script until we 'break' out of the loop

    if (goal != NULL)
    {
        if (goal.GetControllerVariableBool( "Activated"))
            break;
    }

If the 'Goal' object exists, check to see if it has been triggered - and if so, break out of the 'while' loop

// we passed the level
CloseGame();
NewWorld();
SetRelativeMouseMode( false);
ShowForm( "LevelSelectDialog");

Once the 'goal' trigger has been activated, this chunk of code is executed, which, by default, returns us to the level selection screen so we can pick the new level.

Adding the Level Complete Trigger

I've put together an extremely simple level, consisting of exactly 2 objects - a terrain and the 'push ball' object template (which is a very simple example player script), shown below:

In order to activate the level change, what we need to do is add a simple trigger to our world that will be used as the activation of the level change itself.  GameCore includes a number of different trigger types as object templates that you can use for, or for the more advanced users, you can add your own.

In the image below, I've added an 'Automatic Trigger' to the world and named it 'Goal'.  To do so click 'Add -> From Object Template -> Triggers -> Automatic Trigger'.  Place the object where you want your level change to be located and name it appropriately.

The name is important, because this is how we reference the object from script, as shown in this line:

Object@ goal = game.GetWorld().GetObject( "Goal");

You can name your level change objects whatever you want, as long as you modify the above line (the GetObject("Goal") part) to the name of the trigger object that you want to use as the level change activation.  Name objects is done on the Object Properties panel, as shown below:

That's it!  You now have a trigger in your world called 'Goal' that we can then use to activate our level change.

Loading the New Level

Now that we have an understanding of how the main.gsl script is setup, we can see that to load a new level after a Level complete trigger is activated is simply a matter of modifying the last 4 lines of script to automatically load the new level instead of going back to the menu.

So instead of this:

    Object@ goal = game.GetWorld().GetObject( "Goal");

    while (true)
    {
        // check to see if we reached the level goal
        if (goal != NULL)
        {
            if (goal.GetControllerVariableBool( "Activated"))
                break;
        }

        // this delay is needed to allow the other game processes to run
        Delay( 0.01);
    }

    // we passed the level
    CloseGame();
    NewWorld();
    SetRelativeMouseMode( false);
    ShowForm( "LevelSelectDialog");

What we can do is something like this:

    while (true)
    {
        // check to see if we reached the level goal
    }
    
    // here we load the new level, show a simple message instead for testing
    GetGameManager().ShowTextPlain("Level Change activated - Loading new Level!");

If you test your game, you should be able to activate the trigger and get a message to show on-screen, like so:

Loading the New World

The next step is to actually load the new level.  If we look at the menu.gsl script (located in the /media/gui/ directory of your project), we can see that there is a LoadWorld() function located there that contains the appropriate script for loading a new level.   We can use this script as a starting point by adding the appropriate lines to the end of our game script.

    while (true)
    {
        // check to see if we reached the level goal
    }
    
    // now that the level is done, load the new level
    NewWorld();

    // show the loading screen
    ShowForm( "LoadingScreen");
    // load the next world in our game
    StartLoadingWorld( "../worlds/level2.wld");
    while (!DoneLoadingWorld())
        Delay( 0.001f);

    // run the game script
    LoadGameScript( "main.gsl", "MainGame");

    HideForm( "LoadingScreen");

That's about it!  Basically once the trigger is activated, we show the loading screen, start loading our new world and then load the main.gsl game script again to start the process over.

Pretty simple, no?