Phaser Scene Management
Relevant source files
The following files were used as context for generating this wiki page:The souless project leverages Phaser 3's scene management system to structure the game into distinct states and modules. Each scene is a self-contained unit responsible for a specific part of the game, such as the main menu, core gameplay, user interface, or narrative sequences. This modular approach allows for a clean separation of concerns, making the codebase easier to manage and extend.
Scenes are managed through a central configuration and transition between each other by starting, stopping, or launching other scenes. Data is passed between scenes during these transitions to maintain game state. A key feature is the use of parallel scenes, where the GameScene and UIScene run concurrently to separate gameplay logic from UI rendering.
Scene Configuration
All game scenes are registered in the main Phaser game configuration object located in renderer/renderer.js. The scene property of the configuration is an array that lists all the scene classes. The order in this array determines the initial boot order, but Phaser manages them by their unique keys thereafter.
Sources: renderer/renderer.js:13-27
// renderer/renderer.js:13-27
const config = {
// ... other properties
scene: [
MainMenuScene,
IntroScene,
GameScene,
UITestScene,
EndingScene,
BossTestScene,
PauseMenuScene,
EffectTestScene,
UIScene,
],
// ... other properties
};
The following diagram illustrates how the Phaser Game instance is initialized with the scene configuration.
This diagram shows the Phaser Game object being created with a configuration that includes an array of all the game's scenes.
Sources: renderer/renderer.js:13-27
Scene Overview
The project is composed of several key scenes, each with a specific role.
| Scene Class | Key | Role |
|---|---|---|
MainMenuScene | MainMenuScene | The initial entry point. Manages new game creation, loading saved games, and exiting. |
IntroScene | IntroScene | Displays the narrative introduction to the player. Transitions to GameScene on completion. |
GameScene | GameScene | The core gameplay scene. Manages the player, map, enemies, and all primary game logic. |
UIScene | UIScene | Runs in parallel with GameScene to render all UI elements like health bars and skill cooldowns. |
EndingScene | EndingScene | Displays the game clear screen and final dialogue after the final boss is defeated. |
PauseMenuScene | PauseMenuScene | A menu that can be launched on top of GameScene to pause the game. |
TestScene | EffectTestScene | A scene for testing various visual effects. |
BossTestScene | BossTestScene | A dedicated scene for testing boss mechanics. |
Sources: renderer/renderer.js:15-23, src/scenes/GameScene.js:40, src/scenes/MainMenuScene.js:5, src/scenes/UIScene.js:11, src/scenes/IntroScene.js:4, src/scenes/EndingScene.js:8
Scene Lifecycle and Transitions
Scene transitions are fundamental to the game's flow. The this.scene.start() method is primarily used to stop the current scene and start a new one, effectively moving the player from one game state to another.
Game Start Flow
When the application launches, MainMenuScene is the first active scene. From there, the player can start a new game, which triggers a transition to IntroScene, or load a saved game, which transitions directly to GameScene.
The following sequence diagram shows the typical flow when starting a new game.
This diagram illustrates the scene transitions from the main menu to the main gameplay, including the parallel launch of the UI scene.
Sources: src/scenes/MainMenuScene.js:522-525, src/scenes/IntroScene.js:290-296, src/scenes/GameScene.js:231
Key Transition Points
- New Game:
MainMenuScenecallsthis.scene.start('IntroScene', { slotIndex: slotIndex })to begin the story.
Sources: src/scenes/MainMenuScene.js:522-525 - Load Game:
MainMenuScenecallsthis.scene.start('GameScene', { mapKey: ..., characterType: ... })to load the player directly into the game.
Sources: src/scenes/MainMenuScene.js:550-554 - Intro to Game: After the intro dialogue,
IntroScenetransitions to the first playable map by callingthis.scene.start('GameScene', { mapKey: 'other_cave', ... }).
Sources: src/scenes/IntroScene.js:290-296 - Player Death: In
GameScene, when the player's health reaches zero, theonPlayerDeathmethod is called, which restarts theGameScenewith specific respawn parameters. This is handled bythis.scene.start('GameScene', { ... isRespawn: true }).
Sources: src/scenes/GameScene.js:1418-1426, src/entities/characters/base/CharacterBase.js:480-486 - Final Boss Defeated: After defeating the
final_boss,GameScenetransitions to theEndingSceneviathis.scene.start('EndingScene').
Sources: src/scenes/GameScene.js:1612-1614
Data Passing
Data is passed between scenes using the optional second argument of this.scene.start(key, data). The receiving scene can access this data object in its init(data) method.
For example, when loading a game, MainMenuScene passes the map key and character type to GameScene:
// src/scenes/MainMenuScene.js:550-554
this.scene.start('GameScene', {
mapKey: slotSummary.mapKey || 'other_cave',
characterType: slotSummary.characterType || 'soul',
slotIndex: slotIndex, // 슬롯 인덱스 전달
});
GameScene then receives this data in its init method to configure the scene accordingly.
// src/scenes/GameScene.js:70-71
async init(data = {}) {
this.sceneData = data;
// ...
}
Sources: src/scenes/MainMenuScene.js:550-554, src/scenes/GameScene.js:70-71
Parallel Scenes: GameScene and UIScene
The project effectively separates gameplay logic from UI rendering by running GameScene and UIScene in parallel.
- Launch:
GameSceneis responsible for launchingUISceneusingthis.scene.launch('UIScene'). Unlikestart,launchruns the new scene concurrently with the current one.
Sources: src/scenes/GameScene.js:231 - Event-Driven Communication:
UIScenedoes not directly accessGameScene's state. Instead,GameSceneemits events when the player's state changes (e.g., stats updated, experience gained).UIScenelistens for these events and updates the UI elements accordingly.
This relationship is depicted in the diagram below.
This diagram shows how GameScene launches UIScene and communicates UI updates via an event-driven system.
Sources: src/scenes/GameScene.js:231, src/scenes/UIScene.js:68-87, src/scenes/GameScene.js:1483
Key Events for UI Communication
| Event Name | Emitter | Listener | Purpose |
|---|---|---|---|
ui-ready | UIScene | GameScene | Signals that the UI is created and ready. |
character-changed | GameScene | UIScene | Notifies the UI of a player character switch. |
exp-gained | GameScene | UIScene | Sent when the player gains experience points. |
player-stats-updated | GameScene | UIScene | Sent when player health, mana, or other stats change. |
skill-cooldowns-updated | GameScene | UIScene | Provides updated cooldown information for the skill bar. |
character-level-up | GameScene | UIScene | Notifies the UI that a specific character has leveled up. |
Sources: src/scenes/UIScene.js:68-87
Conclusion
The scene management in souless is well-structured, using Phaser's scene system to create a clear and maintainable game architecture. Key states like the main menu, introduction, gameplay, and ending are encapsulated in their own scenes. The use of scene.start() with data passing facilitates clean transitions, while scene.launch() enables a powerful parallel scene pattern for separating game logic from the user interface. This design promotes modularity and allows different parts of the game to be developed and tested independently.