persistent-entity
Persistent Entity
Section titled “Persistent Entity”Version: v2.3.0+
Persistent Entity is a special type of entity that automatically migrates to the new scene during scene transitions. It is suitable for game objects that need to maintain state across scenes, such as players, game managers, audio managers, etc.
Basic Concepts
Section titled “Basic Concepts”In the ECS framework, entities have two lifecycle policies:
| Policy | Description | Default |
|---|---|---|
SceneLocal | Scene-local entity, destroyed when scene changes | ✓ |
Persistent | Persistent entity, automatically migrates during scene transitions |
Quick Start
Section titled “Quick Start”Creating a Persistent Entity
Section titled “Creating a Persistent Entity”import { Scene } from '@esengine/ecs-framework';
class GameScene extends Scene { protected initialize(): void { // Create a persistent player entity const player = this.createEntity('Player').setPersistent(); player.addComponent(new Position(100, 200)); player.addComponent(new PlayerData('Hero', 500));
// Create a normal enemy entity (destroyed when scene changes) const enemy = this.createEntity('Enemy'); enemy.addComponent(new Position(300, 200)); enemy.addComponent(new EnemyAI()); }}Behavior During Scene Transitions
Section titled “Behavior During Scene Transitions”import { Core, Scene } from '@esengine/ecs-framework';
// Initial sceneclass Level1Scene extends Scene { protected initialize(): void { // Player - persistent, will migrate to the next scene const player = this.createEntity('Player').setPersistent(); player.addComponent(new Position(0, 0)); player.addComponent(new Health(100));
// Enemy - scene-local, destroyed when scene changes const enemy = this.createEntity('Enemy'); enemy.addComponent(new Position(100, 100)); }}
// Target sceneclass Level2Scene extends Scene { protected initialize(): void { // New enemy const enemy = this.createEntity('Boss'); enemy.addComponent(new Position(200, 200)); }
public onStart(): void { // Player has automatically migrated to this scene const player = this.findEntity('Player'); console.log(player !== null); // true
// Position and health data are fully preserved const position = player?.getComponent(Position); const health = player?.getComponent(Health); console.log(position?.x, position?.y); // 0, 0 console.log(health?.value); // 100 }}
// Switch scenesCore.create({ debug: true });Core.setScene(new Level1Scene());
// Later switch to Level2Core.loadScene(new Level2Scene());// Player entity migrates automatically, Enemy entity is destroyedAPI Reference
Section titled “API Reference”Entity Methods
Section titled “Entity Methods”setPersistent()
Section titled “setPersistent()”Marks the entity as persistent, preventing destruction during scene transitions.
public setPersistent(): thisReturns: Returns the entity itself for method chaining
Example:
const player = scene.createEntity('Player') .setPersistent();
player.addComponent(new Position(100, 200));setSceneLocal()
Section titled “setSceneLocal()”Restores the entity to scene-local policy (default).
public setSceneLocal(): thisReturns: Returns the entity itself for method chaining
Example:
// Dynamically cancel persistenceplayer.setSceneLocal();isPersistent
Section titled “isPersistent”Checks if the entity is persistent.
public get isPersistent(): booleanExample:
if (entity.isPersistent) { console.log('This is a persistent entity');}lifecyclePolicy
Section titled “lifecyclePolicy”Gets the entity’s lifecycle policy.
public get lifecyclePolicy(): EEntityLifecyclePolicyExample:
import { EEntityLifecyclePolicy } from '@esengine/ecs-framework';
if (entity.lifecyclePolicy === EEntityLifecyclePolicy.Persistent) { console.log('Persistent entity');}Scene Methods
Section titled “Scene Methods”findPersistentEntities()
Section titled “findPersistentEntities()”Finds all persistent entities in the scene.
public findPersistentEntities(): Entity[]Returns: Array of persistent entities
Example:
const persistentEntities = scene.findPersistentEntities();console.log(`Scene has ${persistentEntities.length} persistent entities`);extractPersistentEntities()
Section titled “extractPersistentEntities()”Extracts and removes all persistent entities from the scene (typically called internally by the framework).
public extractPersistentEntities(): Entity[]Returns: Array of extracted persistent entities
receiveMigratedEntities()
Section titled “receiveMigratedEntities()”Receives migrated entities (typically called internally by the framework).
public receiveMigratedEntities(entities: Entity[]): voidParameters:
entities- Array of entities to receive
Use Cases
Section titled “Use Cases”1. Player Entity Across Levels
Section titled “1. Player Entity Across Levels”class PlayerSetupScene extends Scene { protected initialize(): void { // Player maintains state across all levels const player = this.createEntity('Player').setPersistent(); player.addComponent(new Transform(0, 0)); player.addComponent(new Health(100)); player.addComponent(new Inventory()); player.addComponent(new PlayerStats()); }}
class Level1 extends Scene { /* ... */ }class Level2 extends Scene { /* ... */ }class Level3 extends Scene { /* ... */ }
// Player entity automatically migrates between all levelsCore.setScene(new PlayerSetupScene());// ... game progressesCore.loadScene(new Level1());// ... level completeCore.loadScene(new Level2());// Player data (health, inventory, stats) fully preserved2. Global Managers
Section titled “2. Global Managers”class BootstrapScene extends Scene { protected initialize(): void { // Audio manager - persists across scenes const audioManager = this.createEntity('AudioManager').setPersistent(); audioManager.addComponent(new AudioController());
// Achievement manager - persists across scenes const achievementManager = this.createEntity('AchievementManager').setPersistent(); achievementManager.addComponent(new AchievementTracker());
// Game settings - persists across scenes const settings = this.createEntity('GameSettings').setPersistent(); settings.addComponent(new SettingsData()); }}3. Dynamically Toggling Persistence
Section titled “3. Dynamically Toggling Persistence”class GameScene extends Scene { protected initialize(): void { // Initially created as a normal entity const companion = this.createEntity('Companion'); companion.addComponent(new Transform(0, 0)); companion.addComponent(new CompanionAI());
// Listen for recruitment event this.eventSystem.on('companion:recruited', () => { // After recruitment, become persistent companion.setPersistent(); console.log('Companion joined the party, will follow player across scenes'); });
// Listen for dismissal event this.eventSystem.on('companion:dismissed', () => { // After dismissal, restore to scene-local companion.setSceneLocal(); console.log('Companion left the party, will no longer persist across scenes'); }); }}Best Practices
Section titled “Best Practices”1. Clearly Identify Persistent Entities
Section titled “1. Clearly Identify Persistent Entities”// Recommended: Mark immediately when creatingconst player = this.createEntity('Player').setPersistent();
// Not recommended: Marking after creation (easy to forget)const player = this.createEntity('Player');// ... lots of code ...player.setPersistent(); // Easy to forget2. Use Persistence Appropriately
Section titled “2. Use Persistence Appropriately”// ✓ Entities suitable for persistenceconst player = this.createEntity('Player').setPersistent(); // Playerconst gameManager = this.createEntity('GameManager').setPersistent(); // Global managerconst audioManager = this.createEntity('AudioManager').setPersistent(); // Audio system
// ✗ Entities that should NOT be persistentconst bullet = this.createEntity('Bullet'); // Temporary objectsconst enemy = this.createEntity('Enemy'); // Level-specific enemiesconst particle = this.createEntity('Particle'); // Effect particles3. Check Migrated Entities
Section titled “3. Check Migrated Entities”class NewScene extends Scene { public onStart(): void { // Check if expected persistent entities exist const player = this.findEntity('Player'); if (!player) { console.error('Player entity did not migrate correctly!'); // Handle error case } }}4. Avoid Circular References
Section titled “4. Avoid Circular References”// ✗ Avoid: Persistent entity referencing scene-local entityclass BadScene extends Scene { protected initialize(): void { const player = this.createEntity('Player').setPersistent(); const enemy = this.createEntity('Enemy');
// Dangerous: player is persistent but enemy is not // After scene change, enemy is destroyed, reference becomes invalid player.addComponent(new TargetComponent(enemy)); }}
// ✓ Recommended: Use ID references or event systemclass GoodScene extends Scene { protected initialize(): void { const player = this.createEntity('Player').setPersistent(); const enemy = this.createEntity('Enemy');
// Store ID instead of direct reference player.addComponent(new TargetComponent(enemy.id));
// Or use event system for communication }}Important Notes
Section titled “Important Notes”-
Destroyed entities will not migrate: If an entity is destroyed before scene transition, it will not migrate even if marked as persistent.
-
Component data is fully preserved: All components and their state are preserved during migration.
-
Scene reference is updated: After migration, the entity’s
sceneproperty will point to the new scene. -
Query system is updated: Migrated entities are automatically registered in the new scene’s query system.
-
Delayed transitions also work: Persistent entities migrate when using
Core.loadScene()for delayed transitions as well.
Related Documentation
Section titled “Related Documentation”- Scene - Learn the basics of scenes
- SceneManager - Learn about scene transitions