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;
+ }
}