Scene Flow & Level Loading
A lobby scene, a catalog of levels, and one controller that outlives every load. Adding a level to your game is authoring an asset and dropping it in a list — the lobby, the loading screen, the spawn placement and the return path all already know what to do with it.
The shape of a session
There is one lobby scene — Main by default — and any number of level scenes. SceneFlowController lives in the lobby, survives every load, and owns the transitions: play a level locally, host a session, join one, reload the current level, or come back to the lobby.
Loads are Single mode, not additive. The lobby is genuinely unloaded while you play, and coming back re-loads it. That is why persistence across a load is handled explicitly rather than by leaving the lobby lying around underneath.
| Field | Type | Default | What it does |
|---|---|---|---|
mainSceneName | string | "Main" | Scene the return path loads. Must match the lobby scene's file name and be registered in Build Settings. |
loadingScreen | LoadingScreenUI | — | The screen shown during a transition. Assigned by the installer; there is one in the lobby already. |
Levels are assets, listed in a catalog
A LevelDefinitionis one entry in the lobby's level list: a name, an optional thumbnail, the scene, and how many players fit. A LevelCatalog is the ordered list of them the lobby offers.
| Field | Type | Default | What it does |
|---|---|---|---|
displayName | string | — | Name shown in the lobby's level list. |
thumbnail | Sprite | — | Preview image shown left of the name. Optional — leave it empty for a name-only row. |
sceneAsset | SceneAsset | — | The level's scene. Must be registered in Build Settings — the Setup Window adds missing entries and never removes yours. |
maxPlayers | int | 4 | Player capacity — DERIVED from the scene's spawn points and auto-synced whenever the level scene is saved. Add spawn point objects to raise it. The host picks a session size up to this. |
The catalog loads by name from Resources — LevelCatalog— so nothing in the lobby needs a direct reference wired to it, and a level list is a list you edit rather than a scene you re-wire. The same asset also holds the list of folders the catalog scanner watches (kit's own SceneFlow/Levels plus Assets/Levels by default, editable in the Setup Window) — see Level Authoring for adding your own.
Adding a level
Build the scene
Any scene works. Give it aLevelSpawnPointsobject with a child transform per player position — those children are collected automatically, so you can just place empties.Author the definition
Create → Party Core Kit → Level Definition. Set the display name, assign the scene asset, add a thumbnail if you have one. LeavemaxPlayersalone; saving the scene sets it.Add it to the catalog
Append the definition to theLevelCatalogasset's list. Order in the list is order in the lobby.Check Build Settings
The scene must be registered. The Setup Window adds missing entries for you and never removes yours, so running Install is the safe way to do it.
Spawn points
LevelSpawnPointsholds the positions players appear at, used round-robin by player index or client id. Leave the array empty and its children are collected automatically, which means "add a spawn point" is "drag an empty into the object".
It is also the source of a level's maxPlayers, so spawn points are not decoration — they are the level's declared capacity. Placing players is handled for you in both shapes: PlaceLocalNetworkPlayer for an online session and PlaceLocalCoopPlayers for split-screen.
Surviving a scene load
Some objects have to outlive the lobby: the scene flow controller itself, the network manager, the save manager. Because loads are Single-mode and returning to the lobby re-loads Main, every persistent root authored there would be re-created on return — stacking a second copy on every trip.
PersistentCore is the guard. It keys instances by an id string, so each persistent root destroys its own later duplicates and nothing else.
| Field | Type | Default | What it does |
|---|---|---|---|
coreId | string | "core" | Identity of this persistent root, e.g. 'scene-flow-core'. Duplicates with the same id are destroyed on load. Two different roots need two different ids. |
Driving it from code
Everything the lobby buttons do is a public method, so a custom front-end drives the same paths:
using Curitor.PartyCoreKit.SceneFlow;
using UnityEngine;
public class QuickPlay : MonoBehaviour
{
[SerializeField] private LevelDefinition level;
private void StartOffline()
{
// Single-player or local co-op, depending on the session settings.
SceneFlowController.Instance.PlayLocal(level);
}
private void StartOnline()
{
// Returns false when the session could not be started.
bool hosting = SceneFlowController.Instance
.StartHostSession("Clem's game", "abc123", level, maxPlayers: 4);
}
private void GoHome()
{
SceneFlowController.Instance.ReturnToLobby();
// Anything the flow wanted to tell the player -- "host left",
// "connection lost" -- is waiting here. Static, and read-and-clear:
// the notice shows exactly once.
string notice = SceneFlowController.TakeSessionNotice();
if (!string.IsNullOrEmpty(notice)) Debug.Log(notice);
}
}The rest: JoinSession, LoadLevel, ReloadCurrentLevel (which is how a round starts its next run), SetRoundJoinLock, and IsInLobby.