Compare commits
15 Commits
5d897f2f56
...
2cf6135063
| Author | SHA1 | Date | |
|---|---|---|---|
| 2cf6135063 | |||
| be06575f91 | |||
| ed6975bf24 | |||
| d9660c08b1 | |||
| 3902f1caca | |||
| 14e3337daa | |||
| f729cdc0a8 | |||
| c767e1e856 | |||
| f96c58cbd4 | |||
| fed288859f | |||
| 6e4c9b0ef8 | |||
| b931abb735 | |||
| 72492a9f5a | |||
| 2f043c19a6 | |||
| dbb263ebed |
105
Engine.Core/Abstract/BaseEntity.cs
Normal file
105
Engine.Core/Abstract/BaseEntity.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
|
public abstract class BaseEntity : IEntity
|
||||||
|
{
|
||||||
|
public Action<IEntity, string>? OnIdChanged { get; set; } = null;
|
||||||
|
|
||||||
|
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
||||||
|
public Action<IAssignableStateEnable>? OnStateEnableAssigned { get; set; } = null;
|
||||||
|
|
||||||
|
public Action<IInitialize>? OnInitialized { get; set; } = null;
|
||||||
|
public Action<IInitialize>? OnFinalized { get; set; } = null;
|
||||||
|
|
||||||
|
|
||||||
|
private IStateEnable _stateEnable = null!;
|
||||||
|
|
||||||
|
private bool _initialized = false;
|
||||||
|
private string _id = string.Empty;
|
||||||
|
|
||||||
|
public virtual IStateEnable StateEnable => _stateEnable;
|
||||||
|
|
||||||
|
public virtual bool IsActive => StateEnable.Enabled;
|
||||||
|
|
||||||
|
public string Id
|
||||||
|
{
|
||||||
|
get => _id;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string previousId = _id;
|
||||||
|
|
||||||
|
_id = value;
|
||||||
|
OnIdChanged?.Invoke(this, previousId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Initialized
|
||||||
|
{
|
||||||
|
get => _initialized;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (value == _initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_initialized = value;
|
||||||
|
if (value)
|
||||||
|
OnInitialized?.Invoke(this);
|
||||||
|
else
|
||||||
|
OnFinalized?.Invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Assign(IStateEnable stateEnable)
|
||||||
|
{
|
||||||
|
if (Initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_stateEnable = stateEnable;
|
||||||
|
_stateEnable.Assign(this);
|
||||||
|
OnStateEnableAssigned?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UnassignInternal() { }
|
||||||
|
public bool Unassign()
|
||||||
|
{
|
||||||
|
if (Initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UnassignInternal();
|
||||||
|
|
||||||
|
OnUnassigned?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void InitializeInternal() { }
|
||||||
|
public bool Initialize()
|
||||||
|
{
|
||||||
|
if (Initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
InitializeInternal();
|
||||||
|
|
||||||
|
Initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void FinalizeInternal() { }
|
||||||
|
public bool Finalize()
|
||||||
|
{
|
||||||
|
if (!Initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FinalizeInternal();
|
||||||
|
|
||||||
|
Initialized = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BaseEntity() => _id = Guid.NewGuid().ToString("D");
|
||||||
|
protected BaseEntity(string id) => _id = id;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -5,4 +7,14 @@ namespace Syntriax.Engine.Core.Abstract;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEntity : IInitialize, IAssignableStateEnable
|
public interface IEntity : IInitialize, IAssignableStateEnable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the <see cref="Id"/> of the <see cref="IEntity"/> changes.
|
||||||
|
/// The string action parameter is the previous <see cref="Id"/> of the <see cref="IEntity"/>.
|
||||||
|
/// </summary>
|
||||||
|
Action<IEntity, string>? OnIdChanged { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the <see cref="IEntity"/>.
|
||||||
|
/// </summary>
|
||||||
|
string Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the transformation properties of an object such as position, scale, and rotation.
|
/// Represents the transformation properties of an object such as position, scale, and rotation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITransform
|
public interface ITransform : IAssignableGameObject, IEnumerable<ITransform>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event triggered when the <see cref="Position"/> of the <see cref="ITransform"/> changes.
|
/// Event triggered when the <see cref="Position"/> of the <see cref="ITransform"/> changes.
|
||||||
@@ -23,17 +24,75 @@ public interface ITransform
|
|||||||
Action<ITransform>? OnRotationChanged { get; set; }
|
Action<ITransform>? OnRotationChanged { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The position of the <see cref="ITransform"/> in 2D space.
|
/// Event triggered when the <see cref="Parent"/> of the <see cref="ITransform"/> changes. The second parameter is the old <see cref="ITransform"/>.
|
||||||
|
/// </summary>
|
||||||
|
Action<ITransform, ITransform?>? OnParentChanged { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when a new <see cref="ITransform"/> is added to the <see cref="Children"/>.
|
||||||
|
/// </summary>
|
||||||
|
Action<ITransform, ITransform>? OnChildrenAdded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when an <see cref="ITransform"/> is removed from the <see cref="Children"/>.
|
||||||
|
/// </summary>
|
||||||
|
Action<ITransform, ITransform>? OnChildrenRemoved { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The world position of the <see cref="ITransform"/> in 2D space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Vector2D Position { get; set; }
|
Vector2D Position { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The scale of the <see cref="ITransform"/>.
|
/// The world scale of the <see cref="ITransform"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Vector2D Scale { get; set; }
|
Vector2D Scale { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The rotation of the <see cref="ITransform"/> in degrees.
|
/// The world rotation of the <see cref="ITransform"/> in degrees.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
float Rotation { get; set; }
|
float Rotation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The local position of the <see cref="ITransform"/> in 2D space.
|
||||||
|
/// </summary>
|
||||||
|
Vector2D LocalPosition { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The local scale of the <see cref="ITransform"/>.
|
||||||
|
/// </summary>
|
||||||
|
Vector2D LocalScale { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The local rotation of the <see cref="ITransform"/> in degrees.
|
||||||
|
/// </summary>
|
||||||
|
float LocalRotation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parent <see cref="ITransform"/> of the <see cref="ITransform"/>.
|
||||||
|
/// </summary>
|
||||||
|
ITransform? Parent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="ITransform"/>s that have this <see cref="ITransform"/> as their <see cref="Parent"/>.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyList<ITransform> Children { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the parent <see cref="ITransform"/> of this <see cref="ITransform"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="transform">The parent <see cref="ITransform"/> to set.</param>
|
||||||
|
void SetParent(ITransform? transform);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a child <see cref="ITransform"/> to this <see cref="ITransform"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="transform">The child <see cref="ITransform"/> to add.</param>
|
||||||
|
void AddChild(ITransform transform);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a child <see cref="ITransform"/> from this <see cref="ITransform"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="transform">The child <see cref="ITransform"/> to remove.</param>
|
||||||
|
void RemoveChild(ITransform transform);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,43 +6,20 @@ using Syntriax.Engine.Core.Exceptions;
|
|||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")]
|
[System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")]
|
||||||
public abstract class Behaviour : IBehaviour
|
public abstract class Behaviour : BaseEntity, IBehaviour
|
||||||
{
|
{
|
||||||
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
|
||||||
public Action<IAssignableStateEnable>? OnStateEnableAssigned { get; set; } = null;
|
|
||||||
public Action<IAssignableBehaviourController>? OnBehaviourControllerAssigned { get; set; } = null;
|
public Action<IAssignableBehaviourController>? OnBehaviourControllerAssigned { get; set; } = null;
|
||||||
|
|
||||||
public Action<IInitialize>? OnInitialized { get; set; } = null;
|
|
||||||
public Action<IInitialize>? OnFinalized { get; set; } = null;
|
|
||||||
public Action<IBehaviour>? OnPriorityChanged { get; set; } = null;
|
public Action<IBehaviour>? OnPriorityChanged { get; set; } = null;
|
||||||
|
|
||||||
|
|
||||||
private IBehaviourController _behaviourController = null!;
|
private IBehaviourController _behaviourController = null!;
|
||||||
private IStateEnable _stateEnable = null!;
|
|
||||||
|
|
||||||
private bool _initialized = false;
|
|
||||||
private int _priority = 0;
|
private int _priority = 0;
|
||||||
|
|
||||||
public IStateEnable StateEnable => _stateEnable;
|
|
||||||
public IBehaviourController BehaviourController => _behaviourController;
|
public IBehaviourController BehaviourController => _behaviourController;
|
||||||
|
|
||||||
public bool IsActive => StateEnable.Enabled && BehaviourController.GameObject.StateEnable.Enabled;
|
public override bool IsActive => base.IsActive && BehaviourController.GameObject.StateEnable.Enabled;
|
||||||
|
|
||||||
public bool Initialized
|
|
||||||
{
|
|
||||||
get => _initialized;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
if (value == _initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_initialized = value;
|
|
||||||
if (value)
|
|
||||||
OnInitialized?.Invoke(this);
|
|
||||||
else
|
|
||||||
OnFinalized?.Invoke(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Priority
|
public int Priority
|
||||||
{
|
{
|
||||||
@@ -57,17 +34,6 @@ public abstract class Behaviour : IBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Assign(IStateEnable stateEnable)
|
|
||||||
{
|
|
||||||
if (Initialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_stateEnable = stateEnable;
|
|
||||||
_stateEnable.Assign(this);
|
|
||||||
OnStateEnableAssigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Assign(IBehaviourController behaviourController)
|
public bool Assign(IBehaviourController behaviourController)
|
||||||
{
|
{
|
||||||
if (Initialized)
|
if (Initialized)
|
||||||
@@ -78,36 +44,16 @@ public abstract class Behaviour : IBehaviour
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Unassign()
|
protected override void UnassignInternal()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
base.UnassignInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
_stateEnable = null!;
|
|
||||||
_behaviourController = null!;
|
_behaviourController = null!;
|
||||||
|
|
||||||
OnUnassigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Initialize()
|
protected override void InitializeInternal()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
base.InitializeInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
NotAssignedException.Check(this, _behaviourController);
|
NotAssignedException.Check(this, _behaviourController);
|
||||||
NotAssignedException.Check(this, _stateEnable);
|
NotAssignedException.Check(this, StateEnable);
|
||||||
|
|
||||||
Initialized = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Finalize()
|
|
||||||
{
|
|
||||||
if (!Initialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Initialized = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ using Syntriax.Engine.Core.Abstract;
|
|||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class BehaviourCacher<T> : IAssignableGameManager, IEnumerable<T>
|
public class BehaviourCollector<T> : IAssignableGameManager, IEnumerable<T>
|
||||||
{
|
{
|
||||||
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
||||||
public Action<IAssignableGameManager>? OnGameManagerAssigned { get; set; } = null;
|
public Action<IAssignableGameManager>? OnGameManagerAssigned { get; set; } = null;
|
||||||
|
|
||||||
public Action<BehaviourCacher<T>, T>? OnCached { get; set; } = null;
|
public Action<BehaviourCollector<T>, T>? OnCollected { get; set; } = null;
|
||||||
public Action<BehaviourCacher<T>, T>? OnUncached { get; set; } = null;
|
public Action<BehaviourCollector<T>, T>? OnRemoved { get; set; } = null;
|
||||||
|
|
||||||
private readonly List<T> _behaviours = new(32);
|
private readonly List<T> _behaviours = new(32);
|
||||||
|
|
||||||
@@ -21,8 +21,8 @@ public class BehaviourCacher<T> : IAssignableGameManager, IEnumerable<T>
|
|||||||
|
|
||||||
public T this[Index index] => _behaviours[index];
|
public T this[Index index] => _behaviours[index];
|
||||||
|
|
||||||
public BehaviourCacher() { }
|
public BehaviourCollector() { }
|
||||||
public BehaviourCacher(IGameManager gameManager) => Assign(gameManager);
|
public BehaviourCollector(IGameManager gameManager) => Assign(gameManager);
|
||||||
|
|
||||||
private void OnGameObjectRegistered(IGameManager manager, IGameObject gameObject)
|
private void OnGameObjectRegistered(IGameManager manager, IGameObject gameObject)
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,7 @@ public class BehaviourCacher<T> : IAssignableGameManager, IEnumerable<T>
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_behaviours.Add(tBehaviour);
|
_behaviours.Add(tBehaviour);
|
||||||
OnCached?.Invoke(this, tBehaviour);
|
OnCollected?.Invoke(this, tBehaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
|
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
|
||||||
@@ -53,7 +53,7 @@ public class BehaviourCacher<T> : IAssignableGameManager, IEnumerable<T>
|
|||||||
if (!_behaviours.Remove(tBehaviour))
|
if (!_behaviours.Remove(tBehaviour))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnUncached?.Invoke(this, tBehaviour);
|
OnRemoved?.Invoke(this, tBehaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Assign(IGameManager gameManager)
|
public bool Assign(IGameManager gameManager)
|
||||||
47
Engine.Core/Extensions/BehaviourControllerExtensions.cs
Normal file
47
Engine.Core/Extensions/BehaviourControllerExtensions.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
using Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public static class BehaviourControllerExtensions
|
||||||
|
{
|
||||||
|
public static bool TryGetBehaviourInParent<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
|
{
|
||||||
|
behaviour = GetBehaviourInParent<T>(behaviourController);
|
||||||
|
return behaviour is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? GetBehaviourInParent<T>(this IBehaviourController behaviourController) where T : class
|
||||||
|
{
|
||||||
|
IBehaviourController? controller = behaviourController;
|
||||||
|
|
||||||
|
while (controller is not null)
|
||||||
|
{
|
||||||
|
if (behaviourController.GetBehaviour<T>() is T behaviour)
|
||||||
|
return behaviour;
|
||||||
|
|
||||||
|
controller = controller.GameObject.Transform.Parent?.GameObject.BehaviourController;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetBehaviourInChildren<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
|
{
|
||||||
|
behaviour = GetBehaviourInChildren<T>(behaviourController);
|
||||||
|
return behaviour is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? GetBehaviourInChildren<T>(this IBehaviourController behaviourController) where T : class
|
||||||
|
{
|
||||||
|
if (behaviourController.GetBehaviour<T>() is T localBehaviour)
|
||||||
|
return localBehaviour;
|
||||||
|
|
||||||
|
foreach (ITransform transform in behaviourController.GameObject.Transform)
|
||||||
|
if (GetBehaviourInChildren<T>(transform.GameObject.BehaviourController) is T behaviour)
|
||||||
|
return behaviour;
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,18 +7,22 @@ namespace Syntriax.Engine.Core;
|
|||||||
|
|
||||||
public static class BehaviourExtensions
|
public static class BehaviourExtensions
|
||||||
{
|
{
|
||||||
public static bool TryFindBehaviour<T>(this IEnumerable<IGameObject> gameObjects, [NotNullWhen(returnValue: true)] out T? behaviour)
|
public static T? FindBehaviour<T>(this IEnumerable<IGameObject> gameObjects) where T : class
|
||||||
{
|
{
|
||||||
behaviour = default;
|
|
||||||
|
|
||||||
foreach (IGameObject gameObject in gameObjects)
|
foreach (IGameObject gameObject in gameObjects)
|
||||||
if (gameObject.BehaviourController.TryGetBehaviour(out behaviour))
|
if (gameObject.BehaviourController.TryGetBehaviour(out T? behaviour))
|
||||||
return true;
|
return behaviour;
|
||||||
|
|
||||||
return false;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FindBehaviours<T>(this IEnumerable<IGameObject> gameObjects, List<T> behaviours)
|
public static bool TryFindBehaviour<T>(this IEnumerable<IGameObject> gameObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
|
{
|
||||||
|
behaviour = FindBehaviour<T>(gameObjects);
|
||||||
|
return behaviour is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FindBehaviours<T>(this IEnumerable<IGameObject> gameObjects, List<T> behaviours) where T : class
|
||||||
{
|
{
|
||||||
behaviours.Clear();
|
behaviours.Clear();
|
||||||
List<T> cache = [];
|
List<T> cache = [];
|
||||||
|
|||||||
9
Engine.Core/Extensions/GameManagerExtensions.cs
Normal file
9
Engine.Core/Extensions/GameManagerExtensions.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public static class GameManagerExtensions
|
||||||
|
{
|
||||||
|
public static IGameObject InstantiateGameObject(this IGameManager gameManager, params object?[]? args)
|
||||||
|
=> gameManager.InstantiateGameObject<GameObject>(args);
|
||||||
|
}
|
||||||
@@ -4,11 +4,16 @@ namespace Syntriax.Engine.Core;
|
|||||||
|
|
||||||
public static class TransformExtensions
|
public static class TransformExtensions
|
||||||
{
|
{
|
||||||
public static ITransform SetTransform(this ITransform transform, Vector2D? position = null, float? rotation = null, Vector2D? scale = null)
|
public static ITransform SetTransform(this ITransform transform,
|
||||||
|
Vector2D? position = null, float? rotation = null, Vector2D? scale = null,
|
||||||
|
Vector2D? localPosition = null, float? localRotation = null, Vector2D? localScale = null)
|
||||||
{
|
{
|
||||||
if (position.HasValue) transform.Position = position.Value;
|
if (position.HasValue) transform.Position = position.Value;
|
||||||
if (rotation.HasValue) transform.Rotation = rotation.Value;
|
if (rotation.HasValue) transform.Rotation = rotation.Value;
|
||||||
if (scale.HasValue) transform.Scale = scale.Value;
|
if (scale.HasValue) transform.Scale = scale.Value;
|
||||||
|
if (localPosition.HasValue) transform.LocalPosition = localPosition.Value;
|
||||||
|
if (localRotation.HasValue) transform.LocalRotation = localRotation.Value;
|
||||||
|
if (localScale.HasValue) transform.LocalScale = localScale.Value;
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ public class GameObjectFactory
|
|||||||
behaviourController ??= TypeFactory.Get<BehaviourController>();
|
behaviourController ??= TypeFactory.Get<BehaviourController>();
|
||||||
stateEnable ??= TypeFactory.Get<StateEnable>();
|
stateEnable ??= TypeFactory.Get<StateEnable>();
|
||||||
|
|
||||||
|
if (!transform.Assign(gameObject))
|
||||||
|
throw AssignException.From(transform, gameObject);
|
||||||
|
|
||||||
if (!behaviourController.Assign(gameObject))
|
if (!behaviourController.Assign(gameObject))
|
||||||
throw AssignException.From(behaviourController, gameObject);
|
throw AssignException.From(behaviourController, gameObject);
|
||||||
if (!stateEnable.Assign(gameObject))
|
if (!stateEnable.Assign(gameObject))
|
||||||
|
|||||||
@@ -9,22 +9,15 @@ using Syntriax.Engine.Core.Factory;
|
|||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("GameObject Count: {_gameObjects.Count}")]
|
[System.Diagnostics.DebuggerDisplay("GameObject Count: {_gameObjects.Count}")]
|
||||||
public class GameManager : IGameManager
|
public class GameManager : BaseEntity, IGameManager
|
||||||
{
|
{
|
||||||
public Action<IGameManager, IGameObject>? OnGameObjectRegistered { get; set; } = null;
|
public Action<IGameManager, IGameObject>? OnGameObjectRegistered { get; set; } = null;
|
||||||
public Action<IGameManager, IGameObject>? OnGameObjectUnRegistered { get; set; } = null;
|
public Action<IGameManager, IGameObject>? OnGameObjectUnRegistered { get; set; } = null;
|
||||||
|
|
||||||
public Action<IInitialize>? OnInitialized { get; set; } = null;
|
|
||||||
public Action<IInitialize>? OnFinalized { get; set; } = null;
|
|
||||||
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
|
||||||
public Action<IAssignableStateEnable>? OnStateEnableAssigned { get; set; } = null;
|
|
||||||
|
|
||||||
|
|
||||||
private readonly List<IGameObject> _gameObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL);
|
private readonly List<IGameObject> _gameObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL);
|
||||||
|
|
||||||
private IStateEnable _stateEnable = null!;
|
|
||||||
private GameObjectFactory _gameObjectFactory = null!;
|
private GameObjectFactory _gameObjectFactory = null!;
|
||||||
private bool _initialized = false;
|
|
||||||
|
|
||||||
private GameObjectFactory GameObjectFactory
|
private GameObjectFactory GameObjectFactory
|
||||||
{
|
{
|
||||||
@@ -36,21 +29,20 @@ public class GameManager : IGameManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Initialized => _initialized;
|
|
||||||
public IReadOnlyList<IGameObject> GameObjects => _gameObjects;
|
public IReadOnlyList<IGameObject> GameObjects => _gameObjects;
|
||||||
|
|
||||||
public IStateEnable StateEnable
|
public override IStateEnable StateEnable
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_stateEnable is null)
|
if (base.StateEnable is null)
|
||||||
{
|
{
|
||||||
Assign(new StateEnableFactory().Instantiate(this));
|
Assign(new StateEnableFactory().Instantiate(this));
|
||||||
if (_stateEnable is null)
|
if (base.StateEnable is null)
|
||||||
throw NotAssignedException.From(this, _stateEnable);
|
throw NotAssignedException.From(this, base.StateEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _stateEnable;
|
return base.StateEnable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,52 +70,20 @@ public class GameManager : IGameManager
|
|||||||
return gameObject;
|
return gameObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Initialize()
|
protected override void InitializeInternal()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
base.InitializeInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
NotAssignedException.Check(this, StateEnable);
|
NotAssignedException.Check(this, StateEnable);
|
||||||
|
|
||||||
foreach (var gameObject in GameObjects)
|
foreach (var gameObject in GameObjects)
|
||||||
gameObject.Initialize();
|
gameObject.Initialize();
|
||||||
|
|
||||||
_initialized = true;
|
|
||||||
OnInitialized?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Finalize()
|
protected override void FinalizeInternal()
|
||||||
{
|
{
|
||||||
if (!Initialized)
|
base.FinalizeInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = GameObjects.Count; i >= 0; i--)
|
for (int i = GameObjects.Count; i >= 0; i--)
|
||||||
GameObjects[i].Finalize();
|
GameObjects[i].Finalize();
|
||||||
|
|
||||||
OnFinalized?.Invoke(this);
|
|
||||||
_initialized = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Assign(IStateEnable stateEnable)
|
|
||||||
{
|
|
||||||
if (Initialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_stateEnable = stateEnable;
|
|
||||||
OnStateEnableAssigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Unassign()
|
|
||||||
{
|
|
||||||
if (Initialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_stateEnable = null!;
|
|
||||||
OnUnassigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(EngineTime time)
|
public void Update(EngineTime time)
|
||||||
|
|||||||
@@ -6,19 +6,14 @@ using Syntriax.Engine.Core.Exceptions;
|
|||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")]
|
[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")]
|
||||||
public class GameObject : IGameObject
|
public class GameObject : BaseEntity, IGameObject
|
||||||
{
|
{
|
||||||
public Action<IAssignableStateEnable>? OnStateEnableAssigned { get; set; } = null;
|
|
||||||
public Action<IAssignableTransform>? OnTransformAssigned { get; set; } = null;
|
public Action<IAssignableTransform>? OnTransformAssigned { get; set; } = null;
|
||||||
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
|
||||||
public Action<IAssignableBehaviourController>? OnBehaviourControllerAssigned { get; set; } = null;
|
public Action<IAssignableBehaviourController>? OnBehaviourControllerAssigned { get; set; } = null;
|
||||||
public Action<IAssignableGameManager>? OnGameManagerAssigned { get; set; } = null;
|
public Action<IAssignableGameManager>? OnGameManagerAssigned { get; set; } = null;
|
||||||
|
|
||||||
public Action<IEntity>? OnNameChanged { get; set; } = null;
|
public Action<IEntity>? OnNameChanged { get; set; } = null;
|
||||||
|
|
||||||
public Action<IInitialize>? OnInitialized { get; set; } = null;
|
|
||||||
public Action<IInitialize>? OnFinalized { get; set; } = null;
|
|
||||||
|
|
||||||
public Action<IGameObject>? OnUpdated { get; set; } = null;
|
public Action<IGameObject>? OnUpdated { get; set; } = null;
|
||||||
|
|
||||||
|
|
||||||
@@ -28,29 +23,11 @@ public class GameObject : IGameObject
|
|||||||
private IGameManager _gameManager = null!;
|
private IGameManager _gameManager = null!;
|
||||||
|
|
||||||
private string _name = nameof(GameObject);
|
private string _name = nameof(GameObject);
|
||||||
private bool _initialized = false;
|
|
||||||
|
|
||||||
public ITransform Transform => _transform;
|
public ITransform Transform => _transform;
|
||||||
public IBehaviourController BehaviourController => _behaviourController;
|
public IBehaviourController BehaviourController => _behaviourController;
|
||||||
public IStateEnable StateEnable => _stateEnable;
|
|
||||||
public IGameManager GameManager => _gameManager;
|
public IGameManager GameManager => _gameManager;
|
||||||
|
|
||||||
public bool Initialized
|
|
||||||
{
|
|
||||||
get => _initialized;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
if (value == _initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_initialized = value;
|
|
||||||
if (value)
|
|
||||||
OnInitialized?.Invoke(this);
|
|
||||||
else
|
|
||||||
OnFinalized?.Invoke(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get => _name;
|
get => _name;
|
||||||
@@ -63,18 +40,14 @@ public class GameObject : IGameObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Initialize()
|
protected override void InitializeInternal()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
base.InitializeInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
NotAssignedException.Check(this, _transform);
|
NotAssignedException.Check(this, _transform);
|
||||||
NotAssignedException.Check(this, _behaviourController);
|
NotAssignedException.Check(this, _behaviourController);
|
||||||
NotAssignedException.Check(this, _stateEnable);
|
NotAssignedException.Check(this, _stateEnable);
|
||||||
NotAssignedException.Check(this, _gameManager);
|
NotAssignedException.Check(this, _gameManager);
|
||||||
|
|
||||||
Initialized = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
@@ -85,29 +58,12 @@ public class GameObject : IGameObject
|
|||||||
OnUpdated?.Invoke(this);
|
OnUpdated?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Finalize()
|
protected override void FinalizeInternal()
|
||||||
{
|
{
|
||||||
if (!Initialized)
|
base.FinalizeInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
|
foreach (IBehaviour behaviour in _behaviourController.GetBehaviours<IBehaviour>())
|
||||||
System.Threading.Tasks.Parallel.ForEach(
|
behaviour.Finalize();
|
||||||
_behaviourController.GetBehaviours<IBehaviour>(),
|
|
||||||
behaviour => behaviour.Finalize()
|
|
||||||
);
|
|
||||||
|
|
||||||
Initialized = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Assign(IStateEnable stateEnable)
|
|
||||||
{
|
|
||||||
if (Initialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_stateEnable = stateEnable;
|
|
||||||
OnStateEnableAssigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Assign(ITransform transform)
|
public bool Assign(ITransform transform)
|
||||||
@@ -140,18 +96,14 @@ public class GameObject : IGameObject
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Unassign()
|
protected override void UnassignInternal()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
base.UnassignInternal();
|
||||||
return false;
|
|
||||||
|
|
||||||
_stateEnable = null!;
|
_stateEnable = null!;
|
||||||
_transform = null!;
|
_transform = null!;
|
||||||
_behaviourController = null!;
|
_behaviourController = null!;
|
||||||
_gameManager = null!;
|
_gameManager = null!;
|
||||||
|
|
||||||
OnUnassigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameObject() { OnBehaviourControllerAssigned += ConnectBehaviourController; }
|
public GameObject() { OnBehaviourControllerAssigned += ConnectBehaviourController; }
|
||||||
|
|||||||
@@ -1,20 +1,42 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
using Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
|
[System.Diagnostics.DebuggerDisplay("Name: {GameObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
|
||||||
public class Transform : ITransform
|
public class Transform : ITransform
|
||||||
{
|
{
|
||||||
|
public Action<IAssignableGameObject>? OnGameObjectAssigned { get; set; } = null;
|
||||||
|
|
||||||
|
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
||||||
|
|
||||||
public Action<ITransform>? OnPositionChanged { get; set; } = null;
|
public Action<ITransform>? OnPositionChanged { get; set; } = null;
|
||||||
public Action<ITransform>? OnScaleChanged { get; set; } = null;
|
public Action<ITransform>? OnScaleChanged { get; set; } = null;
|
||||||
public Action<ITransform>? OnRotationChanged { get; set; } = null;
|
public Action<ITransform>? OnRotationChanged { get; set; } = null;
|
||||||
|
|
||||||
|
public Action<ITransform, ITransform?>? OnParentChanged { get; set; } = null;
|
||||||
|
public Action<ITransform, ITransform>? OnChildrenAdded { get; set; } = null;
|
||||||
|
public Action<ITransform, ITransform>? OnChildrenRemoved { get; set; } = null;
|
||||||
|
|
||||||
|
|
||||||
private Vector2D _position = Vector2D.Zero;
|
private Vector2D _position = Vector2D.Zero;
|
||||||
private Vector2D _scale = Vector2D.One;
|
private Vector2D _scale = Vector2D.One;
|
||||||
private float _rotation = 0f;
|
private float _rotation = 0f;
|
||||||
|
|
||||||
|
private Vector2D _localPosition = Vector2D.Zero;
|
||||||
|
private Vector2D _localScale = Vector2D.One;
|
||||||
|
private float _localRotation = 0f;
|
||||||
|
|
||||||
|
private readonly List<ITransform> _children = [];
|
||||||
|
|
||||||
|
public IGameObject GameObject { get; private set; } = null!;
|
||||||
|
public ITransform? Parent { get; private set; } = null;
|
||||||
|
|
||||||
|
public IReadOnlyList<ITransform> Children => _children;
|
||||||
|
|
||||||
public Vector2D Position
|
public Vector2D Position
|
||||||
{
|
{
|
||||||
get => _position;
|
get => _position;
|
||||||
@@ -24,6 +46,7 @@ public class Transform : ITransform
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_position = value;
|
_position = value;
|
||||||
|
UpdateLocalPosition();
|
||||||
OnPositionChanged?.Invoke(this);
|
OnPositionChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,6 +60,7 @@ public class Transform : ITransform
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_scale = value;
|
_scale = value;
|
||||||
|
UpdateLocalScale();
|
||||||
OnScaleChanged?.Invoke(this);
|
OnScaleChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +74,210 @@ public class Transform : ITransform
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_rotation = value;
|
_rotation = value;
|
||||||
|
UpdateLocalPosition();
|
||||||
OnRotationChanged?.Invoke(this);
|
OnRotationChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2D LocalPosition
|
||||||
|
{
|
||||||
|
get => _localPosition;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _localPosition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_localPosition = value;
|
||||||
|
UpdatePosition();
|
||||||
|
OnPositionChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2D LocalScale
|
||||||
|
{
|
||||||
|
get => _localScale;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _localScale)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_localScale = value;
|
||||||
|
UpdateScale();
|
||||||
|
OnScaleChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LocalRotation
|
||||||
|
{
|
||||||
|
get => _localRotation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _localRotation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_localRotation = value;
|
||||||
|
UpdateRotation();
|
||||||
|
OnRotationChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParent(ITransform? transform)
|
||||||
|
{
|
||||||
|
if (transform == this || Parent == transform)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ITransform? previousParent = Parent;
|
||||||
|
if (previousParent is not null)
|
||||||
|
{
|
||||||
|
previousParent.RemoveChild(this);
|
||||||
|
previousParent.OnPositionChanged -= RecalculatePosition;
|
||||||
|
previousParent.OnScaleChanged -= RecalculateScale;
|
||||||
|
previousParent.OnRotationChanged -= RecalculateRotation;
|
||||||
|
previousParent.OnParentChanged -= NotifyChildrenOnParentChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent = transform;
|
||||||
|
|
||||||
|
if (transform is not null)
|
||||||
|
{
|
||||||
|
transform.AddChild(this);
|
||||||
|
transform.OnPositionChanged += RecalculatePosition;
|
||||||
|
transform.OnScaleChanged += RecalculateScale;
|
||||||
|
transform.OnRotationChanged += RecalculateRotation;
|
||||||
|
transform.OnParentChanged += NotifyChildrenOnParentChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateLocalPosition();
|
||||||
|
UpdateLocalScale();
|
||||||
|
UpdateLocalRotation();
|
||||||
|
|
||||||
|
OnParentChanged?.Invoke(this, previousParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddChild(ITransform transform)
|
||||||
|
{
|
||||||
|
if (_children.Contains(transform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_children.Add(transform);
|
||||||
|
transform.SetParent(this);
|
||||||
|
OnChildrenAdded?.Invoke(this, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveChild(ITransform transform)
|
||||||
|
{
|
||||||
|
if (!_children.Remove(transform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
transform.SetParent(null);
|
||||||
|
OnChildrenRemoved?.Invoke(this, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<ITransform> GetEnumerator() => _children.GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator();
|
||||||
|
|
||||||
|
private void NotifyChildrenOnParentChange(ITransform transform, ITransform? previousParent)
|
||||||
|
{
|
||||||
|
// TODO No idea how logical this is to propagate this to the children the way I'm doing right now.
|
||||||
|
// I was originally gonna just call `child.OnParentChanged?.Invoke(child, child.Parent);` but seems an unnecessary call too?
|
||||||
|
foreach (var child in Children)
|
||||||
|
child.OnParentChanged?.Invoke(transform, previousParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecalculatePosition(ITransform _)
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdatePosition();
|
||||||
|
OnPositionChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecalculateScale(ITransform _)
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateScale();
|
||||||
|
OnScaleChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RecalculateRotation(ITransform _)
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdatePosition();
|
||||||
|
UpdateRotation();
|
||||||
|
OnPositionChanged?.Invoke(this);
|
||||||
|
OnRotationChanged?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLocalPosition()
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
_localPosition = Position;
|
||||||
|
else
|
||||||
|
_localPosition = Parent.Position.FromTo(Position).Scale(Parent.Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLocalScale()
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
_localScale = Scale;
|
||||||
|
else
|
||||||
|
_localScale = Scale.Scale(new(1f / Parent.Scale.X, 1f / Parent.Scale.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLocalRotation()
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
_localRotation = Rotation;
|
||||||
|
else
|
||||||
|
_localRotation = Rotation - Parent.Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePosition()
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
_position = LocalPosition.Scale(Vector2D.One).Rotate(0f * Math.DegreeToRadian);
|
||||||
|
else
|
||||||
|
_position = Parent.Position + LocalPosition.Scale(new(1f / Parent.Scale.X, 1f / Parent.Scale.Y)).Rotate(Parent.Rotation * Math.DegreeToRadian);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateScale()
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
_scale = LocalScale;
|
||||||
|
else
|
||||||
|
_scale = Vector2D.Scale(Parent.Scale, LocalScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRotation()
|
||||||
|
{
|
||||||
|
if (Parent is null)
|
||||||
|
_rotation = LocalRotation;
|
||||||
|
else
|
||||||
|
_rotation = Parent.Rotation + LocalRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Assign(IGameObject gameObject)
|
||||||
|
{
|
||||||
|
if (GameObject is not null && GameObject.Initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GameObject = gameObject;
|
||||||
|
OnGameObjectAssigned?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Unassign()
|
||||||
|
{
|
||||||
|
if (GameObject is not null && GameObject.Initialized)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GameObject = null!;
|
||||||
|
OnUnassigned?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public abstract class Collider2DBehaviourBase : BehaviourOverride, ICollider2D
|
|||||||
|
|
||||||
protected override void OnInitialize()
|
protected override void OnInitialize()
|
||||||
{
|
{
|
||||||
BehaviourController.TryGetBehaviour(out _rigidBody2D);
|
BehaviourController.TryGetBehaviourInParent(out _rigidBody2D);
|
||||||
|
|
||||||
BehaviourController.OnBehaviourAdded += OnBehaviourAddedToController;
|
BehaviourController.OnBehaviourAdded += OnBehaviourAddedToController;
|
||||||
BehaviourController.OnBehaviourRemoved += OnBehaviourRemovedFromController;
|
BehaviourController.OnBehaviourRemoved += OnBehaviourRemovedFromController;
|
||||||
@@ -45,6 +45,12 @@ public abstract class Collider2DBehaviourBase : BehaviourOverride, ICollider2D
|
|||||||
Transform.OnPositionChanged += SetNeedsRecalculation;
|
Transform.OnPositionChanged += SetNeedsRecalculation;
|
||||||
Transform.OnRotationChanged += SetNeedsRecalculation;
|
Transform.OnRotationChanged += SetNeedsRecalculation;
|
||||||
Transform.OnScaleChanged += SetNeedsRecalculation;
|
Transform.OnScaleChanged += SetNeedsRecalculation;
|
||||||
|
Transform.OnParentChanged += UpdateRigidBody2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRigidBody2D(ITransform _1, ITransform? _2)
|
||||||
|
{
|
||||||
|
BehaviourController.TryGetBehaviourInParent(out _rigidBody2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBehaviourAddedToController(IBehaviourController _, IBehaviour behaviour)
|
private void OnBehaviourAddedToController(IBehaviourController _, IBehaviour behaviour)
|
||||||
|
|||||||
@@ -1,13 +1,33 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
using Syntriax.Engine.Physics2D;
|
|
||||||
using Syntriax.Engine.Physics2D.Primitives;
|
using Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
namespace Engine.Physics2D;
|
namespace Engine.Physics2D;
|
||||||
|
|
||||||
public static partial class Physics2D
|
public static partial class Physics2D
|
||||||
{
|
{
|
||||||
|
public static bool Overlaps(this Shape shape, Vector2D point) => Overlaps(shape, point, out var _);
|
||||||
|
public static bool Overlaps(this Shape shape, Vector2D point, out float depth)
|
||||||
|
{
|
||||||
|
depth = float.MaxValue;
|
||||||
|
var vertices = shape.Vertices;
|
||||||
|
int count = vertices.Count;
|
||||||
|
|
||||||
|
for (int indexProjection = 0; indexProjection < count; indexProjection++)
|
||||||
|
{
|
||||||
|
Vector2D projectionVector = vertices[indexProjection].FromTo(vertices[(indexProjection + 1) % count]).Perpendicular().Normalized;
|
||||||
|
|
||||||
|
Projection shapeProjection = shape.ToProjection(projectionVector);
|
||||||
|
float projectedPoint = point.Dot(projectionVector);
|
||||||
|
|
||||||
|
if (shapeProjection.Max < projectedPoint || shapeProjection.Min > projectedPoint)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
depth = Math.Min(depth, Math.Abs(Math.AbsMin(shapeProjection.Max - projectedPoint, shapeProjection.Min - projectedPoint)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool Overlaps(this Circle left, Circle right)
|
public static bool Overlaps(this Circle left, Circle right)
|
||||||
{
|
{
|
||||||
float distanceSquared = left.Center.FromTo(right.Center).LengthSquared();
|
float distanceSquared = left.Center.FromTo(right.Center).LengthSquared();
|
||||||
@@ -27,7 +47,7 @@ public static partial class Physics2D
|
|||||||
normal = distanceVector.Normalized;
|
normal = distanceVector.Normalized;
|
||||||
|
|
||||||
if (isOverlapping)
|
if (isOverlapping)
|
||||||
depth = MathF.Sqrt(radiusSumSquared - distanceSquared);
|
depth = Math.Sqrt(radiusSumSquared - distanceSquared);
|
||||||
|
|
||||||
return isOverlapping;
|
return isOverlapping;
|
||||||
}
|
}
|
||||||
@@ -44,7 +64,7 @@ public static partial class Physics2D
|
|||||||
normal = distanceVector.Normalized;
|
normal = distanceVector.Normalized;
|
||||||
|
|
||||||
if (isOverlapping)
|
if (isOverlapping)
|
||||||
depth = MathF.Sqrt(radiusSquared - distanceSquared);
|
depth = Math.Sqrt(radiusSquared - distanceSquared);
|
||||||
|
|
||||||
return isOverlapping;
|
return isOverlapping;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using Syntriax.Engine.Physics2D.Abstract;
|
|||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
public class PhysicsEngine2DCacher : IPhysicsEngine2D, IAssignableGameManager
|
public class PhysicsEngine2DCollector : IPhysicsEngine2D, IAssignableGameManager
|
||||||
{
|
{
|
||||||
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
public Action<IAssignable>? OnUnassigned { get; set; } = null;
|
||||||
public Action<IAssignableGameManager>? OnGameManagerAssigned { get; set; } = null;
|
public Action<IAssignableGameManager>? OnGameManagerAssigned { get; set; } = null;
|
||||||
@@ -17,8 +17,8 @@ public class PhysicsEngine2DCacher : IPhysicsEngine2D, IAssignableGameManager
|
|||||||
protected readonly ICollisionDetector2D collisionDetector = null!;
|
protected readonly ICollisionDetector2D collisionDetector = null!;
|
||||||
protected readonly ICollisionResolver2D collisionResolver = null!;
|
protected readonly ICollisionResolver2D collisionResolver = null!;
|
||||||
|
|
||||||
protected BehaviourCacher<IRigidBody2D> rigidBodyCacher = new();
|
protected BehaviourCollector<IRigidBody2D> rigidBodyCollector = new();
|
||||||
protected BehaviourCacher<ICollider2D> colliderCacher = new();
|
protected BehaviourCollector<ICollider2D> colliderCollector = new();
|
||||||
|
|
||||||
|
|
||||||
public int IterationPerStep { get => _iterationPerStep; set => _iterationPerStep = value < 1 ? 1 : value; }
|
public int IterationPerStep { get => _iterationPerStep; set => _iterationPerStep = value < 1 ? 1 : value; }
|
||||||
@@ -31,23 +31,23 @@ public class PhysicsEngine2DCacher : IPhysicsEngine2D, IAssignableGameManager
|
|||||||
for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++)
|
for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++)
|
||||||
{
|
{
|
||||||
// Can Parallel
|
// Can Parallel
|
||||||
foreach (var rigidBody in rigidBodyCacher)
|
foreach (var rigidBody in rigidBodyCollector)
|
||||||
StepRigidBody(rigidBody, intervalDeltaTime);
|
StepRigidBody(rigidBody, intervalDeltaTime);
|
||||||
|
|
||||||
// Can Parallel
|
// Can Parallel
|
||||||
foreach (var collider in colliderCacher)
|
foreach (var collider in colliderCollector)
|
||||||
collider.Recalculate();
|
collider.Recalculate();
|
||||||
|
|
||||||
// Can Parallel
|
// Can Parallel
|
||||||
for (int x = 0; x < colliderCacher.Behaviours.Count; x++)
|
for (int x = 0; x < colliderCollector.Behaviours.Count; x++)
|
||||||
{
|
{
|
||||||
ICollider2D? colliderX = colliderCacher.Behaviours[x];
|
ICollider2D? colliderX = colliderCollector.Behaviours[x];
|
||||||
if (!colliderX.IsActive)
|
if (!colliderX.IsActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int y = x + 1; y < colliderCacher.Behaviours.Count; y++)
|
for (int y = x + 1; y < colliderCollector.Behaviours.Count; y++)
|
||||||
{
|
{
|
||||||
ICollider2D? colliderY = colliderCacher.Behaviours[y];
|
ICollider2D? colliderY = colliderCollector.Behaviours[y];
|
||||||
|
|
||||||
if (!colliderY.IsActive)
|
if (!colliderY.IsActive)
|
||||||
return;
|
return;
|
||||||
@@ -100,8 +100,8 @@ public class PhysicsEngine2DCacher : IPhysicsEngine2D, IAssignableGameManager
|
|||||||
if (GameManager is not null)
|
if (GameManager is not null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
colliderCacher.Assign(gameManager);
|
colliderCollector.Assign(gameManager);
|
||||||
rigidBodyCacher.Assign(gameManager);
|
rigidBodyCollector.Assign(gameManager);
|
||||||
|
|
||||||
GameManager = gameManager;
|
GameManager = gameManager;
|
||||||
OnGameManagerAssigned?.Invoke(this);
|
OnGameManagerAssigned?.Invoke(this);
|
||||||
@@ -114,35 +114,35 @@ public class PhysicsEngine2DCacher : IPhysicsEngine2D, IAssignableGameManager
|
|||||||
if (GameManager is null)
|
if (GameManager is null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
colliderCacher.Unassign();
|
colliderCollector.Unassign();
|
||||||
rigidBodyCacher.Unassign();
|
rigidBodyCollector.Unassign();
|
||||||
|
|
||||||
GameManager = null!;
|
GameManager = null!;
|
||||||
OnUnassigned?.Invoke(this);
|
OnUnassigned?.Invoke(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PhysicsEngine2DCacher()
|
public PhysicsEngine2DCollector()
|
||||||
{
|
{
|
||||||
collisionDetector = new CollisionDetector2D();
|
collisionDetector = new CollisionDetector2D();
|
||||||
collisionResolver = new CollisionResolver2D();
|
collisionResolver = new CollisionResolver2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PhysicsEngine2DCacher(IGameManager gameManager)
|
public PhysicsEngine2DCollector(IGameManager gameManager)
|
||||||
{
|
{
|
||||||
Assign(gameManager);
|
Assign(gameManager);
|
||||||
collisionDetector = new CollisionDetector2D();
|
collisionDetector = new CollisionDetector2D();
|
||||||
collisionResolver = new CollisionResolver2D();
|
collisionResolver = new CollisionResolver2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PhysicsEngine2DCacher(IGameManager gameManager, ICollisionDetector2D collisionDetector, ICollisionResolver2D collisionResolver)
|
public PhysicsEngine2DCollector(IGameManager gameManager, ICollisionDetector2D collisionDetector, ICollisionResolver2D collisionResolver)
|
||||||
{
|
{
|
||||||
Assign(gameManager);
|
Assign(gameManager);
|
||||||
this.collisionDetector = collisionDetector;
|
this.collisionDetector = collisionDetector;
|
||||||
this.collisionResolver = collisionResolver;
|
this.collisionResolver = collisionResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PhysicsEngine2DCacher(ICollisionDetector2D collisionDetector, ICollisionResolver2D collisionResolver)
|
public PhysicsEngine2DCollector(ICollisionDetector2D collisionDetector, ICollisionResolver2D collisionResolver)
|
||||||
{
|
{
|
||||||
this.collisionDetector = collisionDetector;
|
this.collisionDetector = collisionDetector;
|
||||||
this.collisionResolver = collisionResolver;
|
this.collisionResolver = collisionResolver;
|
||||||
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Work In Progress
|
||||||
|
|
||||||
|
This engine is still in development but the implemented features include:
|
||||||
|
- Modular Systems
|
||||||
|
- Behaviour System
|
||||||
|
- 2D Physics Engine(**Not Fully Completed, but usable**)
|
||||||
|
- Rigid Body Simulations
|
||||||
|
- Collision Detection (Convex Shape & Circle)
|
||||||
|
- Collision Resolution (**Not Fully Completed**)
|
||||||
|
- Vector2D, AABB, Circle, Line, LineEquation, Projection & Shape Data Types
|
||||||
|
- General Math
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**A detailed README file will be written in the future. If you want to check out how to use this, please checkout this example Pong game made using this engine on top of [MonoGame](https://monogame.net/) from the link bellow.**
|
||||||
|
|
||||||
|
[Pong Source Code](https://git.syntriax.com/Syntriax/Engine-Pong)
|
||||||
Reference in New Issue
Block a user