Map and Portal System
Relevant source files
The following files were used as context for generating this wiki page:
The Map and Portal System is the foundational framework for constructing and navigating the game world in Souless. It defines all game areas (maps), including their visual appearance, physical boundaries, enemy populations, and the portals that connect them. This system is central to player progression, as it manages the conditions required to unlock new maps and orchestrates the seamless transition of the player between different scenes.
The system is composed of three main parts: data configuration for maps and portals, a runtime model for map creation, and a management layer for handling portal logic and player transitions.
System Architecture
The following diagram illustrates the high-level architecture of the Map and Portal System, showing how data configurations are processed by runtime managers to create the interactive game world.
This diagram shows that mapData.js and portalData.js provide the static definitions. MapModel uses this data to build the map in GameScene, while PortalManager and PortalConditionManager handle the logic of portal connections and unlocking.
Sources: src/config/mapData.js, src/config/portalData.js, src/models/map/MapModel.js, src/controllers/PortalManager.js, src/systems/PortalConditionManager.js, src/scenes/GameScene.js
Map Configuration
All maps in the game are defined as objects within the MAPS constant in mapData.js. Each map object contains properties that define its appearance, physics, entities, and portals.
Sources: src/config/mapData.js
Map Properties
The table below describes the key properties of a map configuration object.
| Property | Type | Description |
|---|---|---|
key | string | A unique identifier for the map. |
name | string | The display name of the map. |
camera | object | Contains camera settings, such as offsetY. |
mapScale | number | A multiplier to scale the map's background layers. |
layers | array | An array of image layer objects, each with a key and asset path. |
underSolidRectangle | object | Defines a solid colored rectangle at the bottom of the map for visual effect. |
spawn | object | Defines the player's default spawn position (x, y, offsetY). |
gravity | number | The vertical gravity applied to physics objects in the map. |
enemies | object | Configuration for enemy spawning, including types, initialCount, maxCount, etc. |
boss | object | Configuration for boss encounters, including enabled, spawnCondition, and spawnPosition. |
portals | array | An array of portal objects for this map, generated by generateMapPortals. |
Sources: src/config/mapData.js:3-39
Example Map Definition
// src/config/mapData.js
export const MAPS = {
cave: {
key: 'cave',
name: 'Parallax Cave',
camera: {
offsetY: 150,
},
mapScale: 1.5,
layers: [
{ key: 'cave_layer1', path: '/assets/map/parallax_cave/1.png' },
// ... more layers
],
spawn: {
x: 'left',
y: 'bottom',
offsetY: 200,
},
gravity: 800,
enemies: {
types: ['Slime', 'Bat'],
initialCount: 20,
maxCount: 35,
},
portals: generateMapPortals('cave'),
},
// ... more maps
};
Sources: src/config/mapData.js:3-43
Map Rendering (MapModel)
The MapModel class is responsible for taking a map configuration object and constructing the corresponding map within a Phaser scene. It handles the creation of background layers, world boundaries, a fixed collision ground, and portal instances.
Sources: src/models/map/MapModel.js
Class Diagram
This diagram shows the structure of the MapModel class and its key methods.
Sources: src/models/map/MapModel.js:4-245
Map Creation Flow
autoScaleLayers(): The model first calculates the appropriate scale for the map layers based on the screen height or a predefinedmapScale. It also determines the total map width, accounting for therepeatCountproperty.setupWorldBounds(): Sets the physics world boundaries and camera bounds to match the calculated map dimensions.createFixedCollisionGround(): A static, invisible rectangle is created at the bottom of the map to serve as the main ground for all entities.createPortals(): Iterates through theportalsarray in the map config and createsPortalobject instances within the scene.- Return: The
create()method returns an object containing the calculated spawn position and references to the created portals.
Sources: src/models/map/MapModel.js:43-61, src/models/map/MapModel.js:70-93, src/models/map/MapModel.js:127-154, src/models/map/MapModel.js:159-173
Portal System
The portal system manages the connections between maps and the logic for traversing them. It is defined by static connection data, a runtime manager, and an unlock condition manager.
Portal Connections (portalData.js & PortalManager.js)
Portal connections are defined in the PORTAL_CONNECTIONS object in src/config/portalData.js. Each entry represents a one-way portal, containing its source map, position, and the ID of its target portal.
The PortalManager is a static class that provides utility methods to query this data, such as finding all portals on a given map or retrieving a portal's destination.
Sources: src/config/portalData.js, src/controllers/PortalManager.js
Map Progression Flow
The following diagram shows the intended progression path through the game's maps as defined by the portal connections.
Sources: src/config/portalData.js:1-190
Portal Unlocking (PortalConditionManager.js)
The PortalConditionManager is a singleton that manages the unlock state of all portals. It checks if the player has met the specific conditions required to activate a portal. When a condition is met, the manager unlocks the portal and notifies listeners.
Sources: src/systems/PortalConditionManager.js
Unlock Conditions
Portals are unlocked based on various player achievements. The conditions are defined in the PORTAL_CONDITIONS object.
| Condition Type | Description | Example |
|---|---|---|
kill_count | Requires killing a specific number of each enemy type on the source map. | other_cave_to_scary_cave requires 10 kills of each enemy type in other_cave. |
boss_count | Requires defeating a certain total number of bosses. | temple_1_to_temple_2 requires defeating at least 2 bosses. |
total_level | Requires the player's total account level to reach a certain value. | temple_4_to_dark requires total level 60. |
character_levels | Requires each character to reach a specific level. | final_map_to_snow requires each character to be level 50 or higher. |
level_and_boss | A composite condition requiring both a character level and a specific boss defeat. | dark_to_final_map requires each character to be level 40 and the 'semi_boss' to be defeated. |
Sources: src/systems/PortalConditionManager.js:4-122
Condition Check Flow
This flowchart shows the logic inside PortalConditionManager for checking and unlocking a portal.
Scene Transition (GameScene.js)
When a player physically enters an unlocked portal, the onPortalEnter method in GameScene.js is triggered. This method handles the entire transition process to the new map.
Sources: src/scenes/GameScene.js:1062-1078
Portal Transition Sequence
The following sequence diagram details the steps taken when a player transitions between maps.
Summary
The Map and Portal System is a well-defined, data-driven system that effectively separates configuration from runtime logic. Map definitions in mapData.js provide a clear and extensible way to add new content. The MapModel class reliably translates this data into playable scenes. The portal logic, split between PortalManager for connections and PortalConditionManager for progression, creates a robust framework for guiding the player through the game world. Finally, the GameScene handles the critical process of transitioning the player, ensuring game state is saved before loading the new area.