8 Commits

26 changed files with 181 additions and 96 deletions

View File

@@ -60,7 +60,7 @@ public interface IBehaviourController : IInitializable, IHasHierarchyObject, IEn
/// </summary> /// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/>s to get.</typeparam> /// <typeparam name="T">The type of <see cref="IBehaviour"/>s to get.</typeparam>
/// <returns>A list of <see cref="IBehaviour"/>s of the specified type.</returns> /// <returns>A list of <see cref="IBehaviour"/>s of the specified type.</returns>
IList<T> GetBehaviours<T>(); IReadOnlyList<T> GetBehaviours<T>();
/// <summary> /// <summary>
/// Gets all <see cref="IBehaviour"/>s of the specified type and stores them in the provided list. /// Gets all <see cref="IBehaviour"/>s of the specified type and stores them in the provided list.

View File

@@ -32,11 +32,21 @@ public interface IGameManager : IEntity, IEnumerable<IHierarchyObject>
/// </summary> /// </summary>
event HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered; event HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered;
/// <summary>
/// Current time scale the <see cref="IGameManager"/> operates on.
/// </summary>
float TimeScale { get; set; }
/// <summary> /// <summary>
/// Contains time data related to this <see cref="IGameManager"/>. /// Contains time data related to this <see cref="IGameManager"/>.
/// </summary> /// </summary>
EngineTime Time { get; } EngineTime Time { get; }
/// <summary>
/// Contains unscaled time data related to this <see cref="IGameManager"/>.
/// </summary>
EngineTime UnscaledTime { get; }
/// <summary> /// <summary>
/// Gets a read-only list of <see cref="IHierarchyObject"/>s managed by the <see cref="IGameManager"/>. /// Gets a read-only list of <see cref="IHierarchyObject"/>s managed by the <see cref="IGameManager"/>.
/// </summary> /// </summary>

View File

@@ -1,4 +1,5 @@
using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Core.Helpers;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core;
@@ -55,6 +56,8 @@ public abstract class Behaviour : BehaviourBase
protected virtual void OnPreUpdate() { } protected virtual void OnPreUpdate() { }
protected virtual void PreUpdate(IBehaviourController _) protected virtual void PreUpdate(IBehaviourController _)
{ {
AssertHelpers.AssertInitialized(this);
OnPreUpdatePreActiveCheck(); OnPreUpdatePreActiveCheck();
if (!IsActive) if (!IsActive)
@@ -77,6 +80,8 @@ public abstract class Behaviour : BehaviourBase
protected virtual void OnUpdate() { } protected virtual void OnUpdate() { }
protected virtual void Update(IBehaviourController _) protected virtual void Update(IBehaviourController _)
{ {
AssertHelpers.AssertInitialized(this);
OnUpdatePreActiveCheck(); OnUpdatePreActiveCheck();
if (!IsActive) if (!IsActive)
@@ -89,6 +94,8 @@ public abstract class Behaviour : BehaviourBase
protected virtual void OnPreDraw() { } protected virtual void OnPreDraw() { }
protected virtual void PreDraw(IBehaviourController _) protected virtual void PreDraw(IBehaviourController _)
{ {
AssertHelpers.AssertInitialized(this);
OnPreDrawPreActiveCheck(); OnPreDrawPreActiveCheck();
if (!StateEnable.Enabled) if (!StateEnable.Enabled)

View File

@@ -8,7 +8,7 @@ public abstract class Behaviour2D : Behaviour, IBehaviour2D
protected sealed override void OnInitialize(IInitializable _) protected sealed override void OnInitialize(IInitializable _)
{ {
Transform = BehaviourController.GetBehaviourInChildren<ITransform2D>() ?? throw new($"{HierarchyObject.Name} does not contain any {nameof(ITransform2D)}"); Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
base.OnInitialize(_); base.OnInitialize(_);
} }

View File

@@ -1,5 +1,6 @@
using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Core.Exceptions; using Syntriax.Engine.Core.Exceptions;
using Syntriax.Engine.Core.Helpers;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core;
@@ -69,9 +70,8 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
protected override void InitializeInternal() protected override void InitializeInternal()
{ {
base.InitializeInternal(); AssertHelpers.AssertBehaviourControllerAssigned(this);
NotAssignedException.Check(this, _behaviourController); AssertHelpers.AssertStateEnableAssigned(this);
NotAssignedException.Check(this, StateEnable);
} }
private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive(); private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive();

View File

@@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Core.Exceptions; using Syntriax.Engine.Core.Helpers;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core;
@@ -72,7 +72,7 @@ public class BehaviourController : IBehaviourController
return default; return default;
} }
public IList<T> GetBehaviours<T>() public IReadOnlyList<T> GetBehaviours<T>()
{ {
List<T>? behaviours = null; List<T>? behaviours = null;
foreach (IBehaviour behaviourItem in this.behaviours) foreach (IBehaviour behaviourItem in this.behaviours)
@@ -141,7 +141,7 @@ public class BehaviourController : IBehaviourController
if (IsInitialized) if (IsInitialized)
return false; return false;
NotAssignedException.Check(this, _hierarchyObject); AssertHelpers.AssertHierarchyObjectAssigned(this);
foreach (IBehaviour behaviour in behaviours) foreach (IBehaviour behaviour in behaviours)
behaviour.Initialize(); behaviour.Initialize();

View File

@@ -1,12 +0,0 @@
using System;
namespace Syntriax.Engine.Core.Exceptions;
public class AssignException : Exception
{
public AssignException() : base("Assign operation has failed.") { }
public AssignException(string? message) : base(message) { }
public static AssignException From<T, T2>(T to, T2? value)
=> new($"Assign operation has failed on T: {to?.GetType().FullName ?? "\"null\""}, value: {value?.GetType().ToString() ?? "\"null\""}");
}

View File

@@ -0,0 +1,9 @@
using System;
namespace Syntriax.Engine.Core.Exceptions;
public class AssignFailedException(string? message) : Exception(message)
{
public static AssignFailedException From<T, T2>(T to, T2? value)
=> new($"Assign operation has failed on T: {to?.GetType().FullName ?? "\"null\""}, value: {value?.GetType().ToString() ?? "\"null\""}");
}

View File

@@ -0,0 +1,9 @@
using System;
namespace Syntriax.Engine.Core.Exceptions;
public class BehaviourNotFoundException(string? message) : Exception(message)
{
public static NotAssignedException FromType<TBehaviour>()
=> new($"{typeof(TBehaviour).FullName} was not found");
}

View File

@@ -0,0 +1,9 @@
using System;
namespace Syntriax.Engine.Core.Exceptions;
public class HierarchyObjectNotFoundException(string? message) : Exception(message)
{
public static NotAssignedException FromType<THierarchyObject>()
=> new($"{typeof(THierarchyObject).FullName} was not found");
}

View File

@@ -1,21 +1,9 @@
using System; using System;
using Syntriax.Engine.Core.Abstract;
namespace Syntriax.Engine.Core.Exceptions; namespace Syntriax.Engine.Core.Exceptions;
public class NotAssignedException : Exception public class NotAssignedException(string? message) : Exception(message)
{ {
public NotAssignedException() : base("The object has not been assigned.") { }
public NotAssignedException(string? message) : base(message) { }
public static NotAssignedException From<T1, T2>(T1 to, T2? value) public static NotAssignedException From<T1, T2>(T1 to, T2? value)
=> new($"{value?.GetType().FullName ?? "\"null\""} has not been assigned to {to?.GetType().FullName ?? "\"null\""}"); => new($"{value?.GetType().FullName ?? "\"null\""} has not been assigned to {to?.GetType().FullName ?? "\"null\""}");
public static void Check<T1, T2>(T1 to, T2? value)
{
if (value is not null)
return;
throw From(to, value);
}
} }

View File

@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Core.Exceptions;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core;
@@ -19,6 +20,15 @@ public static class BehaviourControllerExtensions
return behaviour is not null; return behaviour is not null;
} }
/// <summary>
/// Gets a <see cref="IBehaviour"/> of the specified type in the provided <see cref="IBehaviourController"/>. Throws an error if not found.
/// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
/// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
public static T GetRequiredBehaviour<T>(this IBehaviourController behaviourController) where T : class
=> behaviourController.GetBehaviour<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.HierarchyObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName}");
/// <summary> /// <summary>
/// Gets an existing <see cref="IBehaviour"/> of the specified type, or adds and returns a new one if it doesn't exist. /// Gets an existing <see cref="IBehaviour"/> of the specified type, or adds and returns a new one if it doesn't exist.
/// </summary> /// </summary>
@@ -30,7 +40,7 @@ public static class BehaviourControllerExtensions
=> behaviourController.GetBehaviour<T>() ?? behaviourController.AddBehaviour<T>(args); => behaviourController.GetBehaviour<T>() ?? behaviourController.AddBehaviour<T>(args);
/// <summary> /// <summary>
/// Tries to get a <see cref="IBehaviour"/> of the specified type in the parent hierarchy. /// Tries to get a <see cref="IBehaviour"/> of the specified type in it's <see cref="IHierarchyObject"/>'s parents recursively.
/// </summary> /// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam> /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param> /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
@@ -43,7 +53,7 @@ public static class BehaviourControllerExtensions
} }
/// <summary> /// <summary>
/// Gets a <see cref="IBehaviour"/> of the specified type in the parent hierarchy. /// Gets a <see cref="IBehaviour"/> of the specified type in it's <see cref="IHierarchyObject"/>'s parents recursively.
/// </summary> /// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam> /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param> /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
@@ -64,7 +74,16 @@ public static class BehaviourControllerExtensions
} }
/// <summary> /// <summary>
/// Tries to get a <see cref="IBehaviour"/> of the specified type in the child hierarchy. /// Gets a <see cref="IBehaviour"/> of the specified type in it's <see cref="IHierarchyObject"/>'s parents recursively. Throws an error if not found.
/// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
/// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
public static T GetRequiredBehaviourInParent<T>(this IBehaviourController behaviourController) where T : class
=> behaviourController.GetBehaviourInParent<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.HierarchyObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any parent");
/// <summary>
/// Tries to get a <see cref="IBehaviour"/> of the specified type in it's <see cref="IHierarchyObject"/>'s children recursively.
/// </summary> /// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam> /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param> /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
@@ -77,7 +96,7 @@ public static class BehaviourControllerExtensions
} }
/// <summary> /// <summary>
/// Gets a <see cref="IBehaviour"/> of the specified type in the child hierarchy. /// Gets a <see cref="IBehaviour"/> of the specified type in it's <see cref="IHierarchyObject"/>'s children recursively.
/// </summary> /// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam> /// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param> /// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
@@ -93,4 +112,13 @@ public static class BehaviourControllerExtensions
return default; return default;
} }
/// <summary>
/// Gets a <see cref="IBehaviour"/> of the specified type in the children recursively. Throws an error if not found.
/// </summary>
/// <typeparam name="T">The type of <see cref="IBehaviour"/> to get.</typeparam>
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
/// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
public static T GetRequiredBehaviourInChildren<T>(this IBehaviourController behaviourController) where T : class
=> behaviourController.GetBehaviourInChildren<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.HierarchyObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any children ");
} }

View File

@@ -1,4 +1,5 @@
using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Core.Exceptions;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core;
@@ -6,4 +7,10 @@ public static class GameManagerExtensions
{ {
public static IHierarchyObject InstantiateHierarchyObject(this IGameManager gameManager, params object?[]? args) public static IHierarchyObject InstantiateHierarchyObject(this IGameManager gameManager, params object?[]? args)
=> gameManager.InstantiateHierarchyObject<HierarchyObject>(args); => gameManager.InstantiateHierarchyObject<HierarchyObject>(args);
public static T GetRequiredHierarchyObject<T>(this IGameManager gameManager) where T : class
=> gameManager.GetHierarchyObject<T>() ?? throw new HierarchyObjectNotFoundException($"{gameManager.GetType().FullName}({gameManager.Id}) does not contain any {nameof(IHierarchyObject)} object of type {typeof(T).FullName}");
public static T FindRequiredBehaviour<T>(this IGameManager gameManager) where T : class
=> gameManager.FindBehaviour<T>() ?? throw new BehaviourNotFoundException($"{gameManager.GetType().FullName}({gameManager.Id}) does not contain any {nameof(IHierarchyObject)} with {nameof(IBehaviour)} of type {typeof(T).FullName}");
} }

View File

@@ -16,7 +16,7 @@ public static class HierarchyObjectExtensions
return hierarchyObject; return hierarchyObject;
} }
public static T? FindHierarchyObject<T>(this IEnumerable<IHierarchyObject> hierarchyObjects) where T : class public static T? GetHierarchyObject<T>(this IEnumerable<IHierarchyObject> hierarchyObjects) where T : class
{ {
foreach (IHierarchyObject hierarchyObject in hierarchyObjects) foreach (IHierarchyObject hierarchyObject in hierarchyObjects)
if (hierarchyObject is T @object) if (hierarchyObject is T @object)
@@ -25,13 +25,13 @@ public static class HierarchyObjectExtensions
return default; return default;
} }
public static bool TryFindHierarchyObject<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class public static bool TryGetHierarchyObject<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
{ {
behaviour = FindHierarchyObject<T>(hierarchyObjects); behaviour = GetHierarchyObject<T>(hierarchyObjects);
return behaviour is not null; return behaviour is not null;
} }
public static void FindHierarchyObjects<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, List<T> behaviours) where T : class public static void GetHierarchyObjects<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, List<T> behaviours) where T : class
{ {
behaviours.Clear(); behaviours.Clear();
foreach (IHierarchyObject hierarchyObject in hierarchyObjects) foreach (IHierarchyObject hierarchyObject in hierarchyObjects)

View File

@@ -14,10 +14,10 @@ public class BehaviourControllerFactory
T behaviourController = TypeFactory.Get<T>(args); T behaviourController = TypeFactory.Get<T>(args);
if (!hierarchyObject.Assign(behaviourController)) if (!hierarchyObject.Assign(behaviourController))
throw AssignException.From(hierarchyObject, behaviourController); throw AssignFailedException.From(hierarchyObject, behaviourController);
if (!behaviourController.Assign(hierarchyObject)) if (!behaviourController.Assign(hierarchyObject))
throw AssignException.From(behaviourController, hierarchyObject); throw AssignFailedException.From(behaviourController, hierarchyObject);
return behaviourController; return behaviourController;
} }

View File

@@ -15,12 +15,12 @@ public class BehaviourFactory
stateEnable ??= TypeFactory.Get<StateEnable>(); stateEnable ??= TypeFactory.Get<StateEnable>();
if (!stateEnable.Assign(behaviour)) if (!stateEnable.Assign(behaviour))
throw AssignException.From(stateEnable, behaviour); throw AssignFailedException.From(stateEnable, behaviour);
if (!behaviour.Assign(stateEnable)) if (!behaviour.Assign(stateEnable))
throw AssignException.From(behaviour, stateEnable); throw AssignFailedException.From(behaviour, stateEnable);
if (!behaviour.Assign(hierarchyObject.BehaviourController)) if (!behaviour.Assign(hierarchyObject.BehaviourController))
throw AssignException.From(behaviour, hierarchyObject.BehaviourController); throw AssignFailedException.From(behaviour, hierarchyObject.BehaviourController);
return behaviour; return behaviour;
} }

View File

@@ -23,14 +23,14 @@ public class HierarchyObjectFactory
stateEnable ??= TypeFactory.Get<StateEnable>(); stateEnable ??= TypeFactory.Get<StateEnable>();
if (!behaviourController.Assign(hierarchyObject)) if (!behaviourController.Assign(hierarchyObject))
throw AssignException.From(behaviourController, hierarchyObject); throw AssignFailedException.From(behaviourController, hierarchyObject);
if (!stateEnable.Assign(hierarchyObject)) if (!stateEnable.Assign(hierarchyObject))
throw AssignException.From(stateEnable, hierarchyObject); throw AssignFailedException.From(stateEnable, hierarchyObject);
if (!hierarchyObject.Assign(behaviourController)) if (!hierarchyObject.Assign(behaviourController))
throw AssignException.From(hierarchyObject, behaviourController); throw AssignFailedException.From(hierarchyObject, behaviourController);
if (!hierarchyObject.Assign(stateEnable)) if (!hierarchyObject.Assign(stateEnable))
throw AssignException.From(hierarchyObject, stateEnable); throw AssignFailedException.From(hierarchyObject, stateEnable);
return hierarchyObject; return hierarchyObject;
} }

View File

@@ -12,10 +12,10 @@ public class StateEnableFactory
T stateEnable = TypeFactory.Get<T>(args); T stateEnable = TypeFactory.Get<T>(args);
if (!entity.Assign(stateEnable)) if (!entity.Assign(stateEnable))
throw AssignException.From(entity, stateEnable); throw AssignFailedException.From(entity, stateEnable);
if (!stateEnable.Assign(entity)) if (!stateEnable.Assign(entity))
throw AssignException.From(stateEnable, entity); throw AssignFailedException.From(stateEnable, entity);
return stateEnable; return stateEnable;
} }

View File

@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Core.Exceptions; using Syntriax.Engine.Core.Helpers;
namespace Syntriax.Engine.Core; namespace Syntriax.Engine.Core;
@@ -18,25 +18,17 @@ public class GameManager : BaseEntity, IGameManager
public event IGameManager.HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null; public event IGameManager.HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null;
private readonly List<IHierarchyObject> _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL); private readonly List<IHierarchyObject> _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL);
private float _timeScale = 1f;
public IReadOnlyList<IHierarchyObject> HierarchyObjects => _hierarchyObjects; public IReadOnlyList<IHierarchyObject> HierarchyObjects => _hierarchyObjects;
public override IStateEnable StateEnable
{
get
{
if (base.StateEnable is null)
{
Assign(Factory.StateEnableFactory.Instantiate(this));
if (base.StateEnable is null)
throw NotAssignedException.From(this, base.StateEnable);
}
return base.StateEnable;
}
}
public EngineTime Time { get; private set; } = new(); public EngineTime Time { get; private set; } = new();
public EngineTime UnscaledTime { get; private set; } = new();
public float TimeScale
{
get => _timeScale;
set => _timeScale = value.Max(0f);
}
public void Register(IHierarchyObject hierarchyObject) public void Register(IHierarchyObject hierarchyObject)
{ {
@@ -68,6 +60,12 @@ public class GameManager : BaseEntity, IGameManager
} }
public void Remove(IHierarchyObject hierarchyObject) public void Remove(IHierarchyObject hierarchyObject)
{
hierarchyObject.SetParent(null);
RemoveIncursive(hierarchyObject);
}
private void RemoveIncursive(IHierarchyObject hierarchyObject)
{ {
if (!_hierarchyObjects.Contains(hierarchyObject)) if (!_hierarchyObjects.Contains(hierarchyObject))
throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}."); throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}.");
@@ -79,7 +77,6 @@ public class GameManager : BaseEntity, IGameManager
Remove(hierarchyObject.Children[i]); Remove(hierarchyObject.Children[i]);
_hierarchyObjects.Remove(hierarchyObject); _hierarchyObjects.Remove(hierarchyObject);
hierarchyObject.SetParent(null);
if (!hierarchyObject.ExitHierarchy()) if (!hierarchyObject.ExitHierarchy())
throw new Exception($"{hierarchyObject.Name} can't exit the hierarchy"); throw new Exception($"{hierarchyObject.Name} can't exit the hierarchy");
@@ -92,9 +89,6 @@ public class GameManager : BaseEntity, IGameManager
protected override void InitializeInternal() protected override void InitializeInternal()
{ {
base.InitializeInternal();
NotAssignedException.Check(this, StateEnable);
foreach (IHierarchyObject hierarchyObject in HierarchyObjects) foreach (IHierarchyObject hierarchyObject in HierarchyObjects)
hierarchyObject.Initialize(); hierarchyObject.Initialize();
} }
@@ -108,18 +102,23 @@ public class GameManager : BaseEntity, IGameManager
public void Update(EngineTime engineTime) public void Update(EngineTime engineTime)
{ {
Time = engineTime; AssertHelpers.AssertInitialized(this);
OnPreUpdate?.Invoke(this, engineTime); UnscaledTime = engineTime;
Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
OnPreUpdate?.Invoke(this, Time);
for (int i = 0; i < HierarchyObjects.Count; i++) for (int i = 0; i < HierarchyObjects.Count; i++)
HierarchyObjects[i].BehaviourController.Update(); HierarchyObjects[i].BehaviourController.Update();
OnUpdate?.Invoke(this, engineTime); OnUpdate?.Invoke(this, Time);
} }
public void PreDraw() public void PreDraw()
{ {
AssertHelpers.AssertInitialized(this);
for (int i = 0; i < HierarchyObjects.Count; i++) for (int i = 0; i < HierarchyObjects.Count; i++)
HierarchyObjects[i].BehaviourController.UpdatePreDraw(); HierarchyObjects[i].BehaviourController.UpdatePreDraw();

View File

@@ -0,0 +1,33 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Syntriax.Engine.Core.Abstract;
namespace Syntriax.Engine.Core.Helpers;
public class AssertHelpers
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AssertInitialized(IInitializable initializable)
=> Debug.Assert(initializable.IsInitialized, $"{initializable.GetType().Name} must be initialized");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AssertBehaviourControllerAssigned(IHasBehaviourController assignable)
=> Debug.Assert(assignable.BehaviourController is not null, $"{assignable.GetType().Name} must be initialized");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AssertEntityAssigned(IHasEntity assignable)
=> Debug.Assert(assignable.Entity is not null, $"{assignable.GetType().Name} must be initialized");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AssertGameManagerAssigned(IHasGameManager assignable)
=> Debug.Assert(assignable.GameManager is not null, $"{assignable.GetType().Name} must be initialized");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AssertHierarchyObjectAssigned(IHasHierarchyObject assignable)
=> Debug.Assert(assignable.HierarchyObject is not null, $"{assignable.GetType().Name} must be initialized");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AssertStateEnableAssigned(IHasStateEnable assignable)
=> Debug.Assert(assignable.StateEnable is not null, $"{assignable.GetType().Name} must be initialized");
}

View File

@@ -64,7 +64,6 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
OnExitingHierarchy(gameManager); OnExitingHierarchy(gameManager);
_gameManager = null!; _gameManager = null!;
SetParent(null);
OnExitedHierarchy?.Invoke(this, gameManager); OnExitedHierarchy?.Invoke(this, gameManager);
return true; return true;
} }
@@ -72,7 +71,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
public void SetParent(IHierarchyObject? parent) public void SetParent(IHierarchyObject? parent)
{ {
if (parent == this) if (parent == this)
throw new Exceptions.AssignException($"{Name} can not parent itself"); throw new Exceptions.AssignFailedException($"{Name} can not parent itself");
if (Parent == parent) if (Parent == parent)
return; return;
@@ -109,13 +108,13 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
OnChildrenAdded?.Invoke(this, parent); OnChildrenAdded?.Invoke(this, parent);
} }
public void RemoveChild(IHierarchyObject parent) public void RemoveChild(IHierarchyObject child)
{ {
if (!_children.Remove(parent)) if (!_children.Remove(child))
return; return;
parent.SetParent(null); child.SetParent(null);
OnChildrenRemoved?.Invoke(this, parent); OnChildrenRemoved?.Invoke(this, child);
} }
protected virtual void OnAssign(IBehaviourController behaviourController) { } protected virtual void OnAssign(IBehaviourController behaviourController) { }

View File

@@ -220,7 +220,6 @@ public class Transform2D : Behaviour, ITransform2D
ITransform2D? previousParent = parentTransform; ITransform2D? previousParent = parentTransform;
if (previousParent is not null) if (previousParent is not null)
{ {
previousParent.BehaviourController.HierarchyObject.RemoveChild(HierarchyObject);
previousParent.OnPositionChanged -= RecalculatePosition; previousParent.OnPositionChanged -= RecalculatePosition;
previousParent.OnScaleChanged -= RecalculateScale; previousParent.OnScaleChanged -= RecalculateScale;
previousParent.OnRotationChanged -= RecalculateRotation; previousParent.OnRotationChanged -= RecalculateRotation;
@@ -232,7 +231,6 @@ public class Transform2D : Behaviour, ITransform2D
if (parentTransform is not null) if (parentTransform is not null)
{ {
parentTransform.BehaviourController.HierarchyObject.AddChild(HierarchyObject);
parentTransform.OnPositionChanged += RecalculatePosition; parentTransform.OnPositionChanged += RecalculatePosition;
parentTransform.OnScaleChanged += RecalculateScale; parentTransform.OnScaleChanged += RecalculateScale;
parentTransform.OnRotationChanged += RecalculateRotation; parentTransform.OnRotationChanged += RecalculateRotation;

View File

@@ -25,7 +25,7 @@ public class PhysicsCoroutineManager : HierarchyObject
protected override void OnEnteringHierarchy(IGameManager gameManager) protected override void OnEnteringHierarchy(IGameManager gameManager)
{ {
physicsEngine = gameManager.FindHierarchyObject<IPhysicsEngine2D>(); physicsEngine = gameManager.GetHierarchyObject<IPhysicsEngine2D>();
if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine) if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine)
foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep; foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep;
else else
@@ -56,7 +56,7 @@ public class PhysicsCoroutineManager : HierarchyObject
if (GameManager is not IGameManager gameManager) if (GameManager is not IGameManager gameManager)
return; return;
physicsEngine = gameManager.FindHierarchyObject<IPhysicsEngine2D>(); physicsEngine = gameManager.GetHierarchyObject<IPhysicsEngine2D>();
if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine) if (physicsEngine is IPhysicsEngine2D foundPhysicsEngine)
{ {
foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep; foundPhysicsEngine.OnPhysicsStep += OnPhysicsStep;

View File

@@ -20,13 +20,13 @@ public class TickerBehaviour : StopwatchBehaviour, ITicker
{ {
base.OnUpdate(); base.OnUpdate();
if (Time < nextTick) while (Time > nextTick)
return; {
nextTick += Period; nextTick += Period;
TickCounter++; TickCounter++;
OnTick?.Invoke(this); OnTick?.Invoke(this);
} }
}
protected override void OnFinalize() protected override void OnFinalize()
{ {

View File

@@ -54,7 +54,7 @@ public class TweenManager : HierarchyObject
protected override void OnEnteringHierarchy(IGameManager gameManager) protected override void OnEnteringHierarchy(IGameManager gameManager)
{ {
coroutineManager = gameManager.FindHierarchyObject<CoroutineManager>() ?? throw new($"No {nameof(CoroutineManager)} was found in the game manager"); coroutineManager = gameManager.GetRequiredHierarchyObject<CoroutineManager>();
} }
protected override void OnExitingHierarchy(IGameManager gameManager) protected override void OnExitingHierarchy(IGameManager gameManager)

View File

@@ -1,6 +1,7 @@
# Work In Progress # Work In Progress
This engine is still in development but the implemented features include: This engine is still in development so there **WILL** be breaking changes, but the implemented features include:
- Modular Systems - Modular Systems
- Behaviour System - Behaviour System
- 2D Physics Engine(**Not Fully Completed, but usable**) - 2D Physics Engine(**Not Fully Completed, but usable**)