Menu and a second level

The menu

The project's first scene, Main.scene, becomes the menu. The menu's UI is Menu.slxml, a title and a Play button.

  1. Create the file Assets/UI/Menu.slxml with this text, the way you created the HUD:
Assets/UI/Menu.slxml
<?xml version="1.0" encoding="UTF-8"?>
<ui version="1">
	<panel id="menu" style="position: absolute; left: 0; top: 0; width: 100%; height: 100%; flex-direction: column; align-items: center; justify-content: center">
		<panel id="title" style="margin-bottom: 32px">Coin Collector</panel>
		<!-- MainMenu finds this button by its id and loads the first level when it is clicked -->
		<button id="play" style="width: 200px" text="Play"/>
	</panel>
</ui>
  1. Create a component named MainMenu and replace its two files:
Source/MainMenu.h
#pragma once

#include "Shalltear.h"

// the menu's Play button. It sits below the UIPanelRenderer that draws the
// menu, on the same object, so the button exists when OnEnable looks for it
class MainMenu : public Behavior {
public:
	// None: the menu has no per-frame code, only OnEnable and OnDisable
	MainMenu() : Behavior(BehaviorTick::None) {}

	SLT_REFLECT_COMPONENT(MainMenu, Behavior)
	SLT_REFLECT_FIELD(firstLevel)
	SLT_END_REFLECT()

	// the scene Play loads
	Handle<SceneAsset> firstLevel;
protected:
	void OnEnable() override;
	void OnDisable() override;
};
Source/MainMenu.cpp
#include "MainMenu.h"

#include "Shalltear/Core/UI/Context.h"
#include "Shalltear/Core/UI/UIPanelRenderer.h"

SLT_REGISTER_TYPE(MainMenu)

// runs when the game starts, not while you edit the scene: a component's hooks
// run only while the game plays. It wires the Play button, found by the id it
// has in Menu.slxml, the same way LevelController wires the pause menu
void MainMenu::OnEnable() {
	UIPanelRenderer* menu = GetOwner()->GetComponent<UIPanelRenderer>().Get();
	if (!menu || !menu->GetContext()) {
		SLT_LOG_WARN("CoinCollector", "MainMenu needs a UIPanelRenderer above it on the same object");
		return;
	}
	Handle<MainMenu> self(this);
	menu->GetContext()->Events(menu->FindElement("play")).onClick = [self] {
		MainMenu* mainMenu = self.Get();
		if (SceneAsset* level = mainMenu ? mainMenu->firstLevel.Get() : nullptr) {
			SceneSystem::ReplaceScenes(level->assetId);
		}
	};
}

void MainMenu::OnDisable() {
	UIPanelRenderer* menu = GetOwner()->GetComponent<UIPanelRenderer>().Get();
	if (menu && menu->GetContext()) {
		menu->GetContext()->Events(menu->FindElement("play")).onClick = nullptr;
	}
}
  1. Save both files. Save the level too, then double-click Main.scene in Assets/Scenes to open it.
  2. Create an empty object named Menu. Add a UIPanelRenderer with Menu.slxml as its document and Game.slpanel as its panelSettings.
  3. Add MainMenu below it, and drag Level1.scene onto its firstLevel field.
  4. Save the scene.

Press Ctrl+P, then Play, and the first level starts. When it ends, you are back at the menu.

A second level

  1. Double-click Level1.scene to open it, and select File ▸ Save Scene As.... Change the path to project://Assets/Scenes/Level2.scene and select OK. You are now editing the copy.
  2. Select a coin and press Ctrl+D twice, so there are seven, and move them:
CoinPosition
1-7, 0.75, 7
20, 0.75, 8
37, 0.75, 7
4-8, 0.75, 0
58, 0.75, 0
6-7, 0.75, -7
77, 0.75, -7
  1. Create a Level Definition named Level2.level, with timeLimit 25 and coinsToWin 7, and select Save. Leave its nextLevel empty: winning the last level returns to the menu.
  2. Select the Level object and drag Level2.level onto its level field. Save the scene.
  3. Select Level1.level, drag Level2.scene onto its nextLevel field and select Save.

Open Main.scene and press Ctrl+P. Play starts the first level, collecting its coins starts the second, and finishing the second returns to the menu.

Next, build the game.