From aa7db949579334447c2a0887fff7142e4e8d0241 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 22 Oct 2024 22:02:38 +0300 Subject: [PATCH] BREAKING CHANGE: Added IHierarchObject with Hierarchy Enter & Exit --- .../Abstract/Assignable/IHierarchyObject.cs | 62 +++++++++++++++++++ Engine.Core/Abstract/IGameManager.cs | 14 ++++- Engine.Core/Abstract/IGameObject.cs | 2 +- Engine.Core/Behaviour.cs | 10 +++ Engine.Core/GameManager.cs | 51 +++++++++++++-- Engine.Core/GameObject.cs | 40 +++++++----- 6 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 Engine.Core/Abstract/Assignable/IHierarchyObject.cs diff --git a/Engine.Core/Abstract/Assignable/IHierarchyObject.cs b/Engine.Core/Abstract/Assignable/IHierarchyObject.cs new file mode 100644 index 0000000..b49d503 --- /dev/null +++ b/Engine.Core/Abstract/Assignable/IHierarchyObject.cs @@ -0,0 +1,62 @@ +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Represents an that can enter and exit a hierarchy within the system. +/// This interface allows for tracking the object's presence in the hierarchy and provides events +/// for notifying when the see enters or exits the hierarchy. +/// +public interface IHierarchyObject : IEntity +{ + /// + /// Event triggered when the enters the hierarchy. + /// + event OnEnteredHierarchyDelegate? OnEnteredHierarchy; + + /// + /// Event triggered when the exits the hierarchy. + /// + event OnExitedHierarchyDelegate? OnExitedHierarchy; + + /// + /// Gets the associated with this , if any. + /// + IGameManager? GameManager { get; } + + /// + /// Indicates whether the is currently in the hierarchy. + /// + bool IsInHierarchy { get; } + + /// + /// Internal method to handle entering the hierarchy. + /// This should be called by the system to properly manage hierarchy states. + /// + /// The game manager that is managing this hierarchy. + /// + /// if the successfully entered the hierarchy; + /// if it failed to do so. + /// + internal bool EnterHierarchy(IGameManager gameManager); + + /// + /// Internal method to handle exiting the hierarchy. + /// This should be called by the system to properly manage hierarchy states. + /// + /// + /// if the successfully exited the hierarchy; + /// if it failed to do so. + /// + internal bool ExitHierarchy(); + + /// + /// Delegate type for the event triggered when the enters the hierarchy. + /// + /// The that entered the hierarchy. + delegate void OnEnteredHierarchyDelegate(IHierarchyObject sender); + + /// + /// Delegate type for the event triggered when the exits the hierarchy. + /// + /// The that exited the hierarchy. + delegate void OnExitedHierarchyDelegate(IHierarchyObject sender); +} diff --git a/Engine.Core/Abstract/IGameManager.cs b/Engine.Core/Abstract/IGameManager.cs index 9835dfb..e854ba8 100644 --- a/Engine.Core/Abstract/IGameManager.cs +++ b/Engine.Core/Abstract/IGameManager.cs @@ -5,7 +5,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a game world responsible for managing s. /// -public interface IGameManager : IEntity, IEnumerable +public interface IGameManager : IEntity, IEnumerable, IEnumerable { /// /// Event triggered when a is registered to the . @@ -17,6 +17,16 @@ public interface IGameManager : IEntity, IEnumerable /// event OnGameObjectUnRegisteredDelegate? OnGameObjectUnRegistered; + /// + /// Event triggered when a is registered to the . + /// + event OnHierarchyObjectRegisteredDelegate? OnHierarchyObjectRegistered; + + /// + /// Event triggered when a is unregistered from the . + /// + event OnHierarchyObjectUnRegisteredDelegate? OnHierarchyObjectUnRegistered; + /// /// Gets a read-only list of s managed by the . /// @@ -56,4 +66,6 @@ public interface IGameManager : IEntity, IEnumerable delegate void OnGameObjectRegisteredDelegate(IGameManager sender, IGameObject gameObjectRegistered); delegate void OnGameObjectUnRegisteredDelegate(IGameManager sender, IGameObject gameObjectUnregistered); + delegate void OnHierarchyObjectRegisteredDelegate(IGameManager sender, IHierarchyObject hierarchyObjectRegistered); + delegate void OnHierarchyObjectUnRegisteredDelegate(IGameManager sender, IHierarchyObject hierarchyObjectUnregistered); } diff --git a/Engine.Core/Abstract/IGameObject.cs b/Engine.Core/Abstract/IGameObject.cs index 971f3a8..8e9256f 100644 --- a/Engine.Core/Abstract/IGameObject.cs +++ b/Engine.Core/Abstract/IGameObject.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract; /// /// Represents a game object with various properties and functionalities. /// -public interface IGameObject : IEntity, IAssignableGameManager, IAssignableTransform, IAssignableBehaviourController, INameable, IInitialize +public interface IGameObject : IEntity, IHierarchyObject, IAssignableTransform, IAssignableBehaviourController, INameable, IInitialize { /// /// Event triggered when the method is called. diff --git a/Engine.Core/Behaviour.cs b/Engine.Core/Behaviour.cs index 07523c8..600feb2 100644 --- a/Engine.Core/Behaviour.cs +++ b/Engine.Core/Behaviour.cs @@ -27,6 +27,8 @@ public abstract class Behaviour : BehaviourBase BehaviourController.OnPreUpdate += PreUpdate; BehaviourController.OnPreDraw += PreDraw; BehaviourController.OnUpdate += Update; + BehaviourController.GameObject.OnEnteredHierarchy += EnteredHierarchy; + BehaviourController.GameObject.OnExitedHierarchy += ExitedHierarchy; OnInitialize(); } @@ -36,6 +38,8 @@ public abstract class Behaviour : BehaviourBase BehaviourController.OnPreUpdate -= PreUpdate; BehaviourController.OnPreDraw -= PreDraw; BehaviourController.OnUpdate -= Update; + BehaviourController.GameObject.OnEnteredHierarchy -= EnteredHierarchy; + BehaviourController.GameObject.OnExitedHierarchy -= ExitedHierarchy; OnFinalize(); } @@ -84,4 +88,10 @@ public abstract class Behaviour : BehaviourBase OnPreDraw(); } + + protected virtual void OnEnteredHierarchy() { } + private void EnteredHierarchy(IHierarchyObject sender) => OnEnteredHierarchy(); + + protected virtual void OnExitedHierarchy() { } + private void ExitedHierarchy(IHierarchyObject sender) => OnExitedHierarchy(); } diff --git a/Engine.Core/GameManager.cs b/Engine.Core/GameManager.cs index 7e9b1cc..c8a1d2d 100644 --- a/Engine.Core/GameManager.cs +++ b/Engine.Core/GameManager.cs @@ -13,9 +13,11 @@ public class GameManager : BaseEntity, IGameManager { public event IGameManager.OnGameObjectRegisteredDelegate? OnGameObjectRegistered = null; public event IGameManager.OnGameObjectUnRegisteredDelegate? OnGameObjectUnRegistered = null; - + public event IGameManager.OnHierarchyObjectRegisteredDelegate? OnHierarchyObjectRegistered = null; + public event IGameManager.OnHierarchyObjectUnRegisteredDelegate? OnHierarchyObjectUnRegistered = null; private readonly List _gameObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); + private readonly List _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private GameObjectFactory _gameObjectFactory = null!; @@ -101,21 +103,55 @@ public class GameManager : BaseEntity, IGameManager ///////////////////////////////////////////////////////////////// + private void Register(IHierarchyObject hierarchyObject) + { + if (hierarchyObject is IGameObject gameObject) + Register(gameObject); + else + { + _hierarchyObjects.Add(hierarchyObject); + OnHierarchyObjectRegistered?.Invoke(this, hierarchyObject); + } + } + private void Register(IGameObject gameObject) { - gameObject.Assign(this); - gameObject.OnFinalized += OnGameObjectFinalize; + gameObject.OnExitedHierarchy += OnGameObjectExitedHierarchy; _gameObjects.Add(gameObject); + _hierarchyObjects.Add(gameObject); + + if (!gameObject.EnterHierarchy(this)) + throw new Exception($"{nameof(gameObject)} can't enter the hierarchy"); + + OnHierarchyObjectRegistered?.Invoke(this, gameObject); OnGameObjectRegistered?.Invoke(this, gameObject); } + private void Unregister(IHierarchyObject hierarchyObject) + { + if (hierarchyObject is IGameObject gameObject) + Unregister(gameObject); + else + { + _hierarchyObjects.Remove(hierarchyObject); + OnHierarchyObjectUnRegistered?.Invoke(this, hierarchyObject); + } + } + private void Unregister(IGameObject gameObject) { gameObject.OnFinalized -= OnGameObjectFinalize; + gameObject.OnExitedHierarchy -= OnGameObjectExitedHierarchy; _gameObjects.Remove(gameObject); + _hierarchyObjects.Remove(gameObject); + + if (!gameObject.ExitHierarchy()) + throw new Exception($"{nameof(gameObject)} can't exit the hierarchy"); + + OnHierarchyObjectUnRegistered?.Invoke(this, gameObject); OnGameObjectUnRegistered?.Invoke(this, gameObject); } @@ -125,8 +161,15 @@ public class GameManager : BaseEntity, IGameManager Unregister(gameObject); } + private void OnGameObjectExitedHierarchy(IHierarchyObject sender) + { + if (sender is IGameObject gameObject) + Unregister(gameObject); + } + ///////////////////////////////////////////////////////////////// - public IEnumerator GetEnumerator() => _gameObjects.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _gameObjects.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _gameObjects.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => _hierarchyObjects.GetEnumerator(); } diff --git a/Engine.Core/GameObject.cs b/Engine.Core/GameObject.cs index 072e04e..c2a7317 100644 --- a/Engine.Core/GameObject.cs +++ b/Engine.Core/GameObject.cs @@ -6,25 +6,27 @@ namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")] public class GameObject : BaseEntity, IGameObject { + public event IHierarchyObject.OnEnteredHierarchyDelegate? OnEnteredHierarchy = null; + public event IHierarchyObject.OnExitedHierarchyDelegate? OnExitedHierarchy = null; + public event IAssignableTransform.OnTransformAssignedDelegate? OnTransformAssigned = null; - public event IAssignableGameManager.OnGameManagerAssignedDelegate? OnGameManagerAssigned = null; public event IAssignableBehaviourController.OnBehaviourControllerAssignedDelegate? OnBehaviourControllerAssigned = null; public event INameable.OnNameChangedDelegate? OnNameChanged = null; public event IGameObject.OnUpdatedDelegate? OnUpdated = null; - private ITransform _transform = null!; private IBehaviourController _behaviourController = null!; private IStateEnable _stateEnable = null!; - private IGameManager _gameManager = null!; + private IGameManager? _gameManager = null; private string _name = nameof(GameObject); public ITransform Transform => _transform; public IBehaviourController BehaviourController => _behaviourController; - public IGameManager GameManager => _gameManager; + public IGameManager? GameManager => _gameManager; + public bool IsInHierarchy => GameManager is not null; public string Name { @@ -85,16 +87,6 @@ public class GameObject : BaseEntity, IGameObject return true; } - public bool Assign(IGameManager gameManager) - { - if (IsInitialized) - return false; - - _gameManager = gameManager; - OnGameManagerAssigned?.Invoke(this); - return true; - } - protected override void UnassignInternal() { base.UnassignInternal(); @@ -114,4 +106,24 @@ public class GameObject : BaseEntity, IGameObject } private void OnBehaviourRemoved(IBehaviourController _, IBehaviour behaviour) { if (IsInitialized) behaviour.Initialize(); } private void OnBehaviourAdded(IBehaviourController _, IBehaviour behaviour) { if (IsInitialized) behaviour.Finalize(); } + + public bool EnterHierarchy(IGameManager gameManager) + { + if (IsInHierarchy) + return false; + + _gameManager = gameManager; + OnEnteredHierarchy?.Invoke(this); + return true; + } + + public bool ExitHierarchy() + { + if (!IsInHierarchy) + return false; + + _gameManager = null; + OnExitedHierarchy?.Invoke(this); + return true; + } }