diff --git a/Engine.Core/Abstract/IActive.cs b/Engine.Core/Abstract/IActive.cs
new file mode 100644
index 0000000..34c7dd3
--- /dev/null
+++ b/Engine.Core/Abstract/IActive.cs
@@ -0,0 +1,19 @@
+namespace Syntriax.Engine.Core.Abstract;
+
+///
+/// Represents an entity which can be active or not.
+///
+public interface IActive
+{
+ ///
+ /// Event triggered when the state of the changes.
+ ///
+ event ActiveChangedEventHandler? OnActiveChanged;
+
+ ///
+ /// The value indicating whether the is enabled.
+ ///
+ bool IsActive { get; }
+
+ delegate void ActiveChangedEventHandler(IActive sender, bool previousState);
+}
diff --git a/Engine.Core/Abstract/IBehaviour.cs b/Engine.Core/Abstract/IBehaviour.cs
index 9fc2d30..6858d0a 100644
--- a/Engine.Core/Abstract/IBehaviour.cs
+++ b/Engine.Core/Abstract/IBehaviour.cs
@@ -3,7 +3,7 @@ namespace Syntriax.Engine.Core.Abstract;
///
/// Represents a behaviour that any object in the game might use to interact with itself or other objects.
///
-public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable
+public interface IBehaviour : IEntity, IActive, IHasBehaviourController, IHasStateEnable
{
///
/// Event triggered when the priority of the changes.
@@ -15,10 +15,5 @@ public interface IBehaviour : IEntity, IHasBehaviourController, IHasStateEnable
///
int Priority { get; set; }
- ///
- /// The value indicating whether the is active.
- ///
- bool IsActive { get; }
-
delegate void PriorityChangedEventHandler(IBehaviour sender, int previousPriority);
}
diff --git a/Engine.Core/Abstract/IHierarchyObject.cs b/Engine.Core/Abstract/IHierarchyObject.cs
index aa5d7c3..e3909b5 100644
--- a/Engine.Core/Abstract/IHierarchyObject.cs
+++ b/Engine.Core/Abstract/IHierarchyObject.cs
@@ -7,7 +7,7 @@ namespace Syntriax.Engine.Core.Abstract;
/// 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, INameable, IHasBehaviourController, IEnumerable
+public interface IHierarchyObject : IEntity, IActive, INameable, IHasBehaviourController, IEnumerable
{
///
/// Event triggered when the enters the hierarchy.
diff --git a/Engine.Core/Abstract/IStateEnable.cs b/Engine.Core/Abstract/IStateEnable.cs
index 8debf8c..132b9bd 100644
--- a/Engine.Core/Abstract/IStateEnable.cs
+++ b/Engine.Core/Abstract/IStateEnable.cs
@@ -8,12 +8,12 @@ public interface IStateEnable : IHasEntity
///
/// Event triggered when the state of the changes.
///
- event NameChangedEventHandler? OnEnabledChanged;
+ event EnabledChangedEventHandler? OnEnabledChanged;
///
/// The value indicating whether the is enabled.
///
bool Enabled { get; set; }
- delegate void NameChangedEventHandler(IStateEnable sender, bool previousState);
+ delegate void EnabledChangedEventHandler(IStateEnable sender, bool previousState);
}
diff --git a/Engine.Core/ActiveBehaviourCollector.cs b/Engine.Core/ActiveBehaviourCollector.cs
index 70e48d8..f7472aa 100644
--- a/Engine.Core/ActiveBehaviourCollector.cs
+++ b/Engine.Core/ActiveBehaviourCollector.cs
@@ -16,7 +16,7 @@ public class ActiveBehaviourCollector : IBehaviourCollector where T : clas
private readonly List monitoringBehaviours = new(32);
protected readonly List activeBehaviours = new(32);
- protected readonly Dictionary monitoringStateToBehaviour = new(32);
+ protected readonly Dictionary monitoringActiveToBehaviour = new(32);
public IReadOnlyList Behaviours => activeBehaviours;
public IGameManager GameManager { get; private set; } = null!;
@@ -51,23 +51,22 @@ public class ActiveBehaviourCollector : IBehaviourCollector where T : clas
return;
monitoringBehaviours.Add(tBehaviour);
- monitoringStateToBehaviour.Add(tBehaviour.StateEnable, tBehaviour);
- tBehaviour.StateEnable.OnEnabledChanged += OnBehaviourStateChanged;
- OnBehaviourStateChanged(tBehaviour.StateEnable, !tBehaviour.StateEnable.Enabled);
+ monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour);
+ tBehaviour.OnActiveChanged += OnBehaviourStateChanged;
+ OnBehaviourStateChanged(tBehaviour, !tBehaviour.IsActive);
}
- private void OnBehaviourStateChanged(IStateEnable sender, bool previousState)
+ private void OnBehaviourStateChanged(IActive sender, bool previousState)
{
- T behaviour = monitoringStateToBehaviour[sender];
- if (sender.Enabled)
+ T behaviour = monitoringActiveToBehaviour[sender];
+ if (sender.IsActive)
{
activeBehaviours.Add(behaviour);
OnBehaviourAdd(behaviour);
OnCollected?.Invoke(this, behaviour);
}
- else if (activeBehaviours.Contains(behaviour))
+ else if (activeBehaviours.Remove(behaviour))
{
- activeBehaviours.Remove(behaviour);
OnBehaviourRemove(behaviour);
OnRemoved?.Invoke(this, behaviour);
}
@@ -79,10 +78,15 @@ public class ActiveBehaviourCollector : IBehaviourCollector where T : clas
if (behaviour is not T tBehaviour)
return;
- if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringStateToBehaviour.Remove(tBehaviour.StateEnable))
+ if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour))
return;
- tBehaviour.StateEnable.OnEnabledChanged -= OnBehaviourStateChanged;
+ tBehaviour.OnActiveChanged -= OnBehaviourStateChanged;
+ if (activeBehaviours.Remove(tBehaviour))
+ {
+ OnBehaviourRemove(tBehaviour);
+ OnRemoved?.Invoke(this, tBehaviour);
+ }
}
public bool Assign(IGameManager gameManager)
diff --git a/Engine.Core/Abstract/BaseEntity.cs b/Engine.Core/BaseEntity.cs
similarity index 96%
rename from Engine.Core/Abstract/BaseEntity.cs
rename to Engine.Core/BaseEntity.cs
index 02a1ec4..66db6b0 100644
--- a/Engine.Core/Abstract/BaseEntity.cs
+++ b/Engine.Core/BaseEntity.cs
@@ -19,8 +19,6 @@ public abstract class BaseEntity : IEntity
public virtual IStateEnable StateEnable => _stateEnable;
- public virtual bool IsActive => StateEnable.Enabled;
-
public string Id
{
get => _id;
@@ -55,6 +53,7 @@ public abstract class BaseEntity : IEntity
}
}
+ protected virtual void OnAssign(IStateEnable stateEnable) { }
public bool Assign(IStateEnable stateEnable)
{
if (IsInitialized)
@@ -62,6 +61,7 @@ public abstract class BaseEntity : IEntity
_stateEnable = stateEnable;
_stateEnable.Assign(this);
+ OnAssign(stateEnable);
OnStateEnableAssigned?.Invoke(this);
return true;
}
diff --git a/Engine.Core/BehaviourBase.cs b/Engine.Core/BehaviourBase.cs
index 8a7bbca..a89f88f 100644
--- a/Engine.Core/BehaviourBase.cs
+++ b/Engine.Core/BehaviourBase.cs
@@ -7,17 +7,14 @@ namespace Syntriax.Engine.Core;
public abstract class BehaviourBase : BaseEntity, IBehaviour
{
public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null;
-
public event IBehaviour.PriorityChangedEventHandler? OnPriorityChanged = null;
+ public event IActive.ActiveChangedEventHandler? OnActiveChanged = null;
private IBehaviourController _behaviourController = null!;
- private int _priority = 0;
-
public IBehaviourController BehaviourController => _behaviourController;
- public override bool IsActive => base.IsActive && BehaviourController.HierarchyObject.StateEnable.Enabled;
-
+ private int _priority = 0;
public int Priority
{
get => _priority;
@@ -32,18 +29,40 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
}
}
+ public bool IsActive { get; private set; } = false;
+
+ protected virtual void OnAssign(IBehaviourController behaviourController) { }
public bool Assign(IBehaviourController behaviourController)
{
if (IsInitialized)
return false;
_behaviourController = behaviourController;
+ OnAssign(behaviourController);
+ behaviourController.OnHierarchyObjectAssigned += OnHierarchyObjectAssigned;
+ if (behaviourController.HierarchyObject is not null)
+ OnHierarchyObjectAssigned(behaviourController);
OnBehaviourControllerAssigned?.Invoke(this);
return true;
}
+ private void OnHierarchyObjectAssigned(IHasHierarchyObject sender)
+ {
+ sender.HierarchyObject.OnActiveChanged += OnHierarchyObjectActiveChanged;
+ UpdateActive();
+ }
+
+ protected override void OnAssign(IStateEnable stateEnable)
+ {
+ base.OnAssign(stateEnable);
+
+ stateEnable.OnEnabledChanged += OnStateEnabledChanged;
+ }
+
protected override void UnassignInternal()
{
+ StateEnable.OnEnabledChanged -= OnStateEnabledChanged;
+ BehaviourController.OnHierarchyObjectAssigned -= OnHierarchyObjectAssigned;
base.UnassignInternal();
_behaviourController = null!;
}
@@ -54,4 +73,16 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
NotAssignedException.Check(this, _behaviourController);
NotAssignedException.Check(this, StateEnable);
}
+
+ private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive();
+ private void OnHierarchyObjectActiveChanged(IActive sender, bool previousState) => UpdateActive();
+
+ private void UpdateActive()
+ {
+ bool previousActive = IsActive;
+ IsActive = StateEnable.Enabled && _behaviourController.HierarchyObject.IsActive;
+
+ if (previousActive != IsActive)
+ OnActiveChanged?.Invoke(this, previousActive);
+ }
}
diff --git a/Engine.Core/BehaviourCollector.cs b/Engine.Core/BehaviourCollector.cs
index 83f6de3..b586523 100644
--- a/Engine.Core/BehaviourCollector.cs
+++ b/Engine.Core/BehaviourCollector.cs
@@ -66,6 +66,7 @@ public class BehaviourCollector : IBehaviourCollector where T : class
OnRemoved?.Invoke(this, tBehaviour);
}
+ protected virtual void OnAssign(IGameManager gameManager) { }
public bool Assign(IGameManager gameManager)
{
if (GameManager is not null)
@@ -78,6 +79,7 @@ public class BehaviourCollector : IBehaviourCollector where T : class
gameManager.OnHierarchyObjectUnRegistered += OnHierarchyObjectUnregistered;
GameManager = gameManager;
+ OnAssign(gameManager);
OnGameManagerAssigned?.Invoke(this);
return true;
diff --git a/Engine.Core/BehaviourController.cs b/Engine.Core/BehaviourController.cs
index 361ff08..341262d 100644
--- a/Engine.Core/BehaviourController.cs
+++ b/Engine.Core/BehaviourController.cs
@@ -124,12 +124,14 @@ public class BehaviourController : IBehaviourController
OnBehaviourRemoved?.Invoke(this, behaviour);
}
+ protected virtual void OnAssign(IHierarchyObject hierarchyObject) { }
public bool Assign(IHierarchyObject hierarchyObject)
{
if (HierarchyObject is not null && HierarchyObject.IsInitialized)
return false;
_hierarchyObject = hierarchyObject;
+ OnAssign(hierarchyObject);
OnHierarchyObjectAssigned?.Invoke(this);
return true;
}
diff --git a/Engine.Core/Factory/BehaviourFactory.cs b/Engine.Core/Factory/BehaviourFactory.cs
index 7191d1f..23bf214 100644
--- a/Engine.Core/Factory/BehaviourFactory.cs
+++ b/Engine.Core/Factory/BehaviourFactory.cs
@@ -17,10 +17,10 @@ public class BehaviourFactory
if (!stateEnable.Assign(behaviour))
throw AssignException.From(stateEnable, behaviour);
- if (!behaviour.Assign(hierarchyObject.BehaviourController))
- throw AssignException.From(behaviour, hierarchyObject.BehaviourController);
if (!behaviour.Assign(stateEnable))
throw AssignException.From(behaviour, stateEnable);
+ if (!behaviour.Assign(hierarchyObject.BehaviourController))
+ throw AssignException.From(behaviour, hierarchyObject.BehaviourController);
return behaviour;
}
diff --git a/Engine.Core/HierarchyObject.cs b/Engine.Core/HierarchyObject.cs
index 8247e76..b25bb26 100644
--- a/Engine.Core/HierarchyObject.cs
+++ b/Engine.Core/HierarchyObject.cs
@@ -15,6 +15,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
public event IHierarchyObject.ChildrenRemovedEventHandler? OnChildrenRemoved = null;
public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null;
public event INameable.NameChangedEventHandler? OnNameChanged = null;
+ public event IActive.ActiveChangedEventHandler? OnActiveChanged = null;
private string _name = nameof(HierarchyObject);
private IGameManager _gameManager = null!;
@@ -41,6 +42,8 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
public IBehaviourController BehaviourController => _behaviourController;
+ public bool IsActive { get; private set; } = false;
+
protected virtual void OnEnteringHierarchy(IGameManager gameManager) { }
bool IHierarchyObject.EnterHierarchy(IGameManager gameManager)
{
@@ -48,6 +51,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
return false;
_gameManager = gameManager;
+ UpdateActive();
OnEnteringHierarchy(gameManager);
OnEnteredHierarchy?.Invoke(this, gameManager);
return true;
@@ -75,6 +79,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
{
previousParent.RemoveChild(this);
previousParent.OnParentChanged -= NotifyChildrenOnParentChange;
+ previousParent.OnActiveChanged -= OnParentActiveChanged;
}
Parent = parent;
@@ -83,8 +88,10 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
{
parent.AddChild(this);
parent.OnParentChanged += NotifyChildrenOnParentChange;
+ parent.OnActiveChanged += OnParentActiveChanged;
}
+ UpdateActive();
OnParentChanged?.Invoke(this, previousParent, parent);
}
@@ -115,16 +122,43 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
child.SetParent(this);
}
+ protected virtual void OnAssign(IBehaviourController behaviourController) { }
public bool Assign(IBehaviourController behaviourController)
{
if (IsInitialized)
return false;
_behaviourController = behaviourController;
+ OnAssign(behaviourController);
OnBehaviourControllerAssigned?.Invoke(this);
return true;
}
+ protected override void OnAssign(IStateEnable stateEnable)
+ {
+ base.OnAssign(stateEnable);
+
+ stateEnable.OnEnabledChanged += OnStateEnabledChanged;
+ }
+
+ private void OnParentActiveChanged(IActive sender, bool previousState) => UpdateActive();
+ private void OnStateEnabledChanged(IStateEnable senfder, bool previousState) => UpdateActive();
+
+ private void UpdateActive()
+ {
+ bool previousActive = IsActive;
+ IsActive = StateEnable.Enabled && (Parent?.IsActive ?? true);
+
+ if (previousActive != IsActive)
+ OnActiveChanged?.Invoke(this, previousActive);
+ }
+
+ protected override void UnassignInternal()
+ {
+ base.UnassignInternal();
+ StateEnable.OnEnabledChanged -= OnStateEnabledChanged;
+ }
+
protected override void InitializeInternal()
{
base.InitializeInternal();
diff --git a/Engine.Core/StateEnable.cs b/Engine.Core/StateEnable.cs
index f00391b..1bfa884 100644
--- a/Engine.Core/StateEnable.cs
+++ b/Engine.Core/StateEnable.cs
@@ -6,7 +6,7 @@ public class StateEnable : IStateEnable
{
public event IAssignable.UnassignEventHandler? OnUnassigned = null;
public event IHasEntity.EntityAssignedEventHandler? OnEntityAssigned = null;
- public event IStateEnable.NameChangedEventHandler? OnEnabledChanged = null;
+ public event IStateEnable.EnabledChangedEventHandler? OnEnabledChanged = null;
private bool _enabled = true;
private IEntity _entity = null!;
@@ -27,12 +27,14 @@ public class StateEnable : IStateEnable
}
}
+ protected virtual void OnAssign(IEntity entity) { }
public bool Assign(IEntity entity)
{
if (_entity is not null && _entity.IsInitialized)
return false;
_entity = entity;
+ OnAssign(entity);
OnEntityAssigned?.Invoke(this);
return true;
}