From b65a3bbd6dad771f752bf425ea76b116e7a37a1a Mon Sep 17 00:00:00 2001 From: Katharina Ziolkowski Date: Tue, 3 Feb 2026 15:36:59 +0100 Subject: [PATCH] Managed the freeing of entityplacers. Also cleaned up EntityManager --- .../GameEntity/Entities/LoadedScenesEntity.cs | 13 ++++ .../Entities/LoadedScenesEntity.cs.uid | 1 + .../GameEntity/Entities/PositionalEntity.cs | 2 +- .../CSharp/GameEntity/Entities/TrashEntity.cs | 4 +- .../EntityPlacer/TrashEntityPlacer.cs | 16 +++- .../GameEntity/Management/EntityManager.cs | 75 ++++++++++++------- .../Management/EntityNodeCreator.cs | 15 +++- .../Management/EntitySceneContainer.cs | 5 +- 8 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs create mode 100644 scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs.uid diff --git a/scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs b/scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs new file mode 100644 index 0000000..88a94a9 --- /dev/null +++ b/scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Babushka.scripts.CSharp.GameEntity.Entities; + +public class LoadedScenesEntity : Entity +{ + private HashSet _loadedScenes = new(); + public override string EntityType => "LoadedScenesEntity"; + + public void AddScene(string sceneName) => _loadedScenes.Add(sceneName); + + public bool WasSceneLoaded(string sceneName) => _loadedScenes.Contains(sceneName); +} \ No newline at end of file diff --git a/scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs.uid b/scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs.uid new file mode 100644 index 0000000..c45f76e --- /dev/null +++ b/scripts/CSharp/GameEntity/Entities/LoadedScenesEntity.cs.uid @@ -0,0 +1 @@ +uid://rabb1y637cm5 diff --git a/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs b/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs index 0832625..f8b6e79 100644 --- a/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs +++ b/scripts/CSharp/GameEntity/Entities/PositionalEntity.cs @@ -28,6 +28,6 @@ public abstract class PositionalEntity : Entity } // Deals with Instantiation of the node - public abstract void AddEntity(Node2D parent); + public abstract void InstantiateEntityNode(Node2D parent); } \ No newline at end of file diff --git a/scripts/CSharp/GameEntity/Entities/TrashEntity.cs b/scripts/CSharp/GameEntity/Entities/TrashEntity.cs index 6ed44b4..718db9c 100644 --- a/scripts/CSharp/GameEntity/Entities/TrashEntity.cs +++ b/scripts/CSharp/GameEntity/Entities/TrashEntity.cs @@ -13,10 +13,10 @@ public class TrashEntity : PositionalEntity { } - public override void AddEntity(Node2D parent) + public override void InstantiateEntityNode(Node2D parent) { if(_creator == null) _creator = EntityManager.Instance.NodeCreator; - var entityNode = _creator.CreateNode2D(EntityType); + var entityNode = _creator.InstantiateNode(EntityType); parent.AddChild(entityNode); entityNode.GlobalPosition = position; } diff --git a/scripts/CSharp/GameEntity/EntityPlacer/TrashEntityPlacer.cs b/scripts/CSharp/GameEntity/EntityPlacer/TrashEntityPlacer.cs index c8b14f9..15b5b13 100644 --- a/scripts/CSharp/GameEntity/EntityPlacer/TrashEntityPlacer.cs +++ b/scripts/CSharp/GameEntity/EntityPlacer/TrashEntityPlacer.cs @@ -10,9 +10,17 @@ public partial class TrashEntityPlacer : Node2D public override void _Ready() { - TrashEntity entity = new TrashEntity(); - entity.sceneName = EntityManager.Instance.CurrentEntitySceneContainer!.sceneName; - entity.position = GlobalPosition; - EntityManager.Instance.AddEntity(entity); + string sceneName = EntityManager.Instance.CurrentEntitySceneContainer!.sceneName; + var loadedScenesEntity = EntityManager.Instance.GetUniqueEntity(); + + if (!loadedScenesEntity.WasSceneLoaded(sceneName)) + { + TrashEntity entity = new TrashEntity(); + entity.sceneName = sceneName; + entity.position = GlobalPosition; + EntityManager.Instance.AddEntity(entity); + } + + QueueFree(); } } \ No newline at end of file diff --git a/scripts/CSharp/GameEntity/Management/EntityManager.cs b/scripts/CSharp/GameEntity/Management/EntityManager.cs index 2d4964e..fdf8834 100644 --- a/scripts/CSharp/GameEntity/Management/EntityManager.cs +++ b/scripts/CSharp/GameEntity/Management/EntityManager.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Godot; using Entity = Babushka.scripts.CSharp.GameEntity.Entities.Entity; @@ -7,21 +6,23 @@ using PositionalEntity = Babushka.scripts.CSharp.GameEntity.Entities.PositionalE namespace Babushka.scripts.CSharp.GameEntity.Management; +/// +/// Manages the lifecycle and interactions of all entities within the game, including their creation, retrieval, +/// and organization. The EntityManager serves as a centralized hub for managing both standard and positional entities. +/// public partial class EntityManager : Node { + public static EntityManager Instance; + [Export] private EntityNodeCreator _nodeCreator = null!; - public EntityNodeCreator NodeCreator => _nodeCreator; - private EntitySceneContainer? _currentEntitySceneContainer; - - public static EntityManager Instance; - private readonly List _allEntities = new(); - + public IEnumerable AllEntities => _allEntities; - public IEnumerable AllPositionalEntities => _allEntities.OfType(); + public EntitySceneContainer? CurrentEntitySceneContainer => _currentEntitySceneContainer; + public EntityNodeCreator NodeCreator => _nodeCreator; public override void _EnterTree() { @@ -30,6 +31,7 @@ public partial class EntityManager : Node public override void _Input(InputEvent @event) { + // for debugging purposes if (@event.IsActionPressed("DebugEntities")) { GD.Print("Entities:"); @@ -39,37 +41,49 @@ public partial class EntityManager : Node } } } + + #region ENTITY MANAGEMENT - public void UnloadScene() - { - if (_currentEntitySceneContainer == null) return; - _currentEntitySceneContainer = null; - } - - public void LoadScene(EntitySceneContainer sceneContainer) - { - _currentEntitySceneContainer = sceneContainer; - foreach (var entity in AllPositionalEntities) - { - _currentEntitySceneContainer.AddIfNeeded(entity); - } - } - + /// + /// Adds an entity to the list of managed entities. If the entity is a positional entity + /// and its scene matches the current scene container, it is also instantiated in the scene. + /// + /// The entity to be added to the manager. public void AddEntity(Entity entity) { - if(!_allEntities.Contains(entity)) + if (!_allEntities.Contains(entity)) _allEntities.Add(entity); if(entity is PositionalEntity positionalEntity && positionalEntity.sceneName == _currentEntitySceneContainer?.sceneName) - CreateEntityNode(positionalEntity); + InstantiatePositionalEntityNode(positionalEntity); } - public void CreateEntityNode(PositionalEntity entity) + private void InstantiatePositionalEntityNode(PositionalEntity entity) { if(_currentEntitySceneContainer == null) return; - entity.AddEntity(_currentEntitySceneContainer); + entity.InstantiateEntityNode(_currentEntitySceneContainer); + } + + /// + /// Retrieves the first entity of the specified type from the list of managed entities. + /// If no such entity exists, creates a new instance of the specified type, adds it to the manager, and returns it. + /// + /// The type of entity to retrieve or create. Must inherit from the Entity class and have a parameterless constructor. + /// The first entity of the specified type or a newly created entity of that type if none were found. + public T GetUniqueEntity() where T : Entity, new() + { + var result = AllEntities.OfType().FirstOrDefault(); + if (result == null) + { + var newEntity = new T(); + AddEntity(newEntity); + result = newEntity; + } + return result; } - public EntitySceneContainer? CurrentEntitySceneContainer => _currentEntitySceneContainer; + #endregion + + #region SCENE CONTAINER ACCESS public void SetSceneContainer(EntitySceneContainer sceneContainer) { @@ -80,4 +94,7 @@ public partial class EntityManager : Node { _currentEntitySceneContainer = null; } + + #endregion + } \ No newline at end of file diff --git a/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs b/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs index d86590d..a43a090 100644 --- a/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs +++ b/scripts/CSharp/GameEntity/Management/EntityNodeCreator.cs @@ -1,4 +1,5 @@ -using Godot; +using System; +using Godot; using Godot.Collections; namespace Babushka.scripts.CSharp.GameEntity.Management; @@ -7,8 +8,18 @@ public partial class EntityNodeCreator : Node { [Export] private Dictionary _entityPrefabs; - public Node2D CreateNode2D(string type) + public Node2D InstantiateNode(string type) { + if (string.IsNullOrEmpty(type)) + { + throw new NullReferenceException("The type provided for Node instantiation cannot be null or empty."); + } + + if (!_entityPrefabs.ContainsKey(type)) + { + throw new Exception($"The type provided for Node instantiation ({type}) is not specified in the EntityNodeCreator dictionary."); + } + return _entityPrefabs[type].Instantiate(); } } \ No newline at end of file diff --git a/scripts/CSharp/GameEntity/Management/EntitySceneContainer.cs b/scripts/CSharp/GameEntity/Management/EntitySceneContainer.cs index 22a0e09..2979cf4 100644 --- a/scripts/CSharp/GameEntity/Management/EntitySceneContainer.cs +++ b/scripts/CSharp/GameEntity/Management/EntitySceneContainer.cs @@ -1,4 +1,5 @@ using System.Linq; +using Babushka.scripts.CSharp.GameEntity.Entities; using Godot; using PositionalEntity = Babushka.scripts.CSharp.GameEntity.Entities.PositionalEntity; @@ -16,6 +17,8 @@ public partial class EntitySceneContainer : Node2D public override void _ExitTree() { EntityManager.Instance.UnsetSceneContainer(); + var loadedScenesEntity = EntityManager.Instance.GetUniqueEntity(); + loadedScenesEntity.AddScene(sceneName); } public override void _Ready() @@ -33,7 +36,7 @@ public partial class EntitySceneContainer : Node2D public void AddEntity(PositionalEntity entity) { - entity.AddEntity(this); + entity.InstantiateEntityNode(this); } } \ No newline at end of file