Compare commits
88 Commits
c135035d5b
...
net8
Author | SHA1 | Date | |
---|---|---|---|
0215f8ef1f | |||
0bf38234c6 | |||
ed6969c16a | |||
b0b421151f | |||
41c5def097 | |||
fbbdfb07fa | |||
bf283d804c | |||
063ea08707 | |||
fd11a94ddf | |||
be2295b92d | |||
a93e55619c | |||
48ae24af47 | |||
1366a417f1 | |||
4bfe98852c | |||
98edbe1af5 | |||
3725a3b0fd | |||
f43ab36742 | |||
c7aafd85bc | |||
5de08b8fe4 | |||
16e4077d40 | |||
fc3c1ed1f9 | |||
b100b5c2fe | |||
5e28ba8814 | |||
4c235e3230 | |||
131203d578 | |||
bd5eb432b7 | |||
d2ca85568f | |||
4c41870732 | |||
f77afa3632 | |||
eb61598489 | |||
efe51b491d | |||
fa3a4d1e0d | |||
6e7a0993f5 | |||
d70bee2c6b | |||
5812f43117 | |||
d102c5471d | |||
fb363970fc | |||
791349686b | |||
3a0942ff46 | |||
b002dd469a | |||
f92f36442c | |||
bb934b59f3 | |||
c704173183 | |||
c3876add1e | |||
35a75d993b | |||
2637f99456 | |||
9581f5aa54 | |||
82cc25a9ef | |||
336e7e16e7 | |||
a3a8fb4e84 | |||
35f6c3850e | |||
f51d5f342e | |||
9c129cefe2 | |||
a254bb721b | |||
5fa7420c04 | |||
5bcc256777 | |||
680d718957 | |||
20bc6a1adb | |||
eb454a471c | |||
c205e710bc | |||
cddb30c631 | |||
29f6c83bf0 | |||
c20f210b29 | |||
1ea1844677 | |||
5b2c13f8bf | |||
c39ee44442 | |||
4623b4861a | |||
0a868b82e5 | |||
d92d16cfad | |||
0184d1758c | |||
6e5b805803 | |||
8293c58f9f | |||
94d01521d4 | |||
5c1c025fe3 | |||
1d292a104e | |||
70c884acfe | |||
a9f5974568 | |||
dae72b11c5 | |||
58eb373c79 | |||
00f7b1aaab | |||
9e4c74ed1d | |||
2e2306c5bb | |||
86b8cd9b55 | |||
bfbcfdce4f | |||
80202d4a07 | |||
2be99d2142 | |||
4081693d32 | |||
193d23c877 |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "Engine.Serializers/YamlDotNet"]
|
||||||
|
path = Engine.Serializers/YamlDotNet
|
||||||
|
url = git@github.com:Syntriax/YamlDotNet.git
|
2
Engine.Core/.gitignore
vendored
2
Engine.Core/.gitignore
vendored
@@ -482,3 +482,5 @@ $RECYCLE.BIN/
|
|||||||
|
|
||||||
# Vim temporary swap files
|
# Vim temporary swap files
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
|
!Debug
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates the class implementing it has Assignable fields that are necessary for the engine to work properly.
|
/// Indicates the class implementing it has Assignable fields that are necessary for the engine to work properly.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IBehaviourController"/> field.
|
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IBehaviourController"/> field.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IEntity"/> field.
|
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IEntity"/> field.
|
||||||
|
@@ -1,26 +0,0 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="ITransform2D"/> field.
|
|
||||||
/// </summary>
|
|
||||||
public interface IHasGameManager : IAssignable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when the <see cref="IGameManager"/> value has has been assigned a new value.
|
|
||||||
/// </summary>
|
|
||||||
event GameManagerAssignedEventHandler? OnGameManagerAssigned;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGameManager" />
|
|
||||||
IGameManager GameManager { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Assign a value to the <see cref="IGameManager"/> field of this object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="gameManager">New <see cref="IGameManager"/> to assign.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see cref="true"/>, if the value given assigned successfully assigned, <see cref="false"/> if not.
|
|
||||||
/// </returns>
|
|
||||||
bool Assign(IGameManager gameManager);
|
|
||||||
|
|
||||||
delegate void GameManagerAssignedEventHandler(IHasGameManager sender);
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IHierarchyObject"/> field.
|
|
||||||
/// </summary>
|
|
||||||
public interface IHasHierarchyObject : IAssignable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when the <see cref="IHierarchyObject"/> value has has been assigned a new value.
|
|
||||||
/// </summary>
|
|
||||||
event HierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IHierarchyObject" />
|
|
||||||
IHierarchyObject HierarchyObject { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Assign a value to the <see cref="IHierarchyObject"/> field of this object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hierarchyObject">New <see cref="IHierarchyObject"/> to assign.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see cref="true"/>, if the value given assigned successfully assigned, <see cref="false"/> if not.
|
|
||||||
/// </returns>
|
|
||||||
bool Assign(IHierarchyObject hierarchyObject);
|
|
||||||
|
|
||||||
delegate void HierarchyObjectAssignedEventHandler(IHasHierarchyObject sender);
|
|
||||||
}
|
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IStateEnable"/> field.
|
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IStateEnable"/> field.
|
||||||
|
26
Engine.Core/Abstract/Assignable/IHasUniverse.cs
Normal file
26
Engine.Core/Abstract/Assignable/IHasUniverse.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IUniverse"/> field.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHasUniverse : IAssignable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the <see cref="IUniverse"/> value has has been assigned a new value.
|
||||||
|
/// </summary>
|
||||||
|
event UniverseAssignedEventHandler? OnUniverseAssigned;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IUniverse" />
|
||||||
|
IUniverse Universe { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assign a value to the <see cref="IUniverse"/> field of this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universe">New <see cref="IUniverse"/> to assign.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see cref="true"/>, if the value given assigned successfully assigned, <see cref="false"/> if not.
|
||||||
|
/// </returns>
|
||||||
|
bool Assign(IUniverse universe);
|
||||||
|
|
||||||
|
delegate void UniverseAssignedEventHandler(IHasUniverse sender);
|
||||||
|
}
|
26
Engine.Core/Abstract/Assignable/IHasUniverseObject.cs
Normal file
26
Engine.Core/Abstract/Assignable/IHasUniverseObject.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IUniverseObject"/> field.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHasUniverseObject : IAssignable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the <see cref="IUniverseObject"/> value has has been assigned a new value.
|
||||||
|
/// </summary>
|
||||||
|
event UniverseObjectAssignedEventHandler? OnUniverseObjectAssigned;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IUniverseObject" />
|
||||||
|
IUniverseObject UniverseObject { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assign a value to the <see cref="IUniverseObject"/> field of this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeObject">New <see cref="IUniverseObject"/> to assign.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see cref="true"/>, if the value given assigned successfully assigned, <see cref="false"/> if not.
|
||||||
|
/// </returns>
|
||||||
|
bool Assign(IUniverseObject universeObject);
|
||||||
|
|
||||||
|
delegate void UniverseObjectAssignedEventHandler(IHasUniverseObject sender);
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entity which can be active or not.
|
/// Represents an entity which can be active or not.
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a behaviour that any object in the game might use to interact with itself or other objects.
|
/// Represents a behaviour that any object in the engine that might use to interact with itself or other objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IBehaviour : IEntity, IActive, IHasBehaviourController, IHasStateEnable
|
public interface IBehaviour : IEntity, IActive, IHasBehaviourController, IHasStateEnable
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public interface IBehaviour2D : IBehaviour
|
public interface IBehaviour2D : IBehaviour
|
||||||
{
|
{
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a collector for the class type of <typeparamref name="T"/>.
|
/// Represents a collector for the class type of <typeparamref name="T"/>.
|
||||||
/// Provides mechanisms for tracking additions and removals, and notifies subscribers when such events occur on the assigned <see cref="IGameManager"/>.
|
/// Provides mechanisms for tracking additions and removals, and notifies subscribers when such events occur on the assigned <see cref="IUniverse"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of objects tracked by the collector.</typeparam>
|
/// <typeparam name="T">The type of objects tracked by the collector.</typeparam>
|
||||||
public interface IBehaviourCollector<T> : IHasGameManager, IEnumerable<T> where T : class
|
public interface IBehaviourCollector<T> : IHasUniverse, IEnumerable<T> where T : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event triggered when an object of type <typeparamref name="T"/> is added to the collector.
|
/// Event triggered when an object of type <typeparamref name="T"/> is added to the collector.
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a controller for managing <see cref="IBehaviour"/>s and notify them accordingly about the engine's updates. Connected to an <see cref="IHierarchyObject"/>.
|
/// Represents a controller for managing <see cref="IBehaviour"/>s and notify them accordingly about the engine's updates. Connected to an <see cref="IUniverseObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IBehaviourController : IInitializable, IHasHierarchyObject, IEnumerable<IBehaviour>
|
public interface IBehaviourController : IEntity, IHasUniverseObject, IEnumerable<IBehaviour>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event triggered before the update of <see cref="IBehaviour"/>s.
|
/// Event triggered before the update of <see cref="IBehaviour"/>s.
|
||||||
@@ -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.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a 2D camera in the engine.
|
/// Represents a 2D camera in the engine.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public interface ICoroutineYield
|
public interface ICoroutineYield
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a basic entity in the engine.
|
/// Represents a basic entity in the engine.
|
||||||
|
@@ -1,81 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a game world responsible for managing <see cref="IHierarchyObject"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public interface IGameManager : IEntity, IEnumerable<IHierarchyObject>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when <see cref="Update(EngineTime)"/> is about to be called called on the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
event UpdateEventHandler? OnPreUpdate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when <see cref="Update(EngineTime)"/> is called on the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
event UpdateEventHandler? OnUpdate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when <see cref="PreDraw"/> is called on the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
event PreDrawEventHandler? OnPreDraw;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when a <see cref="IHierarchyObject"/> is registered to the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
event HierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when a <see cref="IHierarchyObject"/> is unregistered from the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
event HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains time data related to this <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
EngineTime Time { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a read-only list of <see cref="IHierarchyObject"/>s managed by the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
IReadOnlyList<IHierarchyObject> HierarchyObjects { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers an <see cref="IHierarchyObject"/> to the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hierarchyObject">The <see cref="IHierarchyObject"/> to register.</param>
|
|
||||||
void Register(IHierarchyObject hierarchyObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instantiates a <see cref="IHierarchyObject"/> of type T with the given arguments and registers it to the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of <see cref="IHierarchyObject"/> to instantiate.</typeparam>
|
|
||||||
/// <param name="args">Constructor parameters for the given type of <see cref="IHierarchyObject"/>.</param>
|
|
||||||
/// <returns>The instantiated <see cref="IHierarchyObject"/>.</returns>
|
|
||||||
T InstantiateHierarchyObject<T>(params object?[]? args) where T : class, IHierarchyObject;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes an <see cref="IHierarchyObject"/> from the <see cref="IGameManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hierarchyObject">The <see cref="IHierarchyObject"/> to remove.</param>
|
|
||||||
void Remove(IHierarchyObject hierarchyObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the <see cref="IGameManager"/> with the given delta time.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="engineTime">Delta time.</param>
|
|
||||||
void Update(EngineTime engineTime);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs operations that should be done before the draw calls.
|
|
||||||
/// </summary>
|
|
||||||
void PreDraw();
|
|
||||||
|
|
||||||
delegate void UpdateEventHandler(IGameManager sender, EngineTime engineTime);
|
|
||||||
delegate void PreDrawEventHandler(IGameManager sender);
|
|
||||||
|
|
||||||
delegate void HierarchyObjectRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectRegistered);
|
|
||||||
delegate void HierarchyObjectUnRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectUnregistered);
|
|
||||||
}
|
|
@@ -1,131 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an <see cref="IEntity"/> that can enter and exit a hierarchy within the <see cref="IGameManager"/> system.
|
|
||||||
/// This interface allows for tracking the object's presence in the hierarchy and provides events
|
|
||||||
/// for notifying when the see enters or exits the hierarchy.
|
|
||||||
/// </summary>
|
|
||||||
public interface IHierarchyObject : IEntity, IActive, INameable, IHasBehaviourController, IEnumerable<IHierarchyObject>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when the <see cref="IHierarchyObject"/> enters the hierarchy.
|
|
||||||
/// </summary>
|
|
||||||
event EnteredHierarchyEventHandler? OnEnteredHierarchy;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when the <see cref="IHierarchyObject"/> exits the hierarchy.
|
|
||||||
/// </summary>
|
|
||||||
event ExitedHierarchyEventHandler? OnExitedHierarchy;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when the <see cref="Parent"/> of the <see cref="IHierarchyObject"/> changes. The second parameter is the old <see cref="IHierarchyObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
event ParentChangedEventHandler? OnParentChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when a new <see cref="IHierarchyObject"/> is added to the <see cref="Children"/>.
|
|
||||||
/// </summary>
|
|
||||||
event ChildrenAddedEventHandler? OnChildrenAdded;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event triggered when an <see cref="IHierarchyObject"/> is removed from the <see cref="Children"/>.
|
|
||||||
/// </summary>
|
|
||||||
event ChildrenRemovedEventHandler? OnChildrenRemoved;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IGameManager"/> this <see cref="IHierarchyObject"/> is connected to, if any.
|
|
||||||
/// </summary>
|
|
||||||
IGameManager GameManager { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates whether the <see cref="IHierarchyObject"/> is currently in the hierarchy.
|
|
||||||
/// </summary>
|
|
||||||
bool IsInHierarchy { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The parent <see cref="IHierarchyObject"/> of the <see cref="IHierarchyObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
IHierarchyObject? Parent { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="IHierarchyObject"/>s that have this <see cref="IHierarchyObject"/> as their <see cref="Parent"/>.
|
|
||||||
/// </summary>
|
|
||||||
IReadOnlyList<IHierarchyObject> Children { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal method to handle entering the hierarchy.
|
|
||||||
/// This should be called by the system to properly manage hierarchy states.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="gameManager">The <see cref="IGameManager"/> that is managing this hierarchy.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see cref="true"/> if the <see cref="IHierarchyObject"/> successfully entered the hierarchy;
|
|
||||||
/// <see cref="false"/> if it failed to do so.
|
|
||||||
/// </returns>
|
|
||||||
internal bool EnterHierarchy(IGameManager gameManager);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal method to handle exiting the hierarchy.
|
|
||||||
/// This should be called by the system to properly manage hierarchy states.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// <see cref="true"/> if the <see cref="IHierarchyObject"/> successfully exited the hierarchy;
|
|
||||||
/// <see cref="false"/> if it failed to do so.
|
|
||||||
/// </returns>
|
|
||||||
internal bool ExitHierarchy();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the parent <see cref="IHierarchyObject"/> of this <see cref="IHierarchyObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hierarchyObject">The parent <see cref="IHierarchyObject"/> to set.</param>
|
|
||||||
void SetParent(IHierarchyObject? hierarchyObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a child <see cref="IHierarchyObject"/> to this <see cref="IHierarchyObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hierarchyObject">The child <see cref="IHierarchyObject"/> to add.</param>
|
|
||||||
void AddChild(IHierarchyObject hierarchyObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a child <see cref="IHierarchyObject"/> from this <see cref="IHierarchyObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hierarchyObject">The child <see cref="IHierarchyObject"/> to remove.</param>
|
|
||||||
void RemoveChild(IHierarchyObject hierarchyObject);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// EventHandler delegate for the event triggered when the <see cref="IHierarchyObject"/> enters the hierarchy of a <see cref="IGameManager">.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">The <see cref="IHierarchyObject"/> that entered the hierarchy.</param>
|
|
||||||
/// <param name="gameManager">The <see cref="IGameManager"/> that the <see cref="IHierarchyObject"/> has entered it's hierarchy.</param>
|
|
||||||
delegate void EnteredHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// EventHandler delegate for the event triggered when the <see cref="IHierarchyObject"/> exits the hierarchy of a <see cref="IGameManager">.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">The <see cref="IHierarchyObject"/> that exited the hierarchy.</param>
|
|
||||||
/// <param name="gameManager">The <see cref="IGameManager"/> that the <see cref="IHierarchyObject"/> has exited it's hierarchy.</param>
|
|
||||||
delegate void ExitedHierarchyEventHandler(IHierarchyObject sender, IGameManager gameManager);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delegate for the event triggered when the <see cref="IHierarchyObject"/>'s parent changes.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">The <see cref="IHierarchyObject"/> that the parent has changed.</param>
|
|
||||||
/// <param name="previousParent">The previous <see cref="IHierarchyObject"/> the sender was a child of.</param>
|
|
||||||
/// <param name="newParent">The new and current <see cref="IHierarchyObject"/> the sender is a child of.</param>
|
|
||||||
delegate void ParentChangedEventHandler(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delegate for the event triggered when a new <see cref="IHierarchyObject"/> added as a child.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">The parent <see cref="IHierarchyObject"/> this event is being called from.</param>
|
|
||||||
/// <param name="childrenAdded">The <see cref="IHierarchyObject"/> that got removed as a children of the sender <see cref="IHierarchyObject"/>.</param>
|
|
||||||
delegate void ChildrenAddedEventHandler(IHierarchyObject sender, IHierarchyObject childrenAdded);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Delegate for the event triggered when a new <see cref="IHierarchyObject"/> removed from being a child.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">The parent <see cref="IHierarchyObject"/> this event is being called from.</param>
|
|
||||||
/// <param name="childrenAdded">The <see cref="IHierarchyObject"/> that got removed as a children of the sender <see cref="IHierarchyObject"/>.</param>
|
|
||||||
delegate void ChildrenRemovedEventHandler(IHierarchyObject sender, IHierarchyObject childrenRemoved);
|
|
||||||
}
|
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entity that can be initialized and finalized. This information is useful for objects we know that are not in use and can be either recycled or dropped for garbage collection.
|
/// Represents an entity that can be initialized and finalized. This information is useful for objects we know that are not in use and can be either recycled or dropped for garbage collection.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entity with a name.
|
/// Represents an entity with a name.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entity with an enable state that can be toggled.
|
/// Represents an entity with an enable state that can be toggled.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the transformation properties of an object such as position, scale, and rotation in 2D space.
|
/// Represents the transformation properties of an object such as position, scale, and rotation in 2D space.
|
||||||
|
98
Engine.Core/Abstract/IUniverse.cs
Normal file
98
Engine.Core/Abstract/IUniverse.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a universe responsible for managing <see cref="IUniverseObject"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public interface IUniverse : IEntity, IEnumerable<IUniverseObject>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when <see cref="Update(UniverseTime)"/> is about to be called called on the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
event UpdateEventHandler? OnPreUpdate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when <see cref="Update(UniverseTime)"/> is called on the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
event UpdateEventHandler? OnUpdate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when <see cref="PreDraw"/> is called on the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
event PreDrawEventHandler? OnPreDraw;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when a <see cref="IUniverseObject"/> is registered to the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
event UniverseObjectRegisteredEventHandler? OnUniverseObjectRegistered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when a <see cref="IUniverseObject"/> is unregistered from the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
event UniverseObjectUnRegisteredEventHandler? OnUniverseObjectUnRegistered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when <see cref="TimeScale"/> is changed on the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
event TimeScaleChangedEventHandler? OnTimeScaleChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current time scale the <see cref="IUniverse"/> operates on.
|
||||||
|
/// </summary>
|
||||||
|
float TimeScale { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains time data related to this <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
UniverseTime Time { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains unscaled time data related to this <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
UniverseTime UnscaledTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only list of <see cref="IUniverseObject"/>s managed by the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyList<IUniverseObject> UniverseObjects { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers an <see cref="IUniverseObject"/> to the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeObject">The <see cref="IUniverseObject"/> to register.</param>
|
||||||
|
void Register(IUniverseObject universeObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates a <see cref="IUniverseObject"/> of type T with the given arguments and registers it to the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of <see cref="IUniverseObject"/> to instantiate.</typeparam>
|
||||||
|
/// <param name="args">Constructor parameters for the given type of <see cref="IUniverseObject"/>.</param>
|
||||||
|
/// <returns>The instantiated <see cref="IUniverseObject"/>.</returns>
|
||||||
|
T InstantiateUniverseObject<T>(params object?[]? args) where T : class, IUniverseObject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes an <see cref="IUniverseObject"/> from the <see cref="IUniverse"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeObject">The <see cref="IUniverseObject"/> to remove.</param>
|
||||||
|
void Remove(IUniverseObject universeObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the <see cref="IUniverse"/> with the given delta time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeTime">Delta time.</param>
|
||||||
|
void Update(UniverseTime universeTime);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs operations that should be done before the draw calls.
|
||||||
|
/// </summary>
|
||||||
|
void PreDraw();
|
||||||
|
|
||||||
|
delegate void TimeScaleChangedEventHandler(IUniverse sender, float previousTimeScale);
|
||||||
|
|
||||||
|
delegate void UpdateEventHandler(IUniverse sender, UniverseTime engineTime);
|
||||||
|
delegate void PreDrawEventHandler(IUniverse sender);
|
||||||
|
|
||||||
|
delegate void UniverseObjectRegisteredEventHandler(IUniverse sender, IUniverseObject universeObjectRegistered);
|
||||||
|
delegate void UniverseObjectUnRegisteredEventHandler(IUniverse sender, IUniverseObject universeObjectUnregistered);
|
||||||
|
}
|
131
Engine.Core/Abstract/IUniverseObject.cs
Normal file
131
Engine.Core/Abstract/IUniverseObject.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an <see cref="IEntity"/> that can enter and exit a universe within the <see cref="IUniverse"/> system.
|
||||||
|
/// This interface allows for tracking the object's presence in the universe and provides events
|
||||||
|
/// for notifying when the see enters or exits the universe.
|
||||||
|
/// </summary>
|
||||||
|
public interface IUniverseObject : IEntity, IActive, INameable, IHasBehaviourController, IEnumerable<IUniverseObject>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the <see cref="IUniverseObject"/> enters the universe.
|
||||||
|
/// </summary>
|
||||||
|
event EnteredUniverseEventHandler? OnEnteredUniverse;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the <see cref="IUniverseObject"/> exits the universe.
|
||||||
|
/// </summary>
|
||||||
|
event ExitedUniverseEventHandler? OnExitedUniverse;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the <see cref="Parent"/> of the <see cref="IUniverseObject"/> changes. The second parameter is the old <see cref="IUniverseObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
event ParentChangedEventHandler? OnParentChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when a new <see cref="IUniverseObject"/> is added to the <see cref="Children"/>.
|
||||||
|
/// </summary>
|
||||||
|
event ChildrenAddedEventHandler? OnChildrenAdded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when an <see cref="IUniverseObject"/> is removed from the <see cref="Children"/>.
|
||||||
|
/// </summary>
|
||||||
|
event ChildrenRemovedEventHandler? OnChildrenRemoved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IUniverse"/> this <see cref="IUniverseObject"/> is connected to, if any.
|
||||||
|
/// </summary>
|
||||||
|
IUniverse Universe { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the <see cref="IUniverseObject"/> is currently in the universe.
|
||||||
|
/// </summary>
|
||||||
|
bool IsInUniverse { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parent <see cref="IUniverseObject"/> of the <see cref="IUniverseObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
IUniverseObject? Parent { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IUniverseObject"/>s that have this <see cref="IUniverseObject"/> as their <see cref="Parent"/>.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyList<IUniverseObject> Children { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal method to handle entering the universe.
|
||||||
|
/// This should be called by the system to properly manage universe states.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universe">The <see cref="IUniverse"/> that is managing this universe.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <see cref="true"/> if the <see cref="IUniverseObject"/> successfully entered the universe;
|
||||||
|
/// <see cref="false"/> if it failed to do so.
|
||||||
|
/// </returns>
|
||||||
|
internal bool EnterUniverse(IUniverse universe);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal method to handle exiting the universe.
|
||||||
|
/// This should be called by the system to properly manage universe states.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <see cref="true"/> if the <see cref="IUniverseObject"/> successfully exited the universe;
|
||||||
|
/// <see cref="false"/> if it failed to do so.
|
||||||
|
/// </returns>
|
||||||
|
internal bool ExitUniverse();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the parent <see cref="IUniverseObject"/> of this <see cref="IUniverseObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeObject">The parent <see cref="IUniverseObject"/> to set.</param>
|
||||||
|
void SetParent(IUniverseObject? universeObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a child <see cref="IUniverseObject"/> to this <see cref="IUniverseObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeObject">The child <see cref="IUniverseObject"/> to add.</param>
|
||||||
|
void AddChild(IUniverseObject universeObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a child <see cref="IUniverseObject"/> from this <see cref="IUniverseObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="universeObject">The child <see cref="IUniverseObject"/> to remove.</param>
|
||||||
|
void RemoveChild(IUniverseObject universeObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// EventHandler delegate for the event triggered when the <see cref="IUniverseObject"/> enters the universe of a <see cref="IUniverse">.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The <see cref="IUniverseObject"/> that entered the universe.</param>
|
||||||
|
/// <param name="universe">The <see cref="IUniverse"/> that the <see cref="IUniverseObject"/> has entered it's universe.</param>
|
||||||
|
delegate void EnteredUniverseEventHandler(IUniverseObject sender, IUniverse universe);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// EventHandler delegate for the event triggered when the <see cref="IUniverseObject"/> exits the universe of a <see cref="IUniverse">.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The <see cref="IUniverseObject"/> that exited the universe.</param>
|
||||||
|
/// <param name="universe">The <see cref="IUniverse"/> that the <see cref="IUniverseObject"/> has exited it's universe.</param>
|
||||||
|
delegate void ExitedUniverseEventHandler(IUniverseObject sender, IUniverse universe);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for the event triggered when the <see cref="IUniverseObject"/>'s parent changes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The <see cref="IUniverseObject"/> that the parent has changed.</param>
|
||||||
|
/// <param name="previousParent">The previous <see cref="IUniverseObject"/> the sender was a child of.</param>
|
||||||
|
/// <param name="newParent">The new and current <see cref="IUniverseObject"/> the sender is a child of.</param>
|
||||||
|
delegate void ParentChangedEventHandler(IUniverseObject sender, IUniverseObject? previousParent, IUniverseObject? newParent);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for the event triggered when a new <see cref="IUniverseObject"/> added as a child.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The parent <see cref="IUniverseObject"/> this event is being called from.</param>
|
||||||
|
/// <param name="childrenAdded">The <see cref="IUniverseObject"/> that got removed as a children of the sender <see cref="IUniverseObject"/>.</param>
|
||||||
|
delegate void ChildrenAddedEventHandler(IUniverseObject sender, IUniverseObject childrenAdded);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for the event triggered when a new <see cref="IUniverseObject"/> removed from being a child.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The parent <see cref="IUniverseObject"/> this event is being called from.</param>
|
||||||
|
/// <param name="childrenAdded">The <see cref="IUniverseObject"/> that got removed as a children of the sender <see cref="IUniverseObject"/>.</param>
|
||||||
|
delegate void ChildrenRemovedEventHandler(IUniverseObject sender, IUniverseObject childrenRemoved);
|
||||||
|
}
|
@@ -2,14 +2,12 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : class, IBehaviour
|
public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : class, IBehaviour
|
||||||
{
|
{
|
||||||
public event IAssignable.UnassignEventHandler? OnUnassigned = null;
|
public event IAssignable.UnassignEventHandler? OnUnassigned = null;
|
||||||
public event IHasGameManager.GameManagerAssignedEventHandler? OnGameManagerAssigned = null;
|
public event IHasUniverse.UniverseAssignedEventHandler? OnUniverseAssigned = null;
|
||||||
|
|
||||||
public event IBehaviourCollector<T>.CollectedEventHandler? OnCollected = null;
|
public event IBehaviourCollector<T>.CollectedEventHandler? OnCollected = null;
|
||||||
public event IBehaviourCollector<T>.RemovedEventHandler? OnRemoved = null;
|
public event IBehaviourCollector<T>.RemovedEventHandler? OnRemoved = null;
|
||||||
@@ -19,29 +17,29 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
|
|||||||
protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
|
protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
|
||||||
|
|
||||||
public IReadOnlyList<T> Behaviours => activeBehaviours;
|
public IReadOnlyList<T> Behaviours => activeBehaviours;
|
||||||
public IGameManager GameManager { get; private set; } = null!;
|
public IUniverse Universe { get; private set; } = null!;
|
||||||
|
|
||||||
public T this[Index index] => activeBehaviours[index];
|
public T this[Index index] => activeBehaviours[index];
|
||||||
|
|
||||||
public ActiveBehaviourCollector() { }
|
public ActiveBehaviourCollector() { }
|
||||||
public ActiveBehaviourCollector(IGameManager gameManager) => Assign(gameManager);
|
public ActiveBehaviourCollector(IUniverse universe) => Assign(universe);
|
||||||
|
|
||||||
private void OnHierarchyObjectRegistered(IGameManager manager, IHierarchyObject hierarchyObject)
|
private void OnUniverseObjectRegistered(IUniverse manager, IUniverseObject universeObject)
|
||||||
{
|
{
|
||||||
hierarchyObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
|
universeObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
|
||||||
hierarchyObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
|
universeObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
|
||||||
|
|
||||||
foreach (IBehaviour item in hierarchyObject.BehaviourController)
|
foreach (IBehaviour item in universeObject.BehaviourController)
|
||||||
OnBehaviourAdded(hierarchyObject.BehaviourController, item);
|
OnBehaviourAdded(universeObject.BehaviourController, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHierarchyObjectUnregistered(IGameManager manager, IHierarchyObject hierarchyObject)
|
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverseObject universeObject)
|
||||||
{
|
{
|
||||||
hierarchyObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded;
|
universeObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded;
|
||||||
hierarchyObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved;
|
universeObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved;
|
||||||
|
|
||||||
foreach (IBehaviour item in hierarchyObject.BehaviourController)
|
foreach (IBehaviour item in universeObject.BehaviourController)
|
||||||
OnBehaviourRemoved(hierarchyObject.BehaviourController, item);
|
OnBehaviourRemoved(universeObject.BehaviourController, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
|
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
|
||||||
@@ -63,12 +61,12 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
|
|||||||
{
|
{
|
||||||
activeBehaviours.Add(behaviour);
|
activeBehaviours.Add(behaviour);
|
||||||
OnBehaviourAdd(behaviour);
|
OnBehaviourAdd(behaviour);
|
||||||
OnCollected?.Invoke(this, behaviour);
|
OnCollected?.InvokeSafe(this, behaviour);
|
||||||
}
|
}
|
||||||
else if (activeBehaviours.Remove(behaviour))
|
else if (activeBehaviours.Remove(behaviour))
|
||||||
{
|
{
|
||||||
OnBehaviourRemove(behaviour);
|
OnBehaviourRemove(behaviour);
|
||||||
OnRemoved?.Invoke(this, behaviour);
|
OnRemoved?.InvokeSafe(this, behaviour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,40 +83,40 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
|
|||||||
if (activeBehaviours.Remove(tBehaviour))
|
if (activeBehaviours.Remove(tBehaviour))
|
||||||
{
|
{
|
||||||
OnBehaviourRemove(tBehaviour);
|
OnBehaviourRemove(tBehaviour);
|
||||||
OnRemoved?.Invoke(this, tBehaviour);
|
OnRemoved?.InvokeSafe(this, tBehaviour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Assign(IGameManager gameManager)
|
public bool Assign(IUniverse universe)
|
||||||
{
|
{
|
||||||
if (GameManager is not null)
|
if (Universe is not null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (IHierarchyObject hierarchyObject in gameManager.HierarchyObjects)
|
foreach (IUniverseObject universeObject in universe.UniverseObjects)
|
||||||
OnHierarchyObjectRegistered(gameManager, hierarchyObject);
|
OnUniverseObjectRegistered(universe, universeObject);
|
||||||
|
|
||||||
gameManager.OnHierarchyObjectRegistered += OnHierarchyObjectRegistered;
|
universe.OnUniverseObjectRegistered += OnUniverseObjectRegistered;
|
||||||
gameManager.OnHierarchyObjectUnRegistered += OnHierarchyObjectUnregistered;
|
universe.OnUniverseObjectUnRegistered += OnUniverseObjectUnregistered;
|
||||||
|
|
||||||
GameManager = gameManager;
|
Universe = universe;
|
||||||
OnGameManagerAssigned?.Invoke(this);
|
OnUniverseAssigned?.InvokeSafe(this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Unassign()
|
public bool Unassign()
|
||||||
{
|
{
|
||||||
if (GameManager is null)
|
if (Universe is null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (IHierarchyObject hierarchyObject in GameManager.HierarchyObjects)
|
foreach (IUniverseObject universeObject in Universe.UniverseObjects)
|
||||||
OnHierarchyObjectUnregistered(GameManager, hierarchyObject);
|
OnUniverseObjectUnregistered(Universe, universeObject);
|
||||||
|
|
||||||
GameManager.OnHierarchyObjectRegistered -= OnHierarchyObjectRegistered;
|
Universe.OnUniverseObjectRegistered -= OnUniverseObjectRegistered;
|
||||||
GameManager.OnHierarchyObjectUnRegistered -= OnHierarchyObjectUnregistered;
|
Universe.OnUniverseObjectUnRegistered -= OnUniverseObjectUnregistered;
|
||||||
|
|
||||||
GameManager = null!;
|
Universe = null!;
|
||||||
OnUnassigned?.Invoke(this);
|
OnUnassigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
|
public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
|
||||||
@@ -26,5 +24,5 @@ public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> whe
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ActiveBehaviourCollectorSorted() { }
|
public ActiveBehaviourCollectorSorted() { }
|
||||||
public ActiveBehaviourCollectorSorted(IGameManager gameManager, Comparison<T> sortBy) : base(gameManager) => SortBy = sortBy;
|
public ActiveBehaviourCollectorSorted(IUniverse universe, Comparison<T> sortBy) : base(universe) => SortBy = sortBy;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Abstract;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public abstract class BaseEntity : IEntity
|
public abstract class BaseEntity : IEntity
|
||||||
{
|
{
|
||||||
@@ -33,7 +33,7 @@ public abstract class BaseEntity : IEntity
|
|||||||
string previousId = _id;
|
string previousId = _id;
|
||||||
|
|
||||||
_id = value;
|
_id = value;
|
||||||
OnIdChanged?.Invoke(this, previousId);
|
OnIdChanged?.InvokeSafe(this, previousId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,9 +47,9 @@ public abstract class BaseEntity : IEntity
|
|||||||
|
|
||||||
_initialized = value;
|
_initialized = value;
|
||||||
if (value)
|
if (value)
|
||||||
OnInitialized?.Invoke(this);
|
OnInitialized?.InvokeSafe(this);
|
||||||
else
|
else
|
||||||
OnFinalized?.Invoke(this);
|
OnFinalized?.InvokeSafe(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ public abstract class BaseEntity : IEntity
|
|||||||
_stateEnable = stateEnable;
|
_stateEnable = stateEnable;
|
||||||
_stateEnable.Assign(this);
|
_stateEnable.Assign(this);
|
||||||
OnAssign(stateEnable);
|
OnAssign(stateEnable);
|
||||||
OnStateEnableAssigned?.Invoke(this);
|
OnStateEnableAssigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public abstract class BaseEntity : IEntity
|
|||||||
|
|
||||||
_stateEnable = null!;
|
_stateEnable = null!;
|
||||||
_stateEnable.Unassign();
|
_stateEnable.Unassign();
|
||||||
OnUnassigned?.Invoke(this);
|
OnUnassigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,13 +1,11 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public abstract class Behaviour : BehaviourBase
|
public abstract class Behaviour : BehaviourBase
|
||||||
{
|
{
|
||||||
private bool isInitializedThisFrame = false;
|
private bool isInitializedThisFrame = false;
|
||||||
|
|
||||||
protected IGameManager GameManager => BehaviourController.HierarchyObject.GameManager;
|
protected IUniverse Universe => BehaviourController.UniverseObject.Universe;
|
||||||
protected IHierarchyObject HierarchyObject => BehaviourController.HierarchyObject;
|
protected IUniverseObject UniverseObject => BehaviourController.UniverseObject;
|
||||||
|
|
||||||
public Behaviour()
|
public Behaviour()
|
||||||
{
|
{
|
||||||
@@ -27,13 +25,13 @@ public abstract class Behaviour : BehaviourBase
|
|||||||
BehaviourController.OnPreUpdate += PreUpdate;
|
BehaviourController.OnPreUpdate += PreUpdate;
|
||||||
BehaviourController.OnPreDraw += PreDraw;
|
BehaviourController.OnPreDraw += PreDraw;
|
||||||
BehaviourController.OnUpdate += Update;
|
BehaviourController.OnUpdate += Update;
|
||||||
BehaviourController.HierarchyObject.OnEnteredHierarchy += EnteredHierarchy;
|
BehaviourController.UniverseObject.OnEnteredUniverse += EnteredUniverse;
|
||||||
BehaviourController.HierarchyObject.OnExitedHierarchy += ExitedHierarchy;
|
BehaviourController.UniverseObject.OnExitedUniverse += ExitedUniverse;
|
||||||
|
|
||||||
OnInitialize();
|
OnInitialize();
|
||||||
|
|
||||||
if (HierarchyObject.IsInHierarchy)
|
if (UniverseObject.IsInUniverse)
|
||||||
EnteredHierarchy(HierarchyObject, GameManager);
|
EnteredUniverse(UniverseObject, Universe);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnFinalize() { }
|
protected virtual void OnFinalize() { }
|
||||||
@@ -42,19 +40,21 @@ public abstract class Behaviour : BehaviourBase
|
|||||||
BehaviourController.OnPreUpdate -= PreUpdate;
|
BehaviourController.OnPreUpdate -= PreUpdate;
|
||||||
BehaviourController.OnPreDraw -= PreDraw;
|
BehaviourController.OnPreDraw -= PreDraw;
|
||||||
BehaviourController.OnUpdate -= Update;
|
BehaviourController.OnUpdate -= Update;
|
||||||
BehaviourController.HierarchyObject.OnEnteredHierarchy -= EnteredHierarchy;
|
BehaviourController.UniverseObject.OnEnteredUniverse -= EnteredUniverse;
|
||||||
BehaviourController.HierarchyObject.OnExitedHierarchy -= ExitedHierarchy;
|
BehaviourController.UniverseObject.OnExitedUniverse -= ExitedUniverse;
|
||||||
|
|
||||||
OnFinalize();
|
OnFinalize();
|
||||||
|
|
||||||
if (HierarchyObject.IsInHierarchy)
|
if (UniverseObject.IsInUniverse)
|
||||||
ExitedHierarchy(HierarchyObject, GameManager);
|
ExitedUniverse(UniverseObject, Universe);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnPreUpdatePreActiveCheck() { }
|
protected virtual void OnPreUpdatePreActiveCheck() { }
|
||||||
protected virtual void OnPreUpdate() { }
|
protected virtual void OnPreUpdate() { }
|
||||||
protected virtual void PreUpdate(IBehaviourController _)
|
protected virtual void PreUpdate(IBehaviourController _)
|
||||||
{
|
{
|
||||||
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
OnPreUpdatePreActiveCheck();
|
OnPreUpdatePreActiveCheck();
|
||||||
|
|
||||||
if (!IsActive)
|
if (!IsActive)
|
||||||
@@ -77,6 +77,8 @@ public abstract class Behaviour : BehaviourBase
|
|||||||
protected virtual void OnUpdate() { }
|
protected virtual void OnUpdate() { }
|
||||||
protected virtual void Update(IBehaviourController _)
|
protected virtual void Update(IBehaviourController _)
|
||||||
{
|
{
|
||||||
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
OnUpdatePreActiveCheck();
|
OnUpdatePreActiveCheck();
|
||||||
|
|
||||||
if (!IsActive)
|
if (!IsActive)
|
||||||
@@ -89,6 +91,8 @@ public abstract class Behaviour : BehaviourBase
|
|||||||
protected virtual void OnPreDraw() { }
|
protected virtual void OnPreDraw() { }
|
||||||
protected virtual void PreDraw(IBehaviourController _)
|
protected virtual void PreDraw(IBehaviourController _)
|
||||||
{
|
{
|
||||||
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
OnPreDrawPreActiveCheck();
|
OnPreDrawPreActiveCheck();
|
||||||
|
|
||||||
if (!StateEnable.Enabled)
|
if (!StateEnable.Enabled)
|
||||||
@@ -97,9 +101,9 @@ public abstract class Behaviour : BehaviourBase
|
|||||||
OnPreDraw();
|
OnPreDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnEnteredHierarchy(IGameManager gameManager) { }
|
protected virtual void OnEnteredUniverse(IUniverse universe) { }
|
||||||
protected virtual void EnteredHierarchy(IHierarchyObject sender, IGameManager gameManager) => OnEnteredHierarchy(gameManager);
|
protected virtual void EnteredUniverse(IUniverseObject sender, IUniverse universe) => OnEnteredUniverse(universe);
|
||||||
|
|
||||||
protected virtual void OnExitedHierarchy(IGameManager gameManager) { }
|
protected virtual void OnExitedUniverse(IUniverse universe) { }
|
||||||
protected virtual void ExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) => OnExitedHierarchy(gameManager);
|
protected virtual void ExitedUniverse(IUniverseObject sender, IUniverse universe) => OnExitedUniverse(universe);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public abstract class Behaviour2D : Behaviour, IBehaviour2D
|
public abstract class Behaviour2D : Behaviour, IBehaviour2D
|
||||||
@@ -8,7 +6,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(_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +21,6 @@ public abstract class Behaviour2D : Behaviour, IBehaviour2D
|
|||||||
protected sealed override void FirstActiveFrame() => base.FirstActiveFrame();
|
protected sealed override void FirstActiveFrame() => base.FirstActiveFrame();
|
||||||
protected sealed override void Update(IBehaviourController behaviourController) => base.Update(behaviourController);
|
protected sealed override void Update(IBehaviourController behaviourController) => base.Update(behaviourController);
|
||||||
protected sealed override void PreDraw(IBehaviourController behaviourController) => base.PreDraw(behaviourController);
|
protected sealed override void PreDraw(IBehaviourController behaviourController) => base.PreDraw(behaviourController);
|
||||||
protected sealed override void EnteredHierarchy(IHierarchyObject sender, IGameManager gameManager) => base.EnteredHierarchy(sender, gameManager);
|
protected sealed override void EnteredUniverse(IUniverseObject sender, IUniverse universe) => base.EnteredUniverse(sender, universe);
|
||||||
protected sealed override void ExitedHierarchy(IHierarchyObject sender, IGameManager gameManager) => base.ExitedHierarchy(sender, gameManager);
|
protected sealed override void ExitedUniverse(IUniverseObject sender, IUniverse universe) => base.ExitedUniverse(sender, universe);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,3 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
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}")]
|
||||||
@@ -24,7 +21,7 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
|||||||
|
|
||||||
int previousPriority = _priority;
|
int previousPriority = _priority;
|
||||||
_priority = value;
|
_priority = value;
|
||||||
OnPriorityChanged?.Invoke(this, previousPriority);
|
OnPriorityChanged?.InvokeSafe(this, previousPriority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,16 +36,16 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
|||||||
|
|
||||||
_behaviourController = behaviourController;
|
_behaviourController = behaviourController;
|
||||||
OnAssign(behaviourController);
|
OnAssign(behaviourController);
|
||||||
behaviourController.OnHierarchyObjectAssigned += OnHierarchyObjectAssigned;
|
behaviourController.OnUniverseObjectAssigned += OnUniverseObjectAssigned;
|
||||||
if (behaviourController.HierarchyObject is not null)
|
if (behaviourController.UniverseObject is not null)
|
||||||
OnHierarchyObjectAssigned(behaviourController);
|
OnUniverseObjectAssigned(behaviourController);
|
||||||
OnBehaviourControllerAssigned?.Invoke(this);
|
OnBehaviourControllerAssigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHierarchyObjectAssigned(IHasHierarchyObject sender)
|
private void OnUniverseObjectAssigned(IHasUniverseObject sender)
|
||||||
{
|
{
|
||||||
sender.HierarchyObject.OnActiveChanged += OnHierarchyObjectActiveChanged;
|
sender.UniverseObject.OnActiveChanged += OnUniverseObjectActiveChanged;
|
||||||
UpdateActive();
|
UpdateActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,27 +59,26 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
|||||||
protected override void UnassignInternal()
|
protected override void UnassignInternal()
|
||||||
{
|
{
|
||||||
StateEnable.OnEnabledChanged -= OnStateEnabledChanged;
|
StateEnable.OnEnabledChanged -= OnStateEnabledChanged;
|
||||||
BehaviourController.OnHierarchyObjectAssigned -= OnHierarchyObjectAssigned;
|
BehaviourController.OnUniverseObjectAssigned -= OnUniverseObjectAssigned;
|
||||||
base.UnassignInternal();
|
base.UnassignInternal();
|
||||||
_behaviourController = null!;
|
_behaviourController = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void InitializeInternal()
|
protected override void InitializeInternal()
|
||||||
{
|
{
|
||||||
base.InitializeInternal();
|
Debug.Assert.AssertBehaviourControllerAssigned(this);
|
||||||
NotAssignedException.Check(this, _behaviourController);
|
Debug.Assert.AssertStateEnableAssigned(this);
|
||||||
NotAssignedException.Check(this, StateEnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive();
|
private void OnStateEnabledChanged(IStateEnable sender, bool previousState) => UpdateActive();
|
||||||
private void OnHierarchyObjectActiveChanged(IActive sender, bool previousState) => UpdateActive();
|
private void OnUniverseObjectActiveChanged(IActive sender, bool previousState) => UpdateActive();
|
||||||
|
|
||||||
private void UpdateActive()
|
private void UpdateActive()
|
||||||
{
|
{
|
||||||
bool previousActive = IsActive;
|
bool previousActive = IsActive;
|
||||||
_isActive = StateEnable.Enabled && _behaviourController.HierarchyObject.IsActive;
|
_isActive = StateEnable.Enabled && _behaviourController.UniverseObject.IsActive;
|
||||||
|
|
||||||
if (previousActive != IsActive)
|
if (previousActive != IsActive)
|
||||||
OnActiveChanged?.Invoke(this, previousActive);
|
OnActiveChanged?.InvokeSafe(this, previousActive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,14 +2,12 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
|
public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
|
||||||
{
|
{
|
||||||
public event IAssignable.UnassignEventHandler? OnUnassigned = null;
|
public event IAssignable.UnassignEventHandler? OnUnassigned = null;
|
||||||
public event IHasGameManager.GameManagerAssignedEventHandler? OnGameManagerAssigned = null;
|
public event IHasUniverse.UniverseAssignedEventHandler? OnUniverseAssigned = null;
|
||||||
|
|
||||||
public event IBehaviourCollector<T>.CollectedEventHandler? OnCollected = null;
|
public event IBehaviourCollector<T>.CollectedEventHandler? OnCollected = null;
|
||||||
public event IBehaviourCollector<T>.RemovedEventHandler? OnRemoved = null;
|
public event IBehaviourCollector<T>.RemovedEventHandler? OnRemoved = null;
|
||||||
@@ -17,29 +15,29 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
|
|||||||
protected readonly List<T> behaviours = new(32);
|
protected readonly List<T> behaviours = new(32);
|
||||||
|
|
||||||
public IReadOnlyList<T> Behaviours => behaviours;
|
public IReadOnlyList<T> Behaviours => behaviours;
|
||||||
public IGameManager GameManager { get; private set; } = null!;
|
public IUniverse Universe { get; private set; } = null!;
|
||||||
|
|
||||||
public T this[Index index] => behaviours[index];
|
public T this[Index index] => behaviours[index];
|
||||||
|
|
||||||
public BehaviourCollector() { }
|
public BehaviourCollector() { }
|
||||||
public BehaviourCollector(IGameManager gameManager) => Assign(gameManager);
|
public BehaviourCollector(IUniverse universe) => Assign(universe);
|
||||||
|
|
||||||
private void OnHierarchyObjectRegistered(IGameManager manager, IHierarchyObject hierarchyObject)
|
private void OnUniverseObjectRegistered(IUniverse manager, IUniverseObject universeObject)
|
||||||
{
|
{
|
||||||
hierarchyObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
|
universeObject.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
|
||||||
hierarchyObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
|
universeObject.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
|
||||||
|
|
||||||
foreach (IBehaviour item in hierarchyObject.BehaviourController)
|
foreach (IBehaviour item in universeObject.BehaviourController)
|
||||||
OnBehaviourAdded(hierarchyObject.BehaviourController, item);
|
OnBehaviourAdded(universeObject.BehaviourController, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHierarchyObjectUnregistered(IGameManager manager, IHierarchyObject hierarchyObject)
|
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverseObject universeObject)
|
||||||
{
|
{
|
||||||
hierarchyObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded;
|
universeObject.BehaviourController.OnBehaviourAdded -= OnBehaviourAdded;
|
||||||
hierarchyObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved;
|
universeObject.BehaviourController.OnBehaviourRemoved -= OnBehaviourRemoved;
|
||||||
|
|
||||||
foreach (IBehaviour item in hierarchyObject.BehaviourController)
|
foreach (IBehaviour item in universeObject.BehaviourController)
|
||||||
OnBehaviourRemoved(hierarchyObject.BehaviourController, item);
|
OnBehaviourRemoved(universeObject.BehaviourController, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
|
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
|
||||||
@@ -50,7 +48,7 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
|
|||||||
|
|
||||||
behaviours.Add(tBehaviour);
|
behaviours.Add(tBehaviour);
|
||||||
OnBehaviourAdd(behaviour);
|
OnBehaviourAdd(behaviour);
|
||||||
OnCollected?.Invoke(this, tBehaviour);
|
OnCollected?.InvokeSafe(this, tBehaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
|
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
|
||||||
@@ -63,41 +61,41 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
OnBehaviourRemove(behaviour);
|
OnBehaviourRemove(behaviour);
|
||||||
OnRemoved?.Invoke(this, tBehaviour);
|
OnRemoved?.InvokeSafe(this, tBehaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnAssign(IGameManager gameManager) { }
|
protected virtual void OnAssign(IUniverse universe) { }
|
||||||
public bool Assign(IGameManager gameManager)
|
public bool Assign(IUniverse universe)
|
||||||
{
|
{
|
||||||
if (GameManager is not null)
|
if (Universe is not null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (IHierarchyObject hierarchyObject in gameManager.HierarchyObjects)
|
foreach (IUniverseObject universeObject in universe.UniverseObjects)
|
||||||
OnHierarchyObjectRegistered(gameManager, hierarchyObject);
|
OnUniverseObjectRegistered(universe, universeObject);
|
||||||
|
|
||||||
gameManager.OnHierarchyObjectRegistered += OnHierarchyObjectRegistered;
|
universe.OnUniverseObjectRegistered += OnUniverseObjectRegistered;
|
||||||
gameManager.OnHierarchyObjectUnRegistered += OnHierarchyObjectUnregistered;
|
universe.OnUniverseObjectUnRegistered += OnUniverseObjectUnregistered;
|
||||||
|
|
||||||
GameManager = gameManager;
|
Universe = universe;
|
||||||
OnAssign(gameManager);
|
OnAssign(universe);
|
||||||
OnGameManagerAssigned?.Invoke(this);
|
OnUniverseAssigned?.InvokeSafe(this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Unassign()
|
public bool Unassign()
|
||||||
{
|
{
|
||||||
if (GameManager is null)
|
if (Universe is null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (IHierarchyObject hierarchyObject in GameManager.HierarchyObjects)
|
foreach (IUniverseObject universeObject in Universe.UniverseObjects)
|
||||||
OnHierarchyObjectUnregistered(GameManager, hierarchyObject);
|
OnUniverseObjectUnregistered(Universe, universeObject);
|
||||||
|
|
||||||
GameManager.OnHierarchyObjectRegistered -= OnHierarchyObjectRegistered;
|
Universe.OnUniverseObjectRegistered -= OnUniverseObjectRegistered;
|
||||||
GameManager.OnHierarchyObjectUnRegistered -= OnHierarchyObjectUnregistered;
|
Universe.OnUniverseObjectUnRegistered -= OnUniverseObjectUnregistered;
|
||||||
|
|
||||||
GameManager = null!;
|
Universe = null!;
|
||||||
OnUnassigned?.Invoke(this);
|
OnUnassigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
|
public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
|
||||||
@@ -26,5 +24,5 @@ public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BehaviourCollectorSorted() { }
|
public BehaviourCollectorSorted() { }
|
||||||
public BehaviourCollectorSorted(IGameManager gameManager, Comparison<T> sortBy) : base(gameManager) => SortBy = sortBy;
|
public BehaviourCollectorSorted(IUniverse universe, Comparison<T> sortBy) : base(universe) => SortBy = sortBy;
|
||||||
}
|
}
|
||||||
|
@@ -3,13 +3,10 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Core.Exceptions;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")]
|
[System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")]
|
||||||
public class BehaviourController : IBehaviourController
|
public class BehaviourController : BaseEntity, IBehaviourController
|
||||||
{
|
{
|
||||||
public event IBehaviourController.PreUpdateEventHandler? OnPreUpdate = null;
|
public event IBehaviourController.PreUpdateEventHandler? OnPreUpdate = null;
|
||||||
public event IBehaviourController.UpdateEventHandler? OnUpdate = null;
|
public event IBehaviourController.UpdateEventHandler? OnUpdate = null;
|
||||||
@@ -17,51 +14,29 @@ public class BehaviourController : IBehaviourController
|
|||||||
|
|
||||||
public event IBehaviourController.BehaviourAddedEventHandler? OnBehaviourAdded = null;
|
public event IBehaviourController.BehaviourAddedEventHandler? OnBehaviourAdded = null;
|
||||||
public event IBehaviourController.BehaviourRemovedEventHandler? OnBehaviourRemoved = null;
|
public event IBehaviourController.BehaviourRemovedEventHandler? OnBehaviourRemoved = null;
|
||||||
public event IHasHierarchyObject.HierarchyObjectAssignedEventHandler? OnHierarchyObjectAssigned = null;
|
public event IHasUniverseObject.UniverseObjectAssignedEventHandler? OnUniverseObjectAssigned = null;
|
||||||
|
|
||||||
public event IInitializable.InitializedEventHandler? OnInitialized = null;
|
|
||||||
public event IInitializable.FinalizedEventHandler? OnFinalized = null;
|
|
||||||
|
|
||||||
public event IAssignable.UnassignEventHandler? OnUnassigned = null;
|
|
||||||
|
|
||||||
private readonly IList<IBehaviour> behaviours = new List<IBehaviour>(Constants.BEHAVIOURS_SIZE_INITIAL);
|
private readonly IList<IBehaviour> behaviours = new List<IBehaviour>(Constants.BEHAVIOURS_SIZE_INITIAL);
|
||||||
|
|
||||||
private IHierarchyObject _hierarchyObject = null!;
|
private IUniverseObject _universeObject = null!;
|
||||||
private bool _initialized = false;
|
|
||||||
|
|
||||||
public IHierarchyObject HierarchyObject => _hierarchyObject;
|
public IUniverseObject UniverseObject => _universeObject;
|
||||||
|
|
||||||
public bool IsInitialized
|
|
||||||
{
|
|
||||||
get => _initialized;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
if (value == _initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_initialized = value;
|
|
||||||
if (value)
|
|
||||||
OnInitialized?.Invoke(this);
|
|
||||||
else
|
|
||||||
OnFinalized?.Invoke(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T AddBehaviour<T>(T behaviour) where T : class, IBehaviour
|
public T AddBehaviour<T>(T behaviour) where T : class, IBehaviour
|
||||||
{
|
{
|
||||||
InsertBehaviourByPriority(behaviour);
|
InsertBehaviourByPriority(behaviour);
|
||||||
|
|
||||||
behaviour.Assign(this);
|
behaviour.Assign(this);
|
||||||
behaviour.Assign(Factory.StateEnableFactory.Instantiate(behaviour));
|
|
||||||
|
|
||||||
|
if (IsInitialized)
|
||||||
behaviour.Initialize();
|
behaviour.Initialize();
|
||||||
behaviour.OnPriorityChanged += OnPriorityChange;
|
behaviour.OnPriorityChanged += OnPriorityChange;
|
||||||
OnBehaviourAdded?.Invoke(this, behaviour);
|
OnBehaviourAdded?.InvokeSafe(this, behaviour);
|
||||||
return behaviour;
|
return behaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T AddBehaviour<T>(params object?[]? args) where T : class, IBehaviour
|
public T AddBehaviour<T>(params object?[]? args) where T : class, IBehaviour
|
||||||
=> AddBehaviour(Factory.BehaviourFactory.Instantiate<T>(_hierarchyObject, args));
|
=> AddBehaviour(Factory.BehaviourFactory.Instantiate<T>(_universeObject, args));
|
||||||
|
|
||||||
public T? GetBehaviour<T>()
|
public T? GetBehaviour<T>()
|
||||||
{
|
{
|
||||||
@@ -72,7 +47,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)
|
||||||
@@ -116,81 +91,63 @@ public class BehaviourController : IBehaviourController
|
|||||||
public void RemoveBehaviour<T>(T behaviour) where T : class, IBehaviour
|
public void RemoveBehaviour<T>(T behaviour) where T : class, IBehaviour
|
||||||
{
|
{
|
||||||
if (!behaviours.Contains(behaviour))
|
if (!behaviours.Contains(behaviour))
|
||||||
throw new Exception($"{behaviour.GetType().Name} does not exist in {HierarchyObject.Name}'s {nameof(IBehaviourController)}.");
|
throw new Exception($"{behaviour.GetType().Name} does not exist in {UniverseObject.Name}'s {nameof(IBehaviourController)}.");
|
||||||
|
|
||||||
behaviour.OnPriorityChanged -= OnPriorityChange;
|
behaviour.OnPriorityChanged -= OnPriorityChange;
|
||||||
behaviour.Finalize();
|
behaviour.Finalize();
|
||||||
behaviours.Remove(behaviour);
|
behaviours.Remove(behaviour);
|
||||||
OnBehaviourRemoved?.Invoke(this, behaviour);
|
OnBehaviourRemoved?.InvokeSafe(this, behaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnAssign(IHierarchyObject hierarchyObject) { }
|
protected virtual void OnAssign(IUniverseObject universeObject) { }
|
||||||
public bool Assign(IHierarchyObject hierarchyObject)
|
public bool Assign(IUniverseObject universeObject)
|
||||||
{
|
{
|
||||||
if (HierarchyObject is not null && HierarchyObject.IsInitialized)
|
if (UniverseObject is not null && UniverseObject.IsInitialized)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_hierarchyObject = hierarchyObject;
|
_universeObject = universeObject;
|
||||||
OnAssign(hierarchyObject);
|
OnAssign(universeObject);
|
||||||
OnHierarchyObjectAssigned?.Invoke(this);
|
OnUniverseObjectAssigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Initialize()
|
protected override void InitializeInternal()
|
||||||
{
|
{
|
||||||
if (IsInitialized)
|
Debug.Assert.AssertUniverseObjectAssigned(this);
|
||||||
return false;
|
|
||||||
|
|
||||||
NotAssignedException.Check(this, _hierarchyObject);
|
|
||||||
|
|
||||||
foreach (IBehaviour behaviour in behaviours)
|
foreach (IBehaviour behaviour in behaviours)
|
||||||
behaviour.Initialize();
|
behaviour.Initialize();
|
||||||
|
|
||||||
IsInitialized = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Finalize()
|
protected override void FinalizeInternal()
|
||||||
{
|
{
|
||||||
if (!IsInitialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
foreach (IBehaviour behaviour in behaviours)
|
foreach (IBehaviour behaviour in behaviours)
|
||||||
behaviour.Finalize();
|
behaviour.Finalize();
|
||||||
|
|
||||||
IsInitialized = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Unassign()
|
|
||||||
{
|
|
||||||
if (IsInitialized)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_hierarchyObject = null!;
|
|
||||||
OnUnassigned?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
if (!HierarchyObject.StateEnable.Enabled)
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
|
if (!UniverseObject.StateEnable.Enabled || !StateEnable.Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnPreUpdate?.Invoke(this);
|
OnPreUpdate?.InvokeSafe(this);
|
||||||
OnUpdate?.Invoke(this);
|
OnUpdate?.InvokeSafe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdatePreDraw()
|
public void UpdatePreDraw()
|
||||||
{
|
{
|
||||||
if (!HierarchyObject.StateEnable.Enabled)
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
|
if (!UniverseObject.StateEnable.Enabled || !StateEnable.Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnPreDraw?.Invoke(this);
|
OnPreDraw?.InvokeSafe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BehaviourController() { }
|
public BehaviourController() { }
|
||||||
public BehaviourController(IHierarchyObject hierarchyObject) => Assign(hierarchyObject);
|
public BehaviourController(IUniverseObject universeObject) => Assign(universeObject);
|
||||||
|
|
||||||
private void InsertBehaviourByPriority<T>(T behaviour) where T : class, IBehaviour
|
private void InsertBehaviourByPriority<T>(T behaviour) where T : class, IBehaviour
|
||||||
{
|
{
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class CoroutineManager : HierarchyObject
|
public class CoroutineManager : UniverseObject
|
||||||
{
|
{
|
||||||
private readonly List<IEnumerator> enumerators = [];
|
private readonly List<IEnumerator> enumerators = [];
|
||||||
|
|
||||||
@@ -20,17 +18,17 @@ public class CoroutineManager : HierarchyObject
|
|||||||
enumerators.Remove(enumerator);
|
enumerators.Remove(enumerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnEnteringHierarchy(IGameManager gameManager)
|
protected override void OnEnteringUniverse(IUniverse universe)
|
||||||
{
|
{
|
||||||
gameManager.OnUpdate += OnUpdate;
|
universe.OnUpdate += OnUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnExitingHierarchy(IGameManager gameManager)
|
protected override void OnExitingUniverse(IUniverse universe)
|
||||||
{
|
{
|
||||||
gameManager.OnUpdate -= OnUpdate;
|
universe.OnUpdate -= OnUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdate(IGameManager sender, EngineTime time)
|
private void OnUpdate(IUniverse sender, UniverseTime time)
|
||||||
{
|
{
|
||||||
for (int i = enumerators.Count - 1; i >= 0; i--)
|
for (int i = enumerators.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class CoroutineYield(Func<bool> condition) : ICoroutineYield
|
public class CoroutineYield(Func<bool> condition) : ICoroutineYield
|
||||||
|
30
Engine.Core/Debug/AssertHelpers.cs
Normal file
30
Engine.Core/Debug/AssertHelpers.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Debug;
|
||||||
|
|
||||||
|
public static class Assert
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AssertInitialized(IInitializable initializable)
|
||||||
|
=> System.Diagnostics.Debug.Assert(initializable.IsInitialized, $"{initializable.GetType().Name} must be initialized");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AssertBehaviourControllerAssigned(IHasBehaviourController assignable)
|
||||||
|
=> System.Diagnostics.Debug.Assert(assignable.BehaviourController is not null, $"{assignable.GetType().Name} must be initialized");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AssertEntityAssigned(IHasEntity assignable)
|
||||||
|
=> System.Diagnostics.Debug.Assert(assignable.Entity is not null, $"{assignable.GetType().Name} must be initialized");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AssertUniverseAssigned(IHasUniverse assignable)
|
||||||
|
=> System.Diagnostics.Debug.Assert(assignable.Universe is not null, $"{assignable.GetType().Name} must be initialized");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AssertUniverseObjectAssigned(IHasUniverseObject assignable)
|
||||||
|
=> System.Diagnostics.Debug.Assert(assignable.UniverseObject is not null, $"{assignable.GetType().Name} must be initialized");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void AssertStateEnableAssigned(IHasStateEnable assignable)
|
||||||
|
=> System.Diagnostics.Debug.Assert(assignable.StateEnable is not null, $"{assignable.GetType().Name} must be initialized");
|
||||||
|
}
|
8
Engine.Core/Debug/ConsoleLogger.cs
Normal file
8
Engine.Core/Debug/ConsoleLogger.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Debug;
|
||||||
|
|
||||||
|
public class ConsoleLogger : LoggerBase
|
||||||
|
{
|
||||||
|
protected override void Write(string message) => Console.WriteLine(message);
|
||||||
|
}
|
20
Engine.Core/Debug/FileLogger.cs
Normal file
20
Engine.Core/Debug/FileLogger.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Debug;
|
||||||
|
|
||||||
|
public class FileLogger : LoggerBase
|
||||||
|
{
|
||||||
|
public readonly string FilePath;
|
||||||
|
|
||||||
|
public FileLogger(string filePath)
|
||||||
|
{
|
||||||
|
FilePath = filePath;
|
||||||
|
File.Open(filePath, FileMode.Create).Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Write(string message)
|
||||||
|
{
|
||||||
|
File.AppendAllTextAsync(FilePath, $"{message}{Environment.NewLine}");
|
||||||
|
}
|
||||||
|
}
|
15
Engine.Core/Debug/ILogger.cs
Normal file
15
Engine.Core/Debug/ILogger.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Syntriax.Engine.Core.Debug;
|
||||||
|
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
Level FilterLevel { get; set; }
|
||||||
|
|
||||||
|
void Log(string message, Level level = Level.Info, bool force = false);
|
||||||
|
|
||||||
|
enum Level
|
||||||
|
{
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
}
|
20
Engine.Core/Debug/LoggerBase.cs
Normal file
20
Engine.Core/Debug/LoggerBase.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Debug;
|
||||||
|
|
||||||
|
public abstract class LoggerBase : ILogger
|
||||||
|
{
|
||||||
|
public ILogger.Level FilterLevel { get; set; } = ILogger.Level.Info;
|
||||||
|
|
||||||
|
public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
|
||||||
|
{
|
||||||
|
if (!force && level < FilterLevel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string timestamp = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt");
|
||||||
|
|
||||||
|
Write($"[{timestamp}] [{level}] \t{message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void Write(string message);
|
||||||
|
}
|
28
Engine.Core/Debug/LoggerExtensions.cs
Normal file
28
Engine.Core/Debug/LoggerExtensions.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Debug;
|
||||||
|
|
||||||
|
public static class LoggerExtensions
|
||||||
|
{
|
||||||
|
public static void Log<T>(this ILogger logger, T caller, string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
|
||||||
|
{
|
||||||
|
string body = $"{caller?.GetType().Name ?? typeof(T).Name}: {message}";
|
||||||
|
logger.Log(body, level, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogWarning<T>(this ILogger logger, T caller, string message, bool force = false) => Log(logger, caller, message, ILogger.Level.Info, force);
|
||||||
|
|
||||||
|
public static void LogError<T>(this ILogger logger, T caller, string message, bool force = false)
|
||||||
|
{
|
||||||
|
Log(logger, caller, message, ILogger.Level.Error, force);
|
||||||
|
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{new StackTrace()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogException<T>(this ILogger logger, T caller, Exception exception, bool force = false)
|
||||||
|
{
|
||||||
|
Log(logger, caller, $"Message: {exception.Message}", ILogger.Level.Error, force);
|
||||||
|
Log(logger, caller, $"InnerException: {exception.InnerException}", ILogger.Level.Error, force);
|
||||||
|
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{exception.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
@@ -6,41 +6,41 @@ skinparam nodesep 100
|
|||||||
|
|
||||||
title Core Engine Relations
|
title Core Engine Relations
|
||||||
|
|
||||||
interface Engine.Core.Abstract.IEntity extends Engine.Core.Abstract.IInitializable {}
|
interface Engine.Core.IEntity extends Engine.Core.IInitializable {}
|
||||||
interface Engine.Core.Abstract.IHierarchyObject extends Engine.Core.Abstract.IEntity, Engine.Core.Abstract.INameable {}
|
interface Engine.Core.IUniverseObject extends Engine.Core.IEntity, Engine.Core.INameable {}
|
||||||
|
|
||||||
interface Engine.Core.Abstract.INameable {}
|
interface Engine.Core.INameable {}
|
||||||
|
|
||||||
Engine.Core.Abstract.IHierarchyObject --> Engine.Core.Abstract.IBehaviourController: has
|
Engine.Core.IUniverseObject --> Engine.Core.IBehaviourController: has
|
||||||
Engine.Core.Abstract.IBehaviourController "1" --> "0..*" Engine.Core.Abstract.IBehaviour: has
|
Engine.Core.IBehaviourController "1" --> "0..*" Engine.Core.IBehaviour: has
|
||||||
|
|
||||||
interface Engine.Core.Abstract.IBehaviourController {}
|
interface Engine.Core.IBehaviourController {}
|
||||||
interface Engine.Core.Abstract.IBehaviour {}
|
interface Engine.Core.IBehaviour {}
|
||||||
interface Engine.Core.Abstract.IBehaviour2D extends Engine.Core.Abstract.IBehaviour {}
|
interface Engine.Core.IBehaviour2D extends Engine.Core.IBehaviour {}
|
||||||
interface Engine.Core.Abstract.IBehaviour3D extends Engine.Core.Abstract.IBehaviour {}
|
interface Engine.Core.IBehaviour3D extends Engine.Core.IBehaviour {}
|
||||||
|
|
||||||
interface Engine.Core.Abstract.IGameManager {}
|
interface Engine.Core.IUniverse {}
|
||||||
Engine.Core.Abstract.IGameManager "1" -r-> "0..*" Engine.Core.Abstract.IHierarchyObject: has
|
Engine.Core.IUniverse "1" -r-> "0..*" Engine.Core.IUniverseObject: has
|
||||||
|
|
||||||
' together {
|
' together {
|
||||||
' interface Engine.Core.Abstract.IAssignable {}
|
' interface Engine.Core.IAssignable {}
|
||||||
' interface Engine.Core.Abstract.IHasStateEnable extends Engine.Core.Abstract.IAssignable {}
|
' interface Engine.Core.IHasStateEnable extends Engine.Core.IAssignable {}
|
||||||
' interface Engine.Core.Abstract.IHasGameManager extends Engine.Core.Abstract.IAssignable {}
|
' interface Engine.Core.IHasUniverse extends Engine.Core.IAssignable {}
|
||||||
' interface Engine.Core.Abstract.IHasHierarchyObject extends Engine.Core.Abstract.IAssignable {}
|
' interface Engine.Core.IHasUniverseObject extends Engine.Core.IAssignable {}
|
||||||
' interface Engine.Core.Abstract.IHasBehaviourController extends Engine.Core.Abstract.IAssignable {}
|
' interface Engine.Core.IHasBehaviourController extends Engine.Core.IAssignable {}
|
||||||
' ' Engine.Core.Abstract.IHasStateEnable --> Engine.Core.Abstract.IStateEnable: has
|
' ' Engine.Core.IHasStateEnable --> Engine.Core.IStateEnable: has
|
||||||
' ' Engine.Core.Abstract.IHasGameManager --> Engine.Core.Abstract.IGameManager: has
|
' ' Engine.Core.IHasUniverse --> Engine.Core.IUniverse: has
|
||||||
' ' Engine.Core.Abstract.IHasHierarchyObject --> Engine.Core.Abstract.IHierarchyObject: has
|
' ' Engine.Core.IHasUniverseObject --> Engine.Core.IUniverseObject: has
|
||||||
' ' Engine.Core.Abstract.IHasBehaviourController --> Engine.Core.Abstract.IBehaviourController: has
|
' ' Engine.Core.IHasBehaviourController --> Engine.Core.IBehaviourController: has
|
||||||
' }
|
' }
|
||||||
|
|
||||||
together {
|
together {
|
||||||
interface Engine.Core.Abstract.ITransform2D {}
|
interface Engine.Core.ITransform2D {}
|
||||||
interface Engine.Core.Abstract.ICamera2D {}
|
interface Engine.Core.ICamera2D {}
|
||||||
interface Engine.Core.Abstract.ICoroutineYield {}
|
interface Engine.Core.ICoroutineYield {}
|
||||||
interface Engine.Core.Abstract.IStateEnable {}
|
interface Engine.Core.IStateEnable {}
|
||||||
interface Engine.Core.Abstract.IInitializable {}
|
interface Engine.Core.IInitializable {}
|
||||||
interface Engine.Core.Abstract.IBehaviourCollector {}
|
interface Engine.Core.IBehaviourCollector {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
|
@@ -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\""}");
|
|
||||||
}
|
|
9
Engine.Core/Exceptions/AssignFailedException.cs
Normal file
9
Engine.Core/Exceptions/AssignFailedException.cs
Normal 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\""}");
|
||||||
|
}
|
9
Engine.Core/Exceptions/BehaviourNotFoundException.cs
Normal file
9
Engine.Core/Exceptions/BehaviourNotFoundException.cs
Normal 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");
|
||||||
|
}
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
|
public class UniverseObjectNotFoundException(string? message) : Exception(message)
|
||||||
|
{
|
||||||
|
public static NotAssignedException FromType<TUniverseObject>()
|
||||||
|
=> new($"{typeof(TUniverseObject).FullName} was not found");
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
using Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
@@ -19,6 +19,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.UniverseObject.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,12 +39,12 @@ 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="IUniverseObject"/>'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>
|
||||||
/// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
|
/// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
|
||||||
/// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found in the parent hierarchy; otherwise, <see cref="false"/>.</returns>
|
/// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found in the parent universe; otherwise, <see cref="false"/>.</returns>
|
||||||
public static bool TryGetBehaviourInParent<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
public static bool TryGetBehaviourInParent<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
{
|
{
|
||||||
behaviour = GetBehaviourInParent<T>(behaviourController);
|
behaviour = GetBehaviourInParent<T>(behaviourController);
|
||||||
@@ -43,7 +52,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="IUniverseObject"/>'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>
|
||||||
@@ -57,19 +66,28 @@ public static class BehaviourControllerExtensions
|
|||||||
if (controller.GetBehaviour<T>() is T behaviour)
|
if (controller.GetBehaviour<T>() is T behaviour)
|
||||||
return behaviour;
|
return behaviour;
|
||||||
|
|
||||||
controller = controller.HierarchyObject.Parent?.BehaviourController;
|
controller = controller.UniverseObject.Parent?.BehaviourController;
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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="IUniverseObject"/>'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.UniverseObject.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="IUniverseObject"/>'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>
|
||||||
/// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
|
/// <param name="behaviour">When this method returns, contains the <see cref="IBehaviour"/> of the specified type, if found; otherwise, null.</param>
|
||||||
/// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found in the child hierarchy; otherwise, <see cref="false"/>.</returns>
|
/// <returns><see cref="true"/> if a <see cref="IBehaviour"/> of the specified type was found in the child universe; otherwise, <see cref="false"/>.</returns>
|
||||||
public static bool TryGetBehaviourInChildren<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
public static bool TryGetBehaviourInChildren<T>(this IBehaviourController behaviourController, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
{
|
{
|
||||||
behaviour = GetBehaviourInChildren<T>(behaviourController);
|
behaviour = GetBehaviourInChildren<T>(behaviourController);
|
||||||
@@ -77,7 +95,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="IUniverseObject"/>'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>
|
||||||
@@ -87,10 +105,19 @@ public static class BehaviourControllerExtensions
|
|||||||
if (behaviourController.GetBehaviour<T>() is T localBehaviour)
|
if (behaviourController.GetBehaviour<T>() is T localBehaviour)
|
||||||
return localBehaviour;
|
return localBehaviour;
|
||||||
|
|
||||||
foreach (IHierarchyObject child in behaviourController.HierarchyObject)
|
foreach (IUniverseObject child in behaviourController.UniverseObject)
|
||||||
if (GetBehaviourInChildren<T>(child.BehaviourController) is T behaviour)
|
if (GetBehaviourInChildren<T>(child.BehaviourController) is T behaviour)
|
||||||
return behaviour;
|
return behaviour;
|
||||||
|
|
||||||
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.UniverseObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any children ");
|
||||||
}
|
}
|
||||||
|
@@ -1,35 +1,33 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public static class BehaviourExtensions
|
public static class BehaviourExtensions
|
||||||
{
|
{
|
||||||
public static T? FindBehaviour<T>(this IEnumerable<IHierarchyObject> hierarchyObjects) where T : class
|
public static T? FindBehaviour<T>(this IEnumerable<IUniverseObject> universeObjects) where T : class
|
||||||
{
|
{
|
||||||
foreach (IHierarchyObject hierarchyObject in hierarchyObjects)
|
foreach (IUniverseObject universeObject in universeObjects)
|
||||||
if (hierarchyObject.BehaviourController.GetBehaviour<T>() is T behaviour)
|
if (universeObject.BehaviourController.GetBehaviour<T>() is T behaviour)
|
||||||
return behaviour;
|
return behaviour;
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryFindBehaviour<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
public static bool TryFindBehaviour<T>(this IEnumerable<IUniverseObject> universeObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
{
|
{
|
||||||
behaviour = FindBehaviour<T>(hierarchyObjects);
|
behaviour = FindBehaviour<T>(universeObjects);
|
||||||
return behaviour is not null;
|
return behaviour is not null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FindBehaviours<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, List<T> behaviours) where T : class
|
public static void FindBehaviours<T>(this IEnumerable<IUniverseObject> universeObjects, List<T> behaviours) where T : class
|
||||||
{
|
{
|
||||||
behaviours.Clear();
|
behaviours.Clear();
|
||||||
List<T> cache = [];
|
List<T> cache = [];
|
||||||
|
|
||||||
foreach (IHierarchyObject hierarchyObject in hierarchyObjects)
|
foreach (IUniverseObject universeObject in universeObjects)
|
||||||
{
|
{
|
||||||
hierarchyObject.BehaviourController.GetBehaviours(cache);
|
universeObject.BehaviourController.GetBehaviours(cache);
|
||||||
behaviours.AddRange(cache);
|
behaviours.AddRange(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
public static class GameManagerExtensions
|
|
||||||
{
|
|
||||||
public static IHierarchyObject InstantiateHierarchyObject(this IGameManager gameManager, params object?[]? args)
|
|
||||||
=> gameManager.InstantiateHierarchyObject<HierarchyObject>(args);
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
public static class HierarchyObjectExtensions
|
|
||||||
{
|
|
||||||
public static T SetHierarchyObject<T>(this T hierarchyObject, string? name = "", IHierarchyObject? parent = null) where T : IHierarchyObject
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(name))
|
|
||||||
hierarchyObject.Name = name;
|
|
||||||
if (parent is not null)
|
|
||||||
hierarchyObject.SetParent(parent);
|
|
||||||
return hierarchyObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T? FindHierarchyObject<T>(this IEnumerable<IHierarchyObject> hierarchyObjects) where T : class
|
|
||||||
{
|
|
||||||
foreach (IHierarchyObject hierarchyObject in hierarchyObjects)
|
|
||||||
if (hierarchyObject is T @object)
|
|
||||||
return @object;
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryFindHierarchyObject<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
|
||||||
{
|
|
||||||
behaviour = FindHierarchyObject<T>(hierarchyObjects);
|
|
||||||
return behaviour is not null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void FindHierarchyObjects<T>(this IEnumerable<IHierarchyObject> hierarchyObjects, List<T> behaviours) where T : class
|
|
||||||
{
|
|
||||||
behaviours.Clear();
|
|
||||||
foreach (IHierarchyObject hierarchyObject in hierarchyObjects)
|
|
||||||
if (hierarchyObject is T @object)
|
|
||||||
behaviours.Add(@object);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,3 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public static class TransformExtensions
|
public static class TransformExtensions
|
||||||
|
15
Engine.Core/Extensions/UniverseExtensions.cs
Normal file
15
Engine.Core/Extensions/UniverseExtensions.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public static class UniverseExtensions
|
||||||
|
{
|
||||||
|
public static IUniverseObject InstantiateUniverseObject(this IUniverse universe, params object?[]? args)
|
||||||
|
=> universe.InstantiateUniverseObject<UniverseObject>(args);
|
||||||
|
|
||||||
|
public static T GetRequiredUniverseObject<T>(this IUniverse universe) where T : class
|
||||||
|
=> universe.GetUniverseObject<T>() ?? throw new UniverseObjectNotFoundException($"{universe.GetType().FullName}({universe.Id}) does not contain any {nameof(IUniverseObject)} object of type {typeof(T).FullName}");
|
||||||
|
|
||||||
|
public static T FindRequiredBehaviour<T>(this IUniverse universe) where T : class
|
||||||
|
=> universe.FindBehaviour<T>() ?? throw new BehaviourNotFoundException($"{universe.GetType().FullName}({universe.Id}) does not contain any {nameof(IUniverseObject)} with {nameof(IBehaviour)} of type {typeof(T).FullName}");
|
||||||
|
}
|
39
Engine.Core/Extensions/UniverseObjectExtensions.cs
Normal file
39
Engine.Core/Extensions/UniverseObjectExtensions.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public static class UniverseObjectExtensions
|
||||||
|
{
|
||||||
|
public static T SetUniverseObject<T>(this T universeObject, string? name = "", IUniverseObject? parent = null) where T : IUniverseObject
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(name))
|
||||||
|
universeObject.Name = name;
|
||||||
|
if (parent is not null)
|
||||||
|
universeObject.SetParent(parent);
|
||||||
|
return universeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? GetUniverseObject<T>(this IEnumerable<IUniverseObject> universeObjects) where T : class
|
||||||
|
{
|
||||||
|
foreach (IUniverseObject universeObject in universeObjects)
|
||||||
|
if (universeObject is T @object)
|
||||||
|
return @object;
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetUniverseObject<T>(this IEnumerable<IUniverseObject> universeObjects, [NotNullWhen(returnValue: true)] out T? behaviour) where T : class
|
||||||
|
{
|
||||||
|
behaviour = GetUniverseObject<T>(universeObjects);
|
||||||
|
return behaviour is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetUniverseObjects<T>(this IEnumerable<IUniverseObject> universeObjects, List<T> behaviours) where T : class
|
||||||
|
{
|
||||||
|
behaviours.Clear();
|
||||||
|
foreach (IUniverseObject universeObject in universeObjects)
|
||||||
|
if (universeObject is T @object)
|
||||||
|
behaviours.Add(@object);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,23 +1,22 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Core.Exceptions;
|
using Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Factory;
|
namespace Syntriax.Engine.Core.Factory;
|
||||||
|
|
||||||
public class BehaviourControllerFactory
|
public class BehaviourControllerFactory
|
||||||
{
|
{
|
||||||
public static IBehaviourController Instantiate(IHierarchyObject hierarchyObject)
|
public static IBehaviourController Instantiate(IUniverseObject universeObject)
|
||||||
=> Instantiate<BehaviourController>(hierarchyObject);
|
=> Instantiate<BehaviourController>(universeObject);
|
||||||
|
|
||||||
public static T Instantiate<T>(IHierarchyObject hierarchyObject, params object?[]? args)
|
public static T Instantiate<T>(IUniverseObject universeObject, params object?[]? args)
|
||||||
where T : class, IBehaviourController
|
where T : class, IBehaviourController
|
||||||
{
|
{
|
||||||
T behaviourController = TypeFactory.Get<T>(args);
|
T behaviourController = TypeFactory.Get<T>(args);
|
||||||
|
|
||||||
if (!hierarchyObject.Assign(behaviourController))
|
if (!universeObject.Assign(behaviourController))
|
||||||
throw AssignException.From(hierarchyObject, behaviourController);
|
throw AssignFailedException.From(universeObject, behaviourController);
|
||||||
|
|
||||||
if (!behaviourController.Assign(hierarchyObject))
|
if (!behaviourController.Assign(universeObject))
|
||||||
throw AssignException.From(behaviourController, hierarchyObject);
|
throw AssignFailedException.From(behaviourController, universeObject);
|
||||||
|
|
||||||
return behaviourController;
|
return behaviourController;
|
||||||
}
|
}
|
||||||
|
@@ -1,26 +1,25 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Core.Exceptions;
|
using Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Factory;
|
namespace Syntriax.Engine.Core.Factory;
|
||||||
|
|
||||||
public class BehaviourFactory
|
public class BehaviourFactory
|
||||||
{
|
{
|
||||||
public static T Instantiate<T>(IHierarchyObject hierarchyObject, params object?[]? args) where T : class, IBehaviour
|
public static T Instantiate<T>(IUniverseObject universeObject, params object?[]? args) where T : class, IBehaviour
|
||||||
=> Instantiate<T>(hierarchyObject, stateEnable: null, args);
|
=> Instantiate<T>(universeObject, stateEnable: null, args);
|
||||||
|
|
||||||
public static T Instantiate<T>(IHierarchyObject hierarchyObject, IStateEnable? stateEnable, params object?[]? args)
|
public static T Instantiate<T>(IUniverseObject universeObject, IStateEnable? stateEnable, params object?[]? args)
|
||||||
where T : class, IBehaviour
|
where T : class, IBehaviour
|
||||||
{
|
{
|
||||||
T behaviour = TypeFactory.Get<T>(args);
|
T behaviour = TypeFactory.Get<T>(args);
|
||||||
|
|
||||||
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(universeObject.BehaviourController))
|
||||||
throw AssignException.From(behaviour, hierarchyObject.BehaviourController);
|
throw AssignFailedException.From(behaviour, universeObject.BehaviourController);
|
||||||
|
|
||||||
return behaviour;
|
return behaviour;
|
||||||
}
|
}
|
||||||
|
@@ -1,37 +0,0 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Core.Exceptions;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Factory;
|
|
||||||
|
|
||||||
public class HierarchyObjectFactory
|
|
||||||
{
|
|
||||||
public static IHierarchyObject Instantiate() => Instantiate<HierarchyObject>();
|
|
||||||
public static T Instantiate<T>(params object?[]? args) where T : class, IHierarchyObject
|
|
||||||
=> Instantiate<T>(behaviourController: null, stateEnable: null, args);
|
|
||||||
|
|
||||||
public static IHierarchyObject Instantiate(IBehaviourController? behaviourController = null, IStateEnable? stateEnable = null) => Instantiate<HierarchyObject>(behaviourController, stateEnable);
|
|
||||||
public static T Instantiate<T>(
|
|
||||||
IBehaviourController? behaviourController = null,
|
|
||||||
IStateEnable? stateEnable = null,
|
|
||||||
params object?[]? args
|
|
||||||
)
|
|
||||||
where T : class, IHierarchyObject
|
|
||||||
{
|
|
||||||
T hierarchyObject = TypeFactory.Get<T>(args);
|
|
||||||
|
|
||||||
behaviourController ??= TypeFactory.Get<BehaviourController>();
|
|
||||||
stateEnable ??= TypeFactory.Get<StateEnable>();
|
|
||||||
|
|
||||||
if (!behaviourController.Assign(hierarchyObject))
|
|
||||||
throw AssignException.From(behaviourController, hierarchyObject);
|
|
||||||
if (!stateEnable.Assign(hierarchyObject))
|
|
||||||
throw AssignException.From(stateEnable, hierarchyObject);
|
|
||||||
|
|
||||||
if (!hierarchyObject.Assign(behaviourController))
|
|
||||||
throw AssignException.From(hierarchyObject, behaviourController);
|
|
||||||
if (!hierarchyObject.Assign(stateEnable))
|
|
||||||
throw AssignException.From(hierarchyObject, stateEnable);
|
|
||||||
|
|
||||||
return hierarchyObject;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,4 +1,3 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Core.Exceptions;
|
using Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Factory;
|
namespace Syntriax.Engine.Core.Factory;
|
||||||
@@ -12,10 +11,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;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Factory;
|
namespace Syntriax.Engine.Core.Factory;
|
||||||
|
|
||||||
public class TransformFactory
|
public class TransformFactory
|
||||||
|
@@ -1,21 +1,59 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core.Factory;
|
namespace Syntriax.Engine.Core.Factory;
|
||||||
|
|
||||||
public static class TypeFactory
|
public static class TypeFactory
|
||||||
{
|
{
|
||||||
public static T Get<T>(params object?[]? args) where T : class
|
private static readonly ConcurrentDictionary<string, Type> registeredTypes = [];
|
||||||
|
|
||||||
|
public static string GetTypeName(Type type) => type.FullName ?? throw new ArgumentException($"{type.Name} must be a resolvable type");
|
||||||
|
|
||||||
|
public static T Get<T>(params object?[]? args) where T : class => (T)Get(typeof(T), args);
|
||||||
|
public static object Get(string fullName, params object?[]? args) => Get(GetType(fullName), args);
|
||||||
|
public static object Get(Type type, params object?[]? args)
|
||||||
{
|
{
|
||||||
T? result;
|
object? result;
|
||||||
|
|
||||||
if (args is not null && args.Length != 0)
|
if (args is not null && args.Length != 0)
|
||||||
result = Activator.CreateInstance(typeof(T), args) as T;
|
result = Activator.CreateInstance(type, args);
|
||||||
else
|
else
|
||||||
result = Activator.CreateInstance(typeof(T)) as T;
|
result = Activator.CreateInstance(type);
|
||||||
|
|
||||||
if (result is null)
|
if (result is null)
|
||||||
throw new Exception($"{typeof(T).Name} of type {typeof(T).Name} could not be created.");
|
throw new Exception($"Type {type.Name} could not be created.");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Type GetType(string fullName)
|
||||||
|
{
|
||||||
|
if (registeredTypes.TryGetValue(fullName, out Type? result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ReloadTypes();
|
||||||
|
|
||||||
|
if (registeredTypes.TryGetValue(fullName, out Type? reloadedType))
|
||||||
|
return reloadedType;
|
||||||
|
|
||||||
|
throw new Exception($"Type {fullName} could not be found in the current domain.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReloadTypes()
|
||||||
|
{
|
||||||
|
registeredTypes.Clear();
|
||||||
|
|
||||||
|
IEnumerable<Type> domainTypes = AppDomain.CurrentDomain
|
||||||
|
.GetAssemblies()
|
||||||
|
.SelectMany(a => a.GetTypes());
|
||||||
|
|
||||||
|
// TODO: Replace this
|
||||||
|
// There are some system & compiler generated types with duplicated names,
|
||||||
|
// it is ugly it will cause headaches in the future because it will not
|
||||||
|
// throw an error if there's a type with an unintended duplicate name
|
||||||
|
foreach (Type type in domainTypes)
|
||||||
|
registeredTypes.TryAdd(GetTypeName(type), type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
36
Engine.Core/Factory/UniverseObjectFactory.cs
Normal file
36
Engine.Core/Factory/UniverseObjectFactory.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using Syntriax.Engine.Core.Exceptions;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Factory;
|
||||||
|
|
||||||
|
public class UniverseObjectFactory
|
||||||
|
{
|
||||||
|
public static IUniverseObject Instantiate() => Instantiate<UniverseObject>();
|
||||||
|
public static T Instantiate<T>(params object?[]? args) where T : class, IUniverseObject
|
||||||
|
=> Instantiate<T>(behaviourController: null, stateEnable: null, args);
|
||||||
|
|
||||||
|
public static IUniverseObject Instantiate(IBehaviourController? behaviourController = null, IStateEnable? stateEnable = null) => Instantiate<UniverseObject>(behaviourController, stateEnable);
|
||||||
|
public static T Instantiate<T>(
|
||||||
|
IBehaviourController? behaviourController = null,
|
||||||
|
IStateEnable? stateEnable = null,
|
||||||
|
params object?[]? args
|
||||||
|
)
|
||||||
|
where T : class, IUniverseObject
|
||||||
|
{
|
||||||
|
T universeObject = TypeFactory.Get<T>(args);
|
||||||
|
|
||||||
|
behaviourController ??= TypeFactory.Get<BehaviourController>();
|
||||||
|
stateEnable ??= TypeFactory.Get<StateEnable>();
|
||||||
|
|
||||||
|
if (!behaviourController.Assign(universeObject))
|
||||||
|
throw AssignFailedException.From(behaviourController, universeObject);
|
||||||
|
if (!stateEnable.Assign(universeObject))
|
||||||
|
throw AssignFailedException.From(stateEnable, universeObject);
|
||||||
|
|
||||||
|
if (!universeObject.Assign(behaviourController))
|
||||||
|
throw AssignFailedException.From(universeObject, behaviourController);
|
||||||
|
if (!universeObject.Assign(stateEnable))
|
||||||
|
throw AssignFailedException.From(universeObject, stateEnable);
|
||||||
|
|
||||||
|
return universeObject;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,143 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Core.Exceptions;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("HierarchyObject Count: {_hierarchyObjects.Count}")]
|
|
||||||
public class GameManager : BaseEntity, IGameManager
|
|
||||||
{
|
|
||||||
public event IGameManager.UpdateEventHandler? OnPreUpdate = null;
|
|
||||||
public event IGameManager.UpdateEventHandler? OnUpdate = null;
|
|
||||||
public event IGameManager.PreDrawEventHandler? OnPreDraw = null;
|
|
||||||
|
|
||||||
public event IGameManager.HierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered = null;
|
|
||||||
public event IGameManager.HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null;
|
|
||||||
|
|
||||||
private readonly List<IHierarchyObject> _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL);
|
|
||||||
|
|
||||||
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 void Register(IHierarchyObject hierarchyObject)
|
|
||||||
{
|
|
||||||
if (_hierarchyObjects.Contains(hierarchyObject))
|
|
||||||
throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is already registered to the {nameof(GameManager)}.");
|
|
||||||
|
|
||||||
hierarchyObject.OnFinalized += OnHierarchyObjectFinalize;
|
|
||||||
hierarchyObject.OnExitedHierarchy += OnHierarchyObjectExitedHierarchy;
|
|
||||||
|
|
||||||
if (!hierarchyObject.Initialize())
|
|
||||||
throw new Exception($"{hierarchyObject.Name} can't be initialized");
|
|
||||||
|
|
||||||
for (int i = 0; i < hierarchyObject.Children.Count; i++)
|
|
||||||
Register(hierarchyObject.Children[i]);
|
|
||||||
|
|
||||||
_hierarchyObjects.Add(hierarchyObject);
|
|
||||||
|
|
||||||
if (!hierarchyObject.EnterHierarchy(this))
|
|
||||||
throw new Exception($"{hierarchyObject.Name} can't enter the hierarchy");
|
|
||||||
|
|
||||||
OnHierarchyObjectRegistered?.Invoke(this, hierarchyObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T InstantiateHierarchyObject<T>(params object?[]? args) where T : class, IHierarchyObject
|
|
||||||
{
|
|
||||||
T hierarchyObject = Factory.HierarchyObjectFactory.Instantiate<T>(args);
|
|
||||||
Register(hierarchyObject);
|
|
||||||
return hierarchyObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(IHierarchyObject hierarchyObject)
|
|
||||||
{
|
|
||||||
if (!_hierarchyObjects.Contains(hierarchyObject))
|
|
||||||
throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}.");
|
|
||||||
|
|
||||||
hierarchyObject.OnFinalized -= OnHierarchyObjectFinalize;
|
|
||||||
hierarchyObject.OnExitedHierarchy -= OnHierarchyObjectExitedHierarchy;
|
|
||||||
|
|
||||||
for (int i = hierarchyObject.Children.Count - 1; i >= 0; i--)
|
|
||||||
Remove(hierarchyObject.Children[i]);
|
|
||||||
|
|
||||||
_hierarchyObjects.Remove(hierarchyObject);
|
|
||||||
hierarchyObject.SetParent(null);
|
|
||||||
|
|
||||||
if (!hierarchyObject.ExitHierarchy())
|
|
||||||
throw new Exception($"{hierarchyObject.Name} can't exit the hierarchy");
|
|
||||||
|
|
||||||
if (!hierarchyObject.Finalize())
|
|
||||||
throw new Exception($"{hierarchyObject.Name} can't be finalized");
|
|
||||||
|
|
||||||
OnHierarchyObjectUnRegistered?.Invoke(this, hierarchyObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void InitializeInternal()
|
|
||||||
{
|
|
||||||
base.InitializeInternal();
|
|
||||||
NotAssignedException.Check(this, StateEnable);
|
|
||||||
|
|
||||||
foreach (IHierarchyObject hierarchyObject in HierarchyObjects)
|
|
||||||
hierarchyObject.Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FinalizeInternal()
|
|
||||||
{
|
|
||||||
base.FinalizeInternal();
|
|
||||||
for (int i = HierarchyObjects.Count; i >= 0; i--)
|
|
||||||
HierarchyObjects[i].Finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(EngineTime engineTime)
|
|
||||||
{
|
|
||||||
Time = engineTime;
|
|
||||||
|
|
||||||
OnPreUpdate?.Invoke(this, engineTime);
|
|
||||||
|
|
||||||
for (int i = 0; i < HierarchyObjects.Count; i++)
|
|
||||||
HierarchyObjects[i].BehaviourController.Update();
|
|
||||||
|
|
||||||
OnUpdate?.Invoke(this, engineTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PreDraw()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < HierarchyObjects.Count; i++)
|
|
||||||
HierarchyObjects[i].BehaviourController.UpdatePreDraw();
|
|
||||||
|
|
||||||
OnPreDraw?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHierarchyObjectFinalize(IInitializable initializable)
|
|
||||||
{
|
|
||||||
if (initializable is IHierarchyObject hierarchyObject)
|
|
||||||
Remove(hierarchyObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHierarchyObjectExitedHierarchy(IHierarchyObject sender, IGameManager gameManager)
|
|
||||||
{
|
|
||||||
if (sender is IHierarchyObject hierarchyObject)
|
|
||||||
Remove(hierarchyObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<IHierarchyObject> GetEnumerator() => _hierarchyObjects.GetEnumerator();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _hierarchyObjects.GetEnumerator();
|
|
||||||
}
|
|
17
Engine.Core/Helpers/DelegateExtensions.cs
Normal file
17
Engine.Core/Helpers/DelegateExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public static class DelegateExtensions
|
||||||
|
{
|
||||||
|
public static void InvokeSafe(this Delegate @delegate, params object?[] args)
|
||||||
|
{
|
||||||
|
foreach (Delegate invocation in @delegate.GetInvocationList())
|
||||||
|
try { invocation.DynamicInvoke(args); }
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
string methodCallRepresentation = $"{invocation.Method.DeclaringType?.FullName}.{invocation.Method.Name}({string.Join(", ", args)})";
|
||||||
|
Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Engine.Core/Helpers/Progression/IProgressionTracker.cs
Normal file
7
Engine.Core/Helpers/Progression/IProgressionTracker.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public interface IProgressionTracker : IReadOnlyProgressionTracker
|
||||||
|
{
|
||||||
|
void Set(float progression, string status);
|
||||||
|
void Reset();
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public interface IReadOnlyProgressionTracker
|
||||||
|
{
|
||||||
|
event ProgressionUpdatedEventHandler? OnUpdated;
|
||||||
|
event ProgressionEndedEventHandler? OnEnded;
|
||||||
|
|
||||||
|
float Progression { get; }
|
||||||
|
string Status { get; }
|
||||||
|
|
||||||
|
delegate void ProgressionUpdatedEventHandler(IReadOnlyProgressionTracker sender, float previousProgression, string previousStatus);
|
||||||
|
delegate void ProgressionEndedEventHandler(IReadOnlyProgressionTracker sender);
|
||||||
|
}
|
36
Engine.Core/Helpers/Progression/ProgressionTracker.cs
Normal file
36
Engine.Core/Helpers/Progression/ProgressionTracker.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public class ProgressionTracker : IProgressionTracker
|
||||||
|
{
|
||||||
|
public event IReadOnlyProgressionTracker.ProgressionUpdatedEventHandler? OnUpdated = null;
|
||||||
|
public event IReadOnlyProgressionTracker.ProgressionEndedEventHandler? OnEnded = null;
|
||||||
|
|
||||||
|
public float Progression { get; private set; } = 0f;
|
||||||
|
public string Status { get; private set; } = "Default";
|
||||||
|
|
||||||
|
void IProgressionTracker.Set(float progression, string status)
|
||||||
|
{
|
||||||
|
if (Progression >= 1f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float previousProgression = Progression;
|
||||||
|
string previousStatus = Status;
|
||||||
|
|
||||||
|
Progression = progression.Clamp(Progression, 1f);
|
||||||
|
Status = status;
|
||||||
|
|
||||||
|
OnUpdated?.InvokeSafe(this, previousProgression, previousStatus);
|
||||||
|
|
||||||
|
if (progression >= 1f)
|
||||||
|
OnEnded?.InvokeSafe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IProgressionTracker.Reset()
|
||||||
|
{
|
||||||
|
Progression = 0f;
|
||||||
|
Status = "Default";
|
||||||
|
|
||||||
|
OnUpdated = null;
|
||||||
|
OnEnded = null;
|
||||||
|
}
|
||||||
|
}
|
9
Engine.Core/Helpers/Progression/ProgressiveTask.cs
Normal file
9
Engine.Core/Helpers/Progression/ProgressiveTask.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
public record struct ProgressiveTask<T>(IReadOnlyProgressionTracker ProgressionTracker, Task<T> Task)
|
||||||
|
{
|
||||||
|
public static implicit operator (IReadOnlyProgressionTracker progressionTracker, Task<T> task)(ProgressiveTask<T> value) => (value.ProgressionTracker, value.Task);
|
||||||
|
public static implicit operator ProgressiveTask<T>((IReadOnlyProgressionTracker progressionTracker, Task<T> task) value) => new(value.progressionTracker, value.task);
|
||||||
|
}
|
@@ -30,6 +30,64 @@ public static class Math
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const float DegreeToRadian = PI / 180f;
|
public const float DegreeToRadian = PI / 180f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets one minus of given <see cref="T"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value <see cref="T"/>.</param>
|
||||||
|
/// <returns>One minus of given <see cref="T"/>.</returns>
|
||||||
|
public static T OneMinus<T>(T value) where T : INumber<T> => T.One - value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds two <see cref="T"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first <see cref="T"/>.</param>
|
||||||
|
/// <param name="value">The second <see cref="T"/>.</param>
|
||||||
|
/// <returns>The sum of the two <see cref="T"/>s.</returns>
|
||||||
|
public static T Add<T>(T left, T value) where T : INumber<T> => left + value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts one <see cref="T"/> from another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The <see cref="T"/> to subtract from.</param>
|
||||||
|
/// <param name="value">The <see cref="T"/> to subtract.</param>
|
||||||
|
/// <returns>The result of subtracting the second <see cref="T"/> from the first.</returns>
|
||||||
|
public static T Subtract<T>(T left, T value) where T : INumber<T> => left - value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies a <see cref="T"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The <see cref="T"/>.</param>
|
||||||
|
/// <param name="multiplier">The scalar value.</param>
|
||||||
|
/// <returns>The result of multiplying the <see cref="T"/> by the scalar value.</returns>
|
||||||
|
public static T Multiply<T>(T left, T multiplier) where T : INumber<T> => left * multiplier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides a <see cref="T"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The <see cref="T"/>.</param>
|
||||||
|
/// <param name="divider">The scalar value.</param>
|
||||||
|
/// <returns>The result of dividing the <see cref="T"/> by the scalar value.</returns>
|
||||||
|
public static T Divide<T>(T left, T divider) where T : INumber<T> => left / divider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the true mathematical modulus of a <see cref="T"/> value.
|
||||||
|
/// Unlike the remainder operator (%), this result is always non-negative,
|
||||||
|
/// even when the <paramref name="value"/> operand is negative.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">A numeric type that implements <see cref="INumber{T}"/>.</typeparam>
|
||||||
|
/// <param name="value">The dividend <see cref="T"/> value.</param>
|
||||||
|
/// <param name="modulus">The modulus <see cref="T"/> value (must be non-zero).</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The non-negative remainder of <paramref name="value"/> divided by <paramref name="modulus"/>.
|
||||||
|
/// </returns>
|
||||||
|
public static T Mod<T>(T value, T modulus) where T : INumber<T>
|
||||||
|
{
|
||||||
|
T result = value % modulus;
|
||||||
|
if (result < T.Zero)
|
||||||
|
result += modulus;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the absolute value of a number.
|
/// Returns the absolute value of a number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -190,6 +248,15 @@ public static class Math
|
|||||||
/// <returns>The number <paramref name="x"/> rounded to <paramref name="digits"/> fractional digits.</returns>
|
/// <returns>The number <paramref name="x"/> rounded to <paramref name="digits"/> fractional digits.</returns>
|
||||||
public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
|
public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rounds a number to an integer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The number to round.</param>
|
||||||
|
/// <param name="roundMode">Specification for how to round <paramref name="x"/> if it's midway between two numbers</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil) => (int)MathF.Round(x, 0, roundMode == RoundMode.Ceil ? MidpointRounding.ToPositiveInfinity : MidpointRounding.ToNegativeInfinity);
|
||||||
|
public enum RoundMode { Ceil, Floor };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the square of a number.
|
/// Returns the square of a number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -5,6 +5,24 @@ namespace Syntriax.Engine.Core;
|
|||||||
|
|
||||||
public static class MathExtensions
|
public static class MathExtensions
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc cref="Math.OneMinus{T}(T)" />
|
||||||
|
public static T OneMinus<T>(this T value) where T : INumber<T> => Math.OneMinus(value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Math.Add{T}(T, T)" />
|
||||||
|
public static T Add<T>(this T left, T value) where T : INumber<T> => Math.Add(left, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Math.Subtract{T}(T, T)" />
|
||||||
|
public static T Subtract<T>(this T left, T value) where T : INumber<T> => Math.Subtract(left, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Math.Multiply{T}(T, T)" />
|
||||||
|
public static T Multiply<T>(this T left, T multiplier) where T : INumber<T> => Math.Multiply(left, multiplier);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Math.Divide{T}(T, T)" />
|
||||||
|
public static T Divide<T>(this T left, T divider) where T : INumber<T> => Math.Divide(left, divider);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Math.Mod{T}(T, T)" />
|
||||||
|
public static T Mod<T>(this T value, T modulus) where T : INumber<T> => Math.Mod(value, modulus);
|
||||||
|
|
||||||
/// <inheritdoc cref="Math.Abs{T}(T)" />
|
/// <inheritdoc cref="Math.Abs{T}(T)" />
|
||||||
public static T Abs<T>(this T x) where T : INumber<T> => Math.Abs(x);
|
public static T Abs<T>(this T x) where T : INumber<T> => Math.Abs(x);
|
||||||
|
|
||||||
@@ -65,6 +83,9 @@ public static class MathExtensions
|
|||||||
/// <inheritdoc cref="Math.Round(float, int, MidpointRounding)" />
|
/// <inheritdoc cref="Math.Round(float, int, MidpointRounding)" />
|
||||||
public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, mode);
|
public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, mode);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="Math.RoundToInt(float, Math.RoundMode)" />
|
||||||
|
public static int RoundToInt(this float x, Math.RoundMode roundMode = Math.RoundMode.Ceil) => Math.RoundToInt(x, roundMode);
|
||||||
|
|
||||||
/// <inheritdoc cref="Math.Sqr{T}(T)" />
|
/// <inheritdoc cref="Math.Sqr{T}(T)" />
|
||||||
public static T Sqr<T>(this T x) where T : INumber<T> => Math.Sqr(x);
|
public static T Sqr<T>(this T x) where T : INumber<T> => Math.Sqr(x);
|
||||||
|
|
||||||
|
10
Engine.Core/Preserver.cs
Normal file
10
Engine.Core/Preserver.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Syntriax.Engine.Core
|
||||||
|
{
|
||||||
|
// This is pretty much so the assembly gets loaded automatically because
|
||||||
|
// the builds include the assembly but sometimes doesn't link load it at startup.
|
||||||
|
// I will hopefully one day fix it and remove this.
|
||||||
|
public static class Preserver
|
||||||
|
{
|
||||||
|
public static void Preserve() { }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,5 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
185
Engine.Core/Primitives/ColorHSV.cs
Normal file
185
Engine.Core/Primitives/ColorHSV.cs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an HSV color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hue">Hue of the <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="saturation">Saturation of the <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="value">Value of the <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorHSV"/> struct with the specified values.
|
||||||
|
/// </remarks>
|
||||||
|
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||||
|
public readonly struct ColorHSV(float hue, float saturation, float value)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Hue value of the <see cref="ColorHSV"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float Hue = hue.Clamp(0f, 1f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Saturation value of the <see cref="ColorHSV"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float Saturation = saturation.Clamp(0f, 1f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Value value of the <see cref="ColorHSV"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float Value = value.Clamp(0f, 1f);
|
||||||
|
|
||||||
|
public static ColorHSV operator -(ColorHSV color) => new(color.Hue.OneMinus().Clamp(0f, 1f), color.Saturation.OneMinus().Clamp(0f, 1f), color.Value.OneMinus().Clamp(0f, 1f));
|
||||||
|
public static ColorHSV operator +(ColorHSV left, ColorHSV right) => new((left.Hue + right.Hue).Clamp(0f, 1f), (left.Saturation + right.Saturation).Clamp(0f, 1f), (left.Value + right.Value).Clamp(0f, 1f));
|
||||||
|
public static ColorHSV operator -(ColorHSV left, ColorHSV right) => new((left.Hue - right.Hue).Clamp(0f, 1f), (left.Saturation - right.Saturation).Clamp(0f, 1f), (left.Value - right.Value).Clamp(0f, 1f));
|
||||||
|
public static ColorHSV operator *(ColorHSV left, ColorHSV right) => new((left.Hue * right.Hue).Clamp(0f, 1f), (left.Saturation * right.Saturation).Clamp(0f, 1f), (left.Value * right.Value).Clamp(0f, 1f));
|
||||||
|
public static ColorHSV operator *(ColorHSV color, float value) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
|
||||||
|
public static ColorHSV operator *(float value, ColorHSV color) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
|
||||||
|
public static ColorHSV operator /(ColorHSV color, float value) => new((color.Hue / value).Clamp(0f, 1f), (color.Saturation / value).Clamp(0f, 1f), (color.Value / value).Clamp(0f, 1f));
|
||||||
|
public static bool operator ==(ColorHSV left, ColorHSV right) => left.Hue.ApproximatelyEquals(right.Hue) && left.Saturation.ApproximatelyEquals(right.Saturation) && left.Value.ApproximatelyEquals(right.Value);
|
||||||
|
public static bool operator !=(ColorHSV left, ColorHSV right) => !left.Hue.ApproximatelyEquals(right.Hue) || !left.Saturation.ApproximatelyEquals(right.Saturation) || !left.Value.ApproximatelyEquals(right.Value);
|
||||||
|
|
||||||
|
public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorRGB)rgba;
|
||||||
|
public static implicit operator ColorHSV(ColorRGB rgb)
|
||||||
|
{
|
||||||
|
float hue;
|
||||||
|
float saturation;
|
||||||
|
float value;
|
||||||
|
|
||||||
|
float rd = rgb.R / 255f;
|
||||||
|
float gd = rgb.G / 255f;
|
||||||
|
float bd = rgb.B / 255f;
|
||||||
|
|
||||||
|
float max = Math.Max(rd, Math.Max(gd, bd));
|
||||||
|
float min = Math.Min(rd, Math.Min(gd, bd));
|
||||||
|
float delta = max - min;
|
||||||
|
|
||||||
|
if (delta.ApproximatelyEquals(0))
|
||||||
|
hue = 0f;
|
||||||
|
else if (max.ApproximatelyEquals(rd))
|
||||||
|
hue = 60f * ((gd - bd) / delta % 6f);
|
||||||
|
else if (max.ApproximatelyEquals(gd))
|
||||||
|
hue = 60f * (((bd - rd) / delta) + 2f);
|
||||||
|
else
|
||||||
|
hue = 60f * (((rd - gd) / delta) + 4f);
|
||||||
|
|
||||||
|
if (hue < 0f)
|
||||||
|
hue += 360f;
|
||||||
|
|
||||||
|
hue /= 360f;
|
||||||
|
saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
|
||||||
|
value = max;
|
||||||
|
|
||||||
|
return new(hue, saturation, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inverts the given <see cref="ColorHSV"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <returns>The inverted <see cref="ColorHSV"/>.</returns>
|
||||||
|
public static ColorHSV Invert(ColorHSV color) => -color;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds two <see cref="ColorHSV"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="right">The second <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <returns>The sum of the two <see cref="ColorHSV"/>s.</returns>
|
||||||
|
public static ColorHSV Add(ColorHSV left, ColorHSV right) => left + right;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts one <see cref="ColorHSV"/> from another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The <see cref="ColorHSV"/> to subtract from.</param>
|
||||||
|
/// <param name="right">The <see cref="ColorHSV"/> to subtract.</param>
|
||||||
|
/// <returns>The result of subtracting the second <see cref="ColorHSV"/> from the first.</returns>
|
||||||
|
public static ColorHSV Subtract(ColorHSV left, ColorHSV right) => left - right;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies a <see cref="ColorHSV"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="value">The scalar value.</param>
|
||||||
|
/// <returns>The result of multiplying the <see cref="ColorHSV"/> by the scalar value.</returns>
|
||||||
|
public static ColorHSV Multiply(ColorHSV color, float value) => color * value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides a <see cref="ColorHSV"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="value">The scalar value.</param>
|
||||||
|
/// <returns>The result of dividing the <see cref="ColorHSV"/> by the scalar value.</returns>
|
||||||
|
public static ColorHSV Divide(ColorHSV color, float value) => color / value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the <see cref="ColorHSV"/> from one point to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">The starting point.</param>
|
||||||
|
/// <param name="to">The ending point.</param>
|
||||||
|
/// <returns>The <see cref="ColorHSV"/> from the starting point to the ending point.</returns>
|
||||||
|
public static ColorHSV FromTo(ColorHSV from, ColorHSV to) => to - from;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs linear interpolation between two <see cref="ColorHSV"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">The starting <see cref="ColorHSV"/> (t = 0).</param>
|
||||||
|
/// <param name="to">The ending <see cref="ColorHSV"/> (t = 1).</param>
|
||||||
|
/// <param name="t">The interpolation parameter.</param>
|
||||||
|
/// <returns>The interpolated <see cref="ColorHSV"/>.</returns>
|
||||||
|
public static ColorHSV Lerp(ColorHSV from, ColorHSV to, float t) => from + FromTo(from, to) * t;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the <see cref="ColorHSV"/> to its string representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string representation of the <see cref="ColorHSV"/>.</returns>
|
||||||
|
public override string ToString() => $"{nameof(ColorHSV)}({Hue}, {Saturation}, {Value})";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if two <see cref="ColorHSV"/>s are approximately equal within a specified epsilon range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="right">The second <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <param name="epsilon">The epsilon range.</param>
|
||||||
|
/// <returns><see cref="true"/> if the <see cref="ColorHSV"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||||
|
public static bool ApproximatelyEquals(ColorHSV left, ColorHSV right, float epsilon = float.Epsilon)
|
||||||
|
=> left.Hue.ApproximatelyEquals(right.Hue, epsilon) && left.Saturation.ApproximatelyEquals(right.Saturation, epsilon) && left.Value.ApproximatelyEquals(right.Value, epsilon);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified object is equal to the current <see cref="ColorHSV"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to compare with the current <see cref="ColorHSV"/>.</param>
|
||||||
|
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSV"/>; otherwise, <see cref="false"/>.</returns>
|
||||||
|
public override bool Equals(object? obj) => obj is ColorHSV objVec && Hue.Equals(objVec.Hue) && Saturation.Equals(objVec.Saturation) && Value.Equals(objVec.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a hash code for the <see cref="ColorHSV"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A hash code for the <see cref="ColorHSV"/>.</returns>
|
||||||
|
public override int GetHashCode() => System.HashCode.Combine(Hue, Saturation, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for <see cref="ColorHSV"/> type.
|
||||||
|
/// </summary>
|
||||||
|
public static class ColorHSVExtensions
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="ColorHSV.Add(ColorHSV, ColorHSV)" />
|
||||||
|
public static ColorHSV Add(this ColorHSV color, ColorHSV value) => ColorHSV.Add(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorHSV.Subtract(ColorHSV, ColorHSV)" />
|
||||||
|
public static ColorHSV Subtract(this ColorHSV color, ColorHSV value) => ColorHSV.Subtract(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorHSV.Multiply(ColorHSV, ColorHSV)" />
|
||||||
|
public static ColorHSV Multiply(this ColorHSV color, float value) => ColorHSV.Multiply(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorHSV.Divide(ColorHSV, ColorHSV)" />
|
||||||
|
public static ColorHSV Divide(this ColorHSV color, float value) => ColorHSV.Divide(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorHSV.FromTo(ColorHSV, ColorHSV)" />
|
||||||
|
public static ColorHSV FromTo(this ColorHSV from, ColorHSV to) => ColorHSV.FromTo(from, to);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorHSV.Lerp(ColorHSV, ColorHSV, float)" />
|
||||||
|
public static ColorHSV Lerp(this ColorHSV from, ColorHSV to, float t) => ColorHSV.Lerp(from, to, t);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorHSV.ApproximatelyEquals(ColorHSV, ColorHSV, float) " />
|
||||||
|
public static bool ApproximatelyEquals(this ColorHSV left, ColorHSV right, float epsilon = float.Epsilon) => ColorHSV.ApproximatelyEquals(left, right, epsilon);
|
||||||
|
}
|
164
Engine.Core/Primitives/ColorRGB.cs
Normal file
164
Engine.Core/Primitives/ColorRGB.cs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an RGB color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">Red value of the <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <param name="g">Green value of the <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <param name="b">Blue value of the <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorRGB"/> struct with the specified values.
|
||||||
|
/// </remarks>
|
||||||
|
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||||
|
public readonly struct ColorRGB(byte r, byte g, byte b)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Red value of the <see cref="ColorRGB"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte R = r;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Green value of the <see cref="ColorRGB"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte G = g;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Blue value of the <see cref="ColorRGB"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte B = b;
|
||||||
|
|
||||||
|
public static ColorRGB operator -(ColorRGB color) => new((byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B));
|
||||||
|
public static ColorRGB operator +(ColorRGB left, ColorRGB right) => new((byte)(left.R + right.R).Clamp(0, 255), (byte)(left.G + right.G).Clamp(0, 255), (byte)(left.B + right.B).Clamp(0, 255));
|
||||||
|
public static ColorRGB operator -(ColorRGB left, ColorRGB right) => new((byte)(left.R - right.R).Clamp(0, 255), (byte)(left.G - right.G).Clamp(0, 255), (byte)(left.B - right.B).Clamp(0, 255));
|
||||||
|
public static ColorRGB operator *(ColorRGB left, ColorRGB right) => new((byte)(left.R * right.R).Clamp(0, 255), (byte)(left.G * right.G).Clamp(0, 255), (byte)(left.B * right.B).Clamp(0, 255));
|
||||||
|
public static ColorRGB operator *(ColorRGB color, float value) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255));
|
||||||
|
public static ColorRGB operator *(float value, ColorRGB color) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255));
|
||||||
|
public static ColorRGB operator /(ColorRGB color, float value) => new((byte)(color.R / value).Clamp(0, 255), (byte)(color.G / value).Clamp(0, 255), (byte)(color.B / value).Clamp(0, 255));
|
||||||
|
public static bool operator ==(ColorRGB left, ColorRGB right) => left.R == right.R && left.G == right.G && left.B == right.B;
|
||||||
|
public static bool operator !=(ColorRGB left, ColorRGB right) => left.R != right.R || left.G != right.G || left.B != right.B;
|
||||||
|
|
||||||
|
public static implicit operator ColorRGB(ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B);
|
||||||
|
public static implicit operator ColorRGB(ColorHSV hsv)
|
||||||
|
{
|
||||||
|
float hue = hsv.Hue * 360f;
|
||||||
|
float chroma = hsv.Value * hsv.Saturation;
|
||||||
|
float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
|
||||||
|
float m = hsv.Value - chroma;
|
||||||
|
|
||||||
|
float r1 = 0f;
|
||||||
|
float g1 = 0f;
|
||||||
|
float b1 = 0f;
|
||||||
|
|
||||||
|
if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
|
||||||
|
else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
|
||||||
|
else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
|
||||||
|
else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
|
||||||
|
else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
|
||||||
|
else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
|
||||||
|
|
||||||
|
byte r = (byte)Math.RoundToInt((r1 + m) * 255);
|
||||||
|
byte g = (byte)Math.RoundToInt((g1 + m) * 255);
|
||||||
|
byte b = (byte)Math.RoundToInt((b1 + m) * 255);
|
||||||
|
|
||||||
|
return new(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inverts the given <see cref="ColorRGB"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <returns>The inverted <see cref="ColorRGB"/>.</returns>
|
||||||
|
public static ColorRGB Invert(ColorRGB color) => -color;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds two <see cref="ColorRGB"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <param name="right">The second <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <returns>The sum of the two <see cref="ColorRGB"/>s.</returns>
|
||||||
|
public static ColorRGB Add(ColorRGB left, ColorRGB right) => left + right;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts one <see cref="ColorRGB"/> from another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The <see cref="ColorRGB"/> to subtract from.</param>
|
||||||
|
/// <param name="right">The <see cref="ColorRGB"/> to subtract.</param>
|
||||||
|
/// <returns>The result of subtracting the second <see cref="ColorRGB"/> from the first.</returns>
|
||||||
|
public static ColorRGB Subtract(ColorRGB left, ColorRGB right) => left - right;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies a <see cref="ColorRGB"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <param name="value">The scalar value.</param>
|
||||||
|
/// <returns>The result of multiplying the <see cref="ColorRGB"/> by the scalar value.</returns>
|
||||||
|
public static ColorRGB Multiply(ColorRGB color, float value) => color * value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides a <see cref="ColorRGB"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <param name="value">The scalar value.</param>
|
||||||
|
/// <returns>The result of dividing the <see cref="ColorRGB"/> by the scalar value.</returns>
|
||||||
|
public static ColorRGB Divide(ColorRGB color, float value) => color / value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the <see cref="ColorRGB"/> from one point to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">The starting point.</param>
|
||||||
|
/// <param name="to">The ending point.</param>
|
||||||
|
/// <returns>The <see cref="ColorRGB"/> from the starting point to the ending point.</returns>
|
||||||
|
public static ColorRGB FromTo(ColorRGB from, ColorRGB to) => to - from;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs linear interpolation between two <see cref="ColorRGB"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">The starting <see cref="ColorRGB"/> (t = 0).</param>
|
||||||
|
/// <param name="to">The ending <see cref="ColorRGB"/> (t = 1).</param>
|
||||||
|
/// <param name="t">The interpolation parameter.</param>
|
||||||
|
/// <returns>The interpolated <see cref="ColorRGB"/>.</returns>
|
||||||
|
public static ColorRGB Lerp(ColorRGB from, ColorRGB to, float t) => from + FromTo(from, to) * t;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the <see cref="ColorRGB"/> to its string representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string representation of the <see cref="ColorRGB"/>.</returns>
|
||||||
|
public override string ToString() => $"{nameof(ColorRGB)}({R}, {G}, {B})";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified object is equal to the current <see cref="ColorRGB"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to compare with the current <see cref="ColorRGB"/>.</param>
|
||||||
|
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGB"/>; otherwise, <see cref="false"/>.</returns>
|
||||||
|
public override bool Equals(object? obj) => obj is ColorRGB objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a hash code for the <see cref="ColorRGB"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A hash code for the <see cref="ColorRGB"/>.</returns>
|
||||||
|
public override int GetHashCode() => System.HashCode.Combine(R, G, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for <see cref="ColorRGB"/> type.
|
||||||
|
/// </summary>
|
||||||
|
public static class ColorRGBExtensions
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="ColorRGB.Add(ColorRGB, ColorRGB)" />
|
||||||
|
public static ColorRGB Add(this ColorRGB color, ColorRGB value) => ColorRGB.Add(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGB.Subtract(ColorRGB, ColorRGB)" />
|
||||||
|
public static ColorRGB Subtract(this ColorRGB color, ColorRGB value) => ColorRGB.Subtract(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGB.Multiply(ColorRGB, ColorRGB)" />
|
||||||
|
public static ColorRGB Multiply(this ColorRGB color, float value) => ColorRGB.Multiply(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGB.Divide(ColorRGB, ColorRGB)" />
|
||||||
|
public static ColorRGB Divide(this ColorRGB color, float value) => ColorRGB.Divide(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGB.FromTo(ColorRGB, ColorRGB)" />
|
||||||
|
public static ColorRGB FromTo(this ColorRGB from, ColorRGB to) => ColorRGB.FromTo(from, to);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGB.Lerp(ColorRGB, ColorRGB, float)" />
|
||||||
|
public static ColorRGB Lerp(this ColorRGB from, ColorRGB to, float t) => ColorRGB.Lerp(from, to, t);
|
||||||
|
}
|
147
Engine.Core/Primitives/ColorRGBA.cs
Normal file
147
Engine.Core/Primitives/ColorRGBA.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an RGBA color.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">Red value of the <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <param name="g">Green value of the <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <param name="b">Blue value of the <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <param name="a">Alpha value of the <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorRGBA"/> struct with the specified values.
|
||||||
|
/// </remarks>
|
||||||
|
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
|
||||||
|
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Red value of the <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte R = r;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Green value of the <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte G = g;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Blue value of the <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte B = b;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Alpha value of the <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly byte A = a;
|
||||||
|
|
||||||
|
public static ColorRGBA operator -(ColorRGBA color) => new((byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B), color.A);
|
||||||
|
public static ColorRGBA operator +(ColorRGBA left, ColorRGBA right) => new((byte)(left.R + right.R).Clamp(0, 255), (byte)(left.G + right.G).Clamp(0, 255), (byte)(left.B + right.B).Clamp(0, 255), (byte)(left.A + right.A).Clamp(0, 255));
|
||||||
|
public static ColorRGBA operator -(ColorRGBA left, ColorRGBA right) => new((byte)(left.R - right.R).Clamp(0, 255), (byte)(left.G - right.G).Clamp(0, 255), (byte)(left.B - right.B).Clamp(0, 255), (byte)(left.A - right.A).Clamp(0, 255));
|
||||||
|
public static ColorRGBA operator *(ColorRGBA left, ColorRGBA right) => new((byte)(left.R * right.R).Clamp(0, 255), (byte)(left.G * right.G).Clamp(0, 255), (byte)(left.B * right.B).Clamp(0, 255), (byte)(left.A * right.A).Clamp(0, 255));
|
||||||
|
public static ColorRGBA operator *(ColorRGBA color, float value) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255), (byte)(color.A * value).Clamp(0, 255));
|
||||||
|
public static ColorRGBA operator *(float value, ColorRGBA color) => new((byte)(color.R * value).Clamp(0, 255), (byte)(color.G * value).Clamp(0, 255), (byte)(color.B * value).Clamp(0, 255), (byte)(color.A * value).Clamp(0, 255));
|
||||||
|
public static ColorRGBA operator /(ColorRGBA color, float value) => new((byte)(color.R / value).Clamp(0, 255), (byte)(color.G / value).Clamp(0, 255), (byte)(color.B / value).Clamp(0, 255), (byte)(color.A / value).Clamp(0, 255));
|
||||||
|
public static bool operator ==(ColorRGBA left, ColorRGBA right) => left.R == right.R && left.G == right.G && left.B == right.B && left.A == right.A;
|
||||||
|
public static bool operator !=(ColorRGBA left, ColorRGBA right) => left.R != right.R || left.G != right.G || left.B != right.B || left.A != right.A;
|
||||||
|
|
||||||
|
public static implicit operator ColorRGBA(ColorRGB rgb) => new(rgb.R, rgb.G, rgb.B, 255);
|
||||||
|
public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorRGB)hsv;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inverts the given <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <returns>The inverted <see cref="ColorRGBA"/>.</returns>
|
||||||
|
public static ColorRGBA Invert(ColorRGBA color) => -color;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds two <see cref="ColorRGBA"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <param name="right">The second <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <returns>The sum of the two <see cref="ColorRGBA"/>s.</returns>
|
||||||
|
public static ColorRGBA Add(ColorRGBA left, ColorRGBA right) => left + right;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts one <see cref="ColorRGBA"/> from another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The <see cref="ColorRGBA"/> to subtract from.</param>
|
||||||
|
/// <param name="right">The <see cref="ColorRGBA"/> to subtract.</param>
|
||||||
|
/// <returns>The result of subtracting the second <see cref="ColorRGBA"/> from the first.</returns>
|
||||||
|
public static ColorRGBA Subtract(ColorRGBA left, ColorRGBA right) => left - right;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies a <see cref="ColorRGBA"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <param name="value">The scalar value.</param>
|
||||||
|
/// <returns>The result of multiplying the <see cref="ColorRGBA"/> by the scalar value.</returns>
|
||||||
|
public static ColorRGBA Multiply(ColorRGBA color, float value) => color * value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides a <see cref="ColorRGBA"/> by a scalar value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="color">The <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <param name="value">The scalar value.</param>
|
||||||
|
/// <returns>The result of dividing the <see cref="ColorRGBA"/> by the scalar value.</returns>
|
||||||
|
public static ColorRGBA Divide(ColorRGBA color, float value) => color / value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the <see cref="ColorRGBA"/> from one point to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">The starting point.</param>
|
||||||
|
/// <param name="to">The ending point.</param>
|
||||||
|
/// <returns>The <see cref="ColorRGBA"/> from the starting point to the ending point.</returns>
|
||||||
|
public static ColorRGBA FromTo(ColorRGBA from, ColorRGBA to) => to - from;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs linear interpolation between two <see cref="ColorRGBA"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="from">The starting <see cref="ColorRGBA"/> (t = 0).</param>
|
||||||
|
/// <param name="to">The ending <see cref="ColorRGBA"/> (t = 1).</param>
|
||||||
|
/// <param name="t">The interpolation parameter.</param>
|
||||||
|
/// <returns>The interpolated <see cref="ColorRGBA"/>.</returns>
|
||||||
|
public static ColorRGBA Lerp(ColorRGBA from, ColorRGBA to, float t) => from + FromTo(from, to) * t;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the <see cref="ColorRGBA"/> to its string representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string representation of the <see cref="ColorRGBA"/>.</returns>
|
||||||
|
public override string ToString() => $"{nameof(ColorRGBA)}({R}, {G}, {B}, {A})";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified object is equal to the current <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to compare with the current <see cref="ColorRGBA"/>.</param>
|
||||||
|
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGBA"/>; otherwise, <see cref="false"/>.</returns>
|
||||||
|
public override bool Equals(object? obj) => obj is ColorRGBA objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B) && A.Equals(objVec.A);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a hash code for the <see cref="ColorRGBA"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A hash code for the <see cref="ColorRGBA"/>.</returns>
|
||||||
|
public override int GetHashCode() => System.HashCode.Combine(R, G, B, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for <see cref="ColorRGBA"/> type.
|
||||||
|
/// </summary>
|
||||||
|
public static class ColorRGBAExtensions
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="ColorRGBA.Add(ColorRGBA, ColorRGBA)" />
|
||||||
|
public static ColorRGBA Add(this ColorRGBA color, ColorRGBA value) => ColorRGBA.Add(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGBA.Subtract(ColorRGBA, ColorRGBA)" />
|
||||||
|
public static ColorRGBA Subtract(this ColorRGBA color, ColorRGBA value) => ColorRGBA.Subtract(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGBA.Multiply(ColorRGBA, ColorRGBA)" />
|
||||||
|
public static ColorRGBA Multiply(this ColorRGBA color, float value) => ColorRGBA.Multiply(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGBA.Divide(ColorRGBA, ColorRGBA)" />
|
||||||
|
public static ColorRGBA Divide(this ColorRGBA color, float value) => ColorRGBA.Divide(color, value);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGBA.FromTo(ColorRGBA, ColorRGBA)" />
|
||||||
|
public static ColorRGBA FromTo(this ColorRGBA from, ColorRGBA to) => ColorRGBA.FromTo(from, to);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ColorRGBA.Lerp(ColorRGBA, ColorRGBA, float)" />
|
||||||
|
public static ColorRGBA Lerp(this ColorRGBA from, ColorRGBA to, float t) => ColorRGBA.Lerp(from, to, t);
|
||||||
|
}
|
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
@@ -68,12 +67,12 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static float GetT(Line2D line, Vector2D point)
|
public static float GetT(Line2D line, Vector2D point)
|
||||||
{
|
{
|
||||||
float fromX = MathF.Abs(line.From.X);
|
float fromX = Math.Abs(line.From.X);
|
||||||
float toX = MathF.Abs(line.To.X);
|
float toX = Math.Abs(line.To.X);
|
||||||
float pointX = MathF.Abs(point.X);
|
float pointX = Math.Abs(point.X);
|
||||||
|
|
||||||
float min = MathF.Min(fromX, toX);
|
float min = Math.Min(fromX, toX);
|
||||||
float max = MathF.Max(fromX, toX) - min;
|
float max = Math.Max(fromX, toX) - min;
|
||||||
|
|
||||||
pointX -= min;
|
pointX -= min;
|
||||||
|
|
||||||
@@ -114,8 +113,8 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool OnSegment(Line2D line, Vector2D point)
|
public static bool OnSegment(Line2D line, Vector2D point)
|
||||||
{
|
{
|
||||||
if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) &&
|
if (point.X <= Math.Max(line.From.X, line.To.X) && point.X >= Math.Min(line.From.X, line.To.X) &&
|
||||||
point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y))
|
point.Y <= Math.Max(line.From.Y, line.To.Y) && point.Y >= Math.Min(line.From.Y, line.To.Y))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -173,7 +172,7 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
|
|||||||
|
|
||||||
float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
|
float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
|
||||||
|
|
||||||
t = MathF.Max(0, MathF.Min(1, t));
|
t = Math.Max(0, Math.Min(1, t));
|
||||||
|
|
||||||
float closestX = line.From.X + t * edgeVector.X;
|
float closestX = line.From.X + t * edgeVector.X;
|
||||||
float closestY = line.From.Y + t * edgeVector.Y;
|
float closestY = line.From.Y + t * edgeVector.Y;
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -178,11 +176,11 @@ public readonly struct Quaternion(float x, float y, float z, float w)
|
|||||||
if (dot > 0.9995f)
|
if (dot > 0.9995f)
|
||||||
return Lerp(from, to, t);
|
return Lerp(from, to, t);
|
||||||
|
|
||||||
float angle = MathF.Acos(dot);
|
float angle = Math.Acos(dot);
|
||||||
float sinAngle = MathF.Sin(angle);
|
float sinAngle = Math.Sin(angle);
|
||||||
|
|
||||||
float fromWeight = MathF.Sin((1f - t) * angle) / sinAngle;
|
float fromWeight = Math.Sin((1f - t) * angle) / sinAngle;
|
||||||
float toWeight = MathF.Sin(t * angle) / sinAngle;
|
float toWeight = Math.Sin(t * angle) / sinAngle;
|
||||||
|
|
||||||
return from * fromWeight + to * toWeight;
|
return from * fromWeight + to * toWeight;
|
||||||
}
|
}
|
||||||
@@ -213,8 +211,8 @@ public readonly struct Quaternion(float x, float y, float z, float w)
|
|||||||
public static Quaternion FromAxisAngle(Vector3D axis, float angle)
|
public static Quaternion FromAxisAngle(Vector3D axis, float angle)
|
||||||
{
|
{
|
||||||
float halfAngle = angle * .5f;
|
float halfAngle = angle * .5f;
|
||||||
float sinHalf = MathF.Sin(halfAngle);
|
float sinHalf = Math.Sin(halfAngle);
|
||||||
return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, MathF.Cos(halfAngle));
|
return new Quaternion(axis.X * sinHalf, axis.Y * sinHalf, axis.Z * sinHalf, Math.Cos(halfAngle));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -301,7 +299,7 @@ public readonly struct Quaternion(float x, float y, float z, float w)
|
|||||||
/// Generates a hash code for the <see cref="Quaternion"/>.
|
/// Generates a hash code for the <see cref="Quaternion"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A hash code for the <see cref="Quaternion"/>.</returns>
|
/// <returns>A hash code for the <see cref="Quaternion"/>.</returns>
|
||||||
public override int GetHashCode() => HashCode.Combine(X, Y, Z);
|
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -13,19 +11,33 @@ namespace Syntriax.Engine.Core;
|
|||||||
/// Initializes a new instance of a <see cref="Shape2D"/> struct with the specified vertices.
|
/// Initializes a new instance of a <see cref="Shape2D"/> struct with the specified vertices.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")]
|
[System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")]
|
||||||
public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||||
{
|
{
|
||||||
public static readonly Shape2D Triangle = CreateNgon(3, Vector2D.Up);
|
public static Shape2D Triangle => CreateNgon(3, Vector2D.Up);
|
||||||
public static readonly Shape2D Square = CreateNgon(4, Vector2D.One);
|
public static Shape2D Square => CreateNgon(4, Vector2D.One);
|
||||||
public static readonly Shape2D Pentagon = CreateNgon(5, Vector2D.Up);
|
public static Shape2D Pentagon => CreateNgon(5, Vector2D.Up);
|
||||||
public static readonly Shape2D Hexagon = CreateNgon(6, Vector2D.Right);
|
public static Shape2D Hexagon => CreateNgon(6, Vector2D.Right);
|
||||||
|
|
||||||
private readonly List<Vector2D> _verticesList = vertices;
|
public event ShapeUpdatedEventHandler? OnShapeUpdated = null;
|
||||||
|
|
||||||
|
private List<Vector2D> _vertices = vertices;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vertices of the <see cref="Shape2D"/>.
|
/// Gets the vertices of the <see cref="Shape2D"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<Vector2D> Vertices => _verticesList;
|
public IReadOnlyList<Vector2D> Vertices
|
||||||
|
{
|
||||||
|
get => _vertices;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_vertices.Clear();
|
||||||
|
|
||||||
|
foreach (Vector2D vertex in value)
|
||||||
|
_vertices.Add(vertex);
|
||||||
|
|
||||||
|
OnShapeUpdated?.InvokeSafe(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The vertex at the specified index.
|
/// The vertex at the specified index.
|
||||||
@@ -209,13 +221,15 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
|||||||
/// <param name="from">The <see cref="Shape2D"/> to transform.</param>
|
/// <param name="from">The <see cref="Shape2D"/> to transform.</param>
|
||||||
/// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
|
/// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
|
||||||
/// <param name="to">The transformed <see cref="Shape2D"/>.</param>
|
/// <param name="to">The transformed <see cref="Shape2D"/>.</param>
|
||||||
public static void Transform(Shape2D from, ITransform2D transform, ref Shape2D to)
|
public static void Transform(Shape2D from, ITransform2D transform, Shape2D to)
|
||||||
{
|
{
|
||||||
to._verticesList.Clear();
|
to._vertices.Clear();
|
||||||
|
|
||||||
int count = from._verticesList.Count;
|
int count = from._vertices.Count;
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
to._verticesList.Add(transform.Transform(from[i]));
|
to._vertices.Add(transform.Transform(from[i]));
|
||||||
|
|
||||||
|
to.OnShapeUpdated?.InvokeSafe(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -242,6 +256,8 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
|
||||||
|
|
||||||
|
public delegate void ShapeUpdatedEventHandler(Shape2D shape2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -277,13 +293,13 @@ public static class Shape2DExtensions
|
|||||||
public static Shape2D Transform(this ITransform2D transform, Shape2D shape) => Shape2D.Transform(shape, transform);
|
public static Shape2D Transform(this ITransform2D transform, Shape2D shape) => Shape2D.Transform(shape, transform);
|
||||||
|
|
||||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, Shape2D)" />
|
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, Shape2D)" />
|
||||||
public static void Transform(this ITransform2D transform, Shape2D from, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
|
public static void Transform(this ITransform2D transform, Shape2D from, Shape2D to) => Shape2D.Transform(from, transform, to);
|
||||||
|
|
||||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D)" />
|
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D)" />
|
||||||
public static Shape2D Transform(this Shape2D shape, ITransform2D transform) => Shape2D.Transform(shape, transform);
|
public static Shape2D Transform(this Shape2D shape, ITransform2D transform) => Shape2D.Transform(shape, transform);
|
||||||
|
|
||||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, ref Shape2D)" />
|
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D,Shape2D)" />
|
||||||
public static void Transform(this Shape2D from, ITransform2D transform, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
|
public static void Transform(this Shape2D from, ITransform2D transform, Shape2D to) => Shape2D.Transform(from, transform, to);
|
||||||
|
|
||||||
/// <inheritdoc cref="Shape2D.ApproximatelyEquals(Shape2D, Shape2D, float)" />
|
/// <inheritdoc cref="Shape2D.ApproximatelyEquals(Shape2D, Shape2D, float)" />
|
||||||
public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon);
|
public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon);
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")]
|
[System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")]
|
||||||
@@ -10,7 +8,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
|
|||||||
public readonly Vector2D C { get; init; } = C;
|
public readonly Vector2D C { get; init; } = C;
|
||||||
|
|
||||||
public readonly float Area
|
public readonly float Area
|
||||||
=> .5f * MathF.Abs(
|
=> .5f * Math.Abs(
|
||||||
A.X * (B.Y - C.Y) +
|
A.X * (B.Y - C.Y) +
|
||||||
B.X * (C.Y - A.Y) +
|
B.X * (C.Y - A.Y) +
|
||||||
C.X * (A.Y - B.Y)
|
C.X * (A.Y - B.Y)
|
||||||
@@ -25,7 +23,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
|
|||||||
float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X);
|
float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X);
|
||||||
|
|
||||||
Vector2D center;
|
Vector2D center;
|
||||||
if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
|
if (Math.Abs(slopeAB - slopeBC) > float.Epsilon)
|
||||||
{
|
{
|
||||||
float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2f * (slopeBC - slopeAB));
|
float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2f * (slopeBC - slopeAB));
|
||||||
float y = -(x - (triangle.A.X + triangle.B.X) / 2f) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2f;
|
float y = -(x - (triangle.A.X + triangle.B.X) / 2f) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2f;
|
||||||
|
@@ -1,6 +1,3 @@
|
|||||||
using System;
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -317,7 +314,7 @@ public readonly struct Vector2D(float x, float y)
|
|||||||
/// Generates a hash code for the <see cref="Vector2D"/>.
|
/// Generates a hash code for the <see cref="Vector2D"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A hash code for the <see cref="Vector2D"/>.</returns>
|
/// <returns>A hash code for the <see cref="Vector2D"/>.</returns>
|
||||||
public override int GetHashCode() => HashCode.Combine(X, Y);
|
public override int GetHashCode() => System.HashCode.Combine(X, Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -290,7 +288,7 @@ public readonly struct Vector3D(float x, float y, float z)
|
|||||||
/// Generates a hash code for the <see cref="Vector3D"/>.
|
/// Generates a hash code for the <see cref="Vector3D"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A hash code for the <see cref="Vector3D"/>.</returns>
|
/// <returns>A hash code for the <see cref="Vector3D"/>.</returns>
|
||||||
public override int GetHashCode() => HashCode.Combine(X, Y, Z);
|
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class)]
|
||||||
|
public class IgnoreSerializationAttribute : Attribute;
|
@@ -0,0 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||||
|
public class SerializeAllAttribute : Attribute;
|
@@ -0,0 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||||
|
public class SerializeAttribute : Attribute;
|
3
Engine.Core/Serialization/EntityReference.cs
Normal file
3
Engine.Core/Serialization/EntityReference.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
public record class EntityReference(string? Id = null);
|
39
Engine.Core/Serialization/EntityRegistry.cs
Normal file
39
Engine.Core/Serialization/EntityRegistry.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
public class EntityRegistry
|
||||||
|
{
|
||||||
|
public event EntityRegisteredEventHandler? OnEntityRegistered = null!;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, Action<IEntity>?> assignCallbacks = [];
|
||||||
|
private readonly Dictionary<string, IEntity> registeredEntities = [];
|
||||||
|
public IReadOnlyDictionary<string, IEntity> RegisteredEntities => registeredEntities;
|
||||||
|
|
||||||
|
public void Add(IEntity entity)
|
||||||
|
{
|
||||||
|
if (registeredEntities.TryAdd(entity.Id, entity))
|
||||||
|
OnEntityRegistered?.InvokeSafe(this, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void QueueAssign(string id, Action<IEntity> setMethod)
|
||||||
|
{
|
||||||
|
assignCallbacks.TryAdd(id, null);
|
||||||
|
assignCallbacks[id] = assignCallbacks[id] + setMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssignAll()
|
||||||
|
{
|
||||||
|
foreach ((string id, Action<IEntity>? action) in assignCallbacks)
|
||||||
|
action?.InvokeSafe(registeredEntities[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
assignCallbacks.Clear();
|
||||||
|
registeredEntities.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void EntityRegisteredEventHandler(EntityRegistry sender, IEntity entity);
|
||||||
|
}
|
18
Engine.Core/Serialization/ISerializer.cs
Normal file
18
Engine.Core/Serialization/ISerializer.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
public interface ISerializer
|
||||||
|
{
|
||||||
|
object Deserialize(string configuration);
|
||||||
|
object Deserialize(string configuration, Type type);
|
||||||
|
T Deserialize<T>(string configuration);
|
||||||
|
|
||||||
|
string Serialize(object instance);
|
||||||
|
|
||||||
|
ProgressiveTask<object> DeserializeAsync(string configuration);
|
||||||
|
ProgressiveTask<object> DeserializeAsync(string configuration, Type type);
|
||||||
|
ProgressiveTask<T> DeserializeAsync<T>(string configuration);
|
||||||
|
|
||||||
|
ProgressiveTask<string> SerializeAsync(object instance);
|
||||||
|
}
|
157
Engine.Core/Serialization/SerializedClass.cs
Normal file
157
Engine.Core/Serialization/SerializedClass.cs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Syntriax.Engine.Core.Factory;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
public class SerializedClass
|
||||||
|
{
|
||||||
|
private const BindingFlags PRIVATE_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.NonPublic;
|
||||||
|
private const BindingFlags PUBLIC_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.Public;
|
||||||
|
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
public Dictionary<string, object?> Public { get; set; } = [];
|
||||||
|
public Dictionary<string, object?> Private { get; set; } = [];
|
||||||
|
|
||||||
|
public SerializedClass() { }
|
||||||
|
public SerializedClass(object @class)
|
||||||
|
{
|
||||||
|
UpdateClass(@class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateClass(object @class)
|
||||||
|
{
|
||||||
|
Type type = @class.GetType();
|
||||||
|
Type = type.FullName ?? type.Name;
|
||||||
|
|
||||||
|
bool shouldSerializeAll = type.HasAttribute<SerializeAllAttribute>();
|
||||||
|
|
||||||
|
Public.Clear();
|
||||||
|
Private.Clear();
|
||||||
|
|
||||||
|
foreach (PropertyInfo privatePropertyInfo in Utils.GetPropertyInfosIncludingBaseClasses(type, PRIVATE_BINDING_FLAGS))
|
||||||
|
{
|
||||||
|
if (privatePropertyInfo.HasAttribute<IgnoreSerializationAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (privatePropertyInfo.SetMethod is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!shouldSerializeAll && !privatePropertyInfo.HasAttribute<SerializeAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
object? value = privatePropertyInfo.GetValue(@class);
|
||||||
|
if (value is IEntity entity)
|
||||||
|
Private.Add(privatePropertyInfo.Name, entity.Id);
|
||||||
|
else
|
||||||
|
Private.Add(privatePropertyInfo.Name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (PropertyInfo publicPropertyInfo in Utils.GetPropertyInfosIncludingBaseClasses(type, PUBLIC_BINDING_FLAGS))
|
||||||
|
{
|
||||||
|
if (publicPropertyInfo.HasAttribute<IgnoreSerializationAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (publicPropertyInfo.SetMethod is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!shouldSerializeAll && !publicPropertyInfo.HasAttribute<SerializeAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
object? value = publicPropertyInfo.GetValue(@class);
|
||||||
|
if (value is IEntity entity)
|
||||||
|
Public.Add(publicPropertyInfo.Name, entity.Id);
|
||||||
|
else
|
||||||
|
Public.Add(publicPropertyInfo.Name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FieldInfo privateFieldInfo in Utils.GetFieldInfosIncludingBaseClasses(type, PRIVATE_BINDING_FLAGS))
|
||||||
|
{
|
||||||
|
if (privateFieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!shouldSerializeAll && !privateFieldInfo.HasAttribute<SerializeAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
object? value = privateFieldInfo.GetValue(@class);
|
||||||
|
if (value is IEntity entity)
|
||||||
|
Private.Add(privateFieldInfo.Name, entity.Id);
|
||||||
|
else
|
||||||
|
Private.Add(privateFieldInfo.Name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FieldInfo publicFieldInfo in Utils.GetFieldInfosIncludingBaseClasses(type, PUBLIC_BINDING_FLAGS))
|
||||||
|
{
|
||||||
|
if (publicFieldInfo.HasAttribute<System.Runtime.CompilerServices.CompilerGeneratedAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!shouldSerializeAll && !publicFieldInfo.HasAttribute<SerializeAttribute>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
object? value = publicFieldInfo.GetValue(@class);
|
||||||
|
if (value is IEntity entity)
|
||||||
|
Public.Add(publicFieldInfo.Name, entity.Id);
|
||||||
|
else
|
||||||
|
Public.Add(publicFieldInfo.Name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object CreateInstance()
|
||||||
|
{
|
||||||
|
Type type = TypeFactory.GetType(Type);
|
||||||
|
object instance = TypeFactory.Get(type);
|
||||||
|
|
||||||
|
foreach ((string key, object? value) in Private)
|
||||||
|
AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS);
|
||||||
|
|
||||||
|
foreach ((string key, object? value) in Public)
|
||||||
|
AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object CreateInstance(EntityRegistry? entityRegistry)
|
||||||
|
{
|
||||||
|
if (entityRegistry is null)
|
||||||
|
return CreateInstance();
|
||||||
|
|
||||||
|
Type type = TypeFactory.GetType(Type);
|
||||||
|
object instance = TypeFactory.Get(type);
|
||||||
|
|
||||||
|
foreach ((string key, object? value) in Private)
|
||||||
|
AssignVariable(key, type, instance, value, PRIVATE_BINDING_FLAGS, entityRegistry);
|
||||||
|
|
||||||
|
foreach ((string key, object? value) in Public)
|
||||||
|
AssignVariable(key, type, instance, value, PUBLIC_BINDING_FLAGS, entityRegistry);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags, EntityRegistry entityRegistry)
|
||||||
|
{
|
||||||
|
if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
|
||||||
|
{
|
||||||
|
if (typeof(IEntity).IsAssignableFrom(fieldInfo.FieldType))
|
||||||
|
entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => fieldInfo.SetValue(instance, entity));
|
||||||
|
else
|
||||||
|
fieldInfo.SetValue(instance, value);
|
||||||
|
}
|
||||||
|
else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
|
||||||
|
{
|
||||||
|
if (typeof(IEntity).IsAssignableFrom(propertyInfo.PropertyType))
|
||||||
|
entityRegistry.QueueAssign(value?.ToString() ?? "", (entity) => propertyInfo.SetValue(instance, entity));
|
||||||
|
else
|
||||||
|
propertyInfo.SetValue(instance, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssignVariable(string key, Type type, object instance, object? value, BindingFlags bindingFlags)
|
||||||
|
{
|
||||||
|
if (type.GetField(key, bindingFlags) is FieldInfo fieldInfo)
|
||||||
|
fieldInfo.SetValue(instance, value);
|
||||||
|
else if (type.GetProperty(key, bindingFlags) is PropertyInfo propertyInfo)
|
||||||
|
propertyInfo.SetValue(instance, value);
|
||||||
|
}
|
||||||
|
}
|
13
Engine.Core/Serialization/TypeContainer.cs
Normal file
13
Engine.Core/Serialization/TypeContainer.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
public class TypeContainer
|
||||||
|
{
|
||||||
|
public object? Value { get; set; } = string.Empty;
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public TypeContainer() { }
|
||||||
|
public TypeContainer(Type type) { Type = type.FullName ?? string.Empty; }
|
||||||
|
public TypeContainer(object? value) { Value = value; Type = value?.GetType().FullName ?? string.Empty; }
|
||||||
|
}
|
82
Engine.Core/Serialization/Utils.cs
Normal file
82
Engine.Core/Serialization/Utils.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
|
public static class Utils
|
||||||
|
{
|
||||||
|
public static bool HasAttribute<T>(this MemberInfo memberInfo) where T : Attribute => memberInfo.GetCustomAttribute<T>() is not null;
|
||||||
|
public static bool IsEnumerable(this Type type) => typeof(System.Collections.IEnumerable).IsAssignableFrom(type) && type != typeof(string);
|
||||||
|
|
||||||
|
public static TypeData GetTypeData(this Type objectType)
|
||||||
|
{
|
||||||
|
List<EventInfo> eventInfos = objectType.GetEvents(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||||
|
.OrderBy(ei => ei.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
List<FieldInfo> fieldInfos = GetFieldInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public)
|
||||||
|
.Where(pi => !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0)).ToList();
|
||||||
|
|
||||||
|
List<PropertyInfo> propertyInfos = GetPropertyInfosIncludingBaseClasses(objectType, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public)
|
||||||
|
.Where(pi => pi.SetMethod is not null && !eventInfos.Any(ei => pi.Name.CompareTo(ei.Name) == 0))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new TypeData(fieldInfos, propertyInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FieldInfo> GetFieldInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
|
||||||
|
{
|
||||||
|
if (type.BaseType is null)
|
||||||
|
return [.. type.GetFields(bindingFlags)];
|
||||||
|
|
||||||
|
Type currentType = type;
|
||||||
|
FieldInfoComparer fieldComparer = new();
|
||||||
|
HashSet<FieldInfo> fieldInfoList = new(type.GetFields(bindingFlags), fieldComparer);
|
||||||
|
|
||||||
|
while (currentType.BaseType is Type baseType)
|
||||||
|
{
|
||||||
|
currentType = baseType;
|
||||||
|
fieldInfoList.UnionWith(currentType!.GetFields(bindingFlags));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.. fieldInfoList.OrderBy(fi => fi.Name)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<PropertyInfo> GetPropertyInfosIncludingBaseClasses(Type type, BindingFlags bindingFlags)
|
||||||
|
{
|
||||||
|
if (type.BaseType is null)
|
||||||
|
return [.. type.GetProperties(bindingFlags)];
|
||||||
|
|
||||||
|
Type currentType = type;
|
||||||
|
PropertyInfoComparer propertyComparer = new();
|
||||||
|
HashSet<PropertyInfo> propertyInfoList = new(type.GetProperties(bindingFlags), propertyComparer);
|
||||||
|
|
||||||
|
while (currentType.BaseType is Type baseType)
|
||||||
|
{
|
||||||
|
currentType = baseType;
|
||||||
|
propertyInfoList.UnionWith(currentType.GetProperties(bindingFlags));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.. propertyInfoList.OrderBy(pi => pi.Name)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FieldInfoComparer : IEqualityComparer<FieldInfo>
|
||||||
|
{
|
||||||
|
public bool Equals(FieldInfo? x, FieldInfo? y) => x?.DeclaringType == y?.DeclaringType && x?.Name == y?.Name;
|
||||||
|
public int GetHashCode(FieldInfo obj) => obj.Name.GetHashCode() ^ obj.DeclaringType!.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PropertyInfoComparer : IEqualityComparer<PropertyInfo>
|
||||||
|
{
|
||||||
|
public bool Equals(PropertyInfo? x, PropertyInfo? y) => x?.DeclaringType == y?.DeclaringType && x?.Name == y?.Name;
|
||||||
|
public int GetHashCode(PropertyInfo obj) => obj.Name.GetHashCode() ^ obj.DeclaringType!.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record struct TypeData(IEnumerable<FieldInfo> Fields, IEnumerable<PropertyInfo> Properties)
|
||||||
|
{
|
||||||
|
public static implicit operator (IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties)(TypeData value) => (value.Fields, value.Properties);
|
||||||
|
public static implicit operator TypeData((IEnumerable<FieldInfo> fields, IEnumerable<PropertyInfo> properties) value) => new(value.fields, value.properties);
|
||||||
|
}
|
@@ -1,5 +1,3 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public class StateEnable : IStateEnable
|
public class StateEnable : IStateEnable
|
||||||
@@ -23,7 +21,7 @@ public class StateEnable : IStateEnable
|
|||||||
|
|
||||||
bool previousState = _enabled;
|
bool previousState = _enabled;
|
||||||
_enabled = value;
|
_enabled = value;
|
||||||
OnEnabledChanged?.Invoke(this, previousState);
|
OnEnabledChanged?.InvokeSafe(this, previousState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +33,7 @@ public class StateEnable : IStateEnable
|
|||||||
|
|
||||||
_entity = entity;
|
_entity = entity;
|
||||||
OnAssign(entity);
|
OnAssign(entity);
|
||||||
OnEntityAssigned?.Invoke(this);
|
OnEntityAssigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +43,7 @@ public class StateEnable : IStateEnable
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
_entity = null!;
|
_entity = null!;
|
||||||
OnUnassigned?.Invoke(this);
|
OnUnassigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,5 @@ namespace Syntriax.Engine.Core;
|
|||||||
internal static class Constants
|
internal static class Constants
|
||||||
{
|
{
|
||||||
internal static int BEHAVIOURS_SIZE_INITIAL = 16;
|
internal static int BEHAVIOURS_SIZE_INITIAL = 16;
|
||||||
internal static int GAME_OBJECTS_SIZE_INITIAL = 256;
|
internal static int UNIVERSE_OBJECTS_SIZE_INITIAL = 256;
|
||||||
internal static int DRAWABLE_OBJECTS_SIZE_INITIAL = 256;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
using Syntriax.Engine.Core.Serialization;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("Name: {HierarchyObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
|
[System.Diagnostics.DebuggerDisplay("Name: {UniverseObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
|
||||||
public class Transform2D : Behaviour, ITransform2D
|
public class Transform2D : Behaviour, ITransform2D
|
||||||
{
|
{
|
||||||
public event ITransform2D.PositionChangedEventHandler? OnPositionChanged = null;
|
public event ITransform2D.PositionChangedEventHandler? OnPositionChanged = null;
|
||||||
@@ -13,9 +13,9 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
private Vector2D _scale = Vector2D.One;
|
private Vector2D _scale = Vector2D.One;
|
||||||
private float _rotation = 0f;
|
private float _rotation = 0f;
|
||||||
|
|
||||||
private Vector2D _localPosition = Vector2D.Zero;
|
[Serialize] private Vector2D _localPosition = Vector2D.Zero;
|
||||||
private Vector2D _localScale = Vector2D.One;
|
[Serialize] private Vector2D _localScale = Vector2D.One;
|
||||||
private float _localRotation = 0f;
|
[Serialize] private float _localRotation = 0f;
|
||||||
|
|
||||||
private ITransform2D? parentTransform = null;
|
private ITransform2D? parentTransform = null;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
_position = value;
|
_position = value;
|
||||||
|
|
||||||
UpdateLocalPosition();
|
UpdateLocalPosition();
|
||||||
OnPositionChanged?.Invoke(this, _position);
|
OnPositionChanged?.InvokeSafe(this, previousPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
_scale = value;
|
_scale = value;
|
||||||
|
|
||||||
UpdateLocalScale();
|
UpdateLocalScale();
|
||||||
OnScaleChanged?.Invoke(this, previousScale);
|
OnScaleChanged?.InvokeSafe(this, previousScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
_rotation = value;
|
_rotation = value;
|
||||||
|
|
||||||
UpdateLocalRotation();
|
UpdateLocalRotation();
|
||||||
OnRotationChanged?.Invoke(this, previousRotation);
|
OnRotationChanged?.InvokeSafe(this, previousRotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
_localPosition = value;
|
_localPosition = value;
|
||||||
|
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
OnPositionChanged?.Invoke(this, previousPosition);
|
OnPositionChanged?.InvokeSafe(this, previousPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +97,8 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
|
|
||||||
UpdateScale();
|
UpdateScale();
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
OnScaleChanged?.Invoke(this, previousScale);
|
OnScaleChanged?.InvokeSafe(this, previousScale);
|
||||||
OnPositionChanged?.Invoke(this, previousPosition);
|
OnPositionChanged?.InvokeSafe(this, previousPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
_localRotation = value;
|
_localRotation = value;
|
||||||
|
|
||||||
UpdateRotation();
|
UpdateRotation();
|
||||||
OnRotationChanged?.Invoke(this, previousRotation);
|
OnRotationChanged?.InvokeSafe(this, previousRotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
|
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
|
|
||||||
OnPositionChanged?.Invoke(this, previousPosition);
|
OnPositionChanged?.InvokeSafe(this, previousPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecalculateScale(ITransform2D _, Vector2D previousScale)
|
private void RecalculateScale(ITransform2D _, Vector2D previousScale)
|
||||||
@@ -138,8 +138,8 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
UpdateScale();
|
UpdateScale();
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
|
|
||||||
OnScaleChanged?.Invoke(this, previousScale);
|
OnScaleChanged?.InvokeSafe(this, previousScale);
|
||||||
OnPositionChanged?.Invoke(this, previousPosition);
|
OnPositionChanged?.InvokeSafe(this, previousPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecalculateRotation(ITransform2D _, float previousRotation)
|
private void RecalculateRotation(ITransform2D _, float previousRotation)
|
||||||
@@ -152,8 +152,8 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
UpdateRotation();
|
UpdateRotation();
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
|
|
||||||
OnRotationChanged?.Invoke(this, previousRotation);
|
OnRotationChanged?.InvokeSafe(this, previousRotation);
|
||||||
OnPositionChanged?.Invoke(this, previousPosition);
|
OnPositionChanged?.InvokeSafe(this, previousPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateLocalPosition()
|
private void UpdateLocalPosition()
|
||||||
@@ -206,25 +206,24 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
|
|
||||||
protected override void InitializeInternal()
|
protected override void InitializeInternal()
|
||||||
{
|
{
|
||||||
UpdateReferences(HierarchyObject.Parent);
|
UpdateReferences(UniverseObject.Parent);
|
||||||
HierarchyObject.OnParentChanged += OnParentChanged;
|
UniverseObject.OnParentChanged += OnParentChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FinalizeInternal()
|
protected override void FinalizeInternal()
|
||||||
{
|
{
|
||||||
HierarchyObject.OnParentChanged -= OnParentChanged;
|
UniverseObject.OnParentChanged -= OnParentChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateReferences(IHierarchyObject? parent)
|
private void UpdateReferences(IUniverseObject? parent)
|
||||||
{
|
{
|
||||||
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;
|
||||||
previousParent.BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged;
|
previousParent.BehaviourController.UniverseObject.OnParentChanged -= OnParentChanged;
|
||||||
previousParent.BehaviourController.OnBehaviourAdded -= LookForTransform2D;
|
previousParent.BehaviourController.OnBehaviourAdded -= LookForTransform2D;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,26 +231,25 @@ 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;
|
||||||
parentTransform.BehaviourController.HierarchyObject.OnParentChanged += OnParentChanged;
|
parentTransform.BehaviourController.UniverseObject.OnParentChanged += OnParentChanged;
|
||||||
|
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
UpdateScale();
|
UpdateScale();
|
||||||
UpdateRotation();
|
UpdateRotation();
|
||||||
}
|
}
|
||||||
else if (HierarchyObject.Parent is not null)
|
else if (UniverseObject.Parent is not null)
|
||||||
HierarchyObject.Parent.BehaviourController.OnBehaviourAdded += LookForTransform2D;
|
UniverseObject.Parent.BehaviourController.OnBehaviourAdded += LookForTransform2D;
|
||||||
|
|
||||||
UpdateLocalPosition();
|
UpdateLocalPosition();
|
||||||
UpdateLocalScale();
|
UpdateLocalScale();
|
||||||
UpdateLocalRotation();
|
UpdateLocalRotation();
|
||||||
|
|
||||||
OnPositionChanged?.Invoke(this, Position);
|
OnPositionChanged?.InvokeSafe(this, Position);
|
||||||
OnScaleChanged?.Invoke(this, Scale);
|
OnScaleChanged?.InvokeSafe(this, Scale);
|
||||||
OnRotationChanged?.Invoke(this, Rotation);
|
OnRotationChanged?.InvokeSafe(this, Rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LookForTransform2D(IBehaviourController sender, IBehaviour behaviourAdded)
|
private void LookForTransform2D(IBehaviourController sender, IBehaviour behaviourAdded)
|
||||||
@@ -259,10 +257,10 @@ public class Transform2D : Behaviour, ITransform2D
|
|||||||
if (behaviourAdded is not ITransform2D transform2D)
|
if (behaviourAdded is not ITransform2D transform2D)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UpdateReferences(HierarchyObject.Parent);
|
UpdateReferences(UniverseObject.Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnParentChanged(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent)
|
private void OnParentChanged(IUniverseObject sender, IUniverseObject? previousParent, IUniverseObject? newParent)
|
||||||
{
|
{
|
||||||
UpdateReferences(newParent);
|
UpdateReferences(newParent);
|
||||||
}
|
}
|
||||||
|
150
Engine.Core/Universe.cs
Normal file
150
Engine.Core/Universe.cs
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
[System.Diagnostics.DebuggerDisplay("UniverseObject Count: {_universeObjects.Count}")]
|
||||||
|
public class Universe : BaseEntity, IUniverse
|
||||||
|
{
|
||||||
|
public event IUniverse.UpdateEventHandler? OnPreUpdate = null;
|
||||||
|
public event IUniverse.UpdateEventHandler? OnUpdate = null;
|
||||||
|
public event IUniverse.PreDrawEventHandler? OnPreDraw = null;
|
||||||
|
|
||||||
|
public event IUniverse.UniverseObjectRegisteredEventHandler? OnUniverseObjectRegistered = null;
|
||||||
|
public event IUniverse.UniverseObjectUnRegisteredEventHandler? OnUniverseObjectUnRegistered = null;
|
||||||
|
|
||||||
|
public event IUniverse.TimeScaleChangedEventHandler? OnTimeScaleChanged = null;
|
||||||
|
|
||||||
|
private readonly List<IUniverseObject> _universeObjects = new(Constants.UNIVERSE_OBJECTS_SIZE_INITIAL);
|
||||||
|
private float _timeScale = 1f;
|
||||||
|
|
||||||
|
public IReadOnlyList<IUniverseObject> UniverseObjects => _universeObjects;
|
||||||
|
|
||||||
|
public UniverseTime Time { get; private set; } = new();
|
||||||
|
public UniverseTime UnscaledTime { get; private set; } = new();
|
||||||
|
public float TimeScale
|
||||||
|
{
|
||||||
|
get => _timeScale;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
value = value.Max(0f);
|
||||||
|
if (value == _timeScale)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float previousTimeScale = _timeScale;
|
||||||
|
_timeScale = value;
|
||||||
|
OnTimeScaleChanged?.InvokeSafe(this, previousTimeScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register(IUniverseObject universeObject)
|
||||||
|
{
|
||||||
|
if (_universeObjects.Contains(universeObject))
|
||||||
|
throw new Exception($"{nameof(IUniverseObject)} named {universeObject.Name} is already registered to the {nameof(Universe)}.");
|
||||||
|
|
||||||
|
universeObject.OnFinalized += OnUniverseObjectFinalize;
|
||||||
|
universeObject.OnExitedUniverse += OnUniverseObjectExitedUniverse;
|
||||||
|
|
||||||
|
if (!universeObject.Initialize())
|
||||||
|
throw new Exception($"{universeObject.Name} can't be initialized");
|
||||||
|
|
||||||
|
for (int i = 0; i < universeObject.Children.Count; i++)
|
||||||
|
Register(universeObject.Children[i]);
|
||||||
|
|
||||||
|
_universeObjects.Add(universeObject);
|
||||||
|
|
||||||
|
if (!universeObject.EnterUniverse(this))
|
||||||
|
throw new Exception($"{universeObject.Name} can't enter the universe");
|
||||||
|
|
||||||
|
OnUniverseObjectRegistered?.InvokeSafe(this, universeObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T InstantiateUniverseObject<T>(params object?[]? args) where T : class, IUniverseObject
|
||||||
|
{
|
||||||
|
T universeObject = Factory.UniverseObjectFactory.Instantiate<T>(args);
|
||||||
|
Register(universeObject);
|
||||||
|
return universeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(IUniverseObject universeObject)
|
||||||
|
{
|
||||||
|
universeObject.SetParent(null);
|
||||||
|
RemoveIncursive(universeObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveIncursive(IUniverseObject universeObject)
|
||||||
|
{
|
||||||
|
if (!_universeObjects.Contains(universeObject))
|
||||||
|
throw new Exception($"{nameof(IUniverseObject)} named {universeObject.Name} is not registered to the {nameof(Universe)}.");
|
||||||
|
|
||||||
|
universeObject.OnFinalized -= OnUniverseObjectFinalize;
|
||||||
|
universeObject.OnExitedUniverse -= OnUniverseObjectExitedUniverse;
|
||||||
|
|
||||||
|
for (int i = universeObject.Children.Count - 1; i >= 0; i--)
|
||||||
|
Remove(universeObject.Children[i]);
|
||||||
|
|
||||||
|
_universeObjects.Remove(universeObject);
|
||||||
|
|
||||||
|
if (!universeObject.ExitUniverse())
|
||||||
|
throw new Exception($"{universeObject.Name} can't exit the universe");
|
||||||
|
|
||||||
|
if (!universeObject.Finalize())
|
||||||
|
throw new Exception($"{universeObject.Name} can't be finalized");
|
||||||
|
|
||||||
|
OnUniverseObjectUnRegistered?.InvokeSafe(this, universeObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InitializeInternal()
|
||||||
|
{
|
||||||
|
foreach (IUniverseObject universeObject in UniverseObjects)
|
||||||
|
universeObject.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void FinalizeInternal()
|
||||||
|
{
|
||||||
|
base.FinalizeInternal();
|
||||||
|
for (int i = UniverseObjects.Count; i >= 0; i--)
|
||||||
|
UniverseObjects[i].Finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(UniverseTime engineTime)
|
||||||
|
{
|
||||||
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
|
UnscaledTime = engineTime;
|
||||||
|
Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
|
||||||
|
|
||||||
|
OnPreUpdate?.InvokeSafe(this, Time);
|
||||||
|
|
||||||
|
for (int i = 0; i < UniverseObjects.Count; i++)
|
||||||
|
UniverseObjects[i].BehaviourController.Update();
|
||||||
|
|
||||||
|
OnUpdate?.InvokeSafe(this, Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PreDraw()
|
||||||
|
{
|
||||||
|
Debug.Assert.AssertInitialized(this);
|
||||||
|
|
||||||
|
for (int i = 0; i < UniverseObjects.Count; i++)
|
||||||
|
UniverseObjects[i].BehaviourController.UpdatePreDraw();
|
||||||
|
|
||||||
|
OnPreDraw?.InvokeSafe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUniverseObjectFinalize(IInitializable initializable)
|
||||||
|
{
|
||||||
|
if (initializable is IUniverseObject universeObject)
|
||||||
|
Remove(universeObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUniverseObjectExitedUniverse(IUniverseObject sender, IUniverse universe)
|
||||||
|
{
|
||||||
|
if (sender is IUniverseObject universeObject)
|
||||||
|
Remove(universeObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IUniverseObject> GetEnumerator() => _universeObjects.GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => _universeObjects.GetEnumerator();
|
||||||
|
}
|
@@ -1,33 +1,31 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")]
|
[System.Diagnostics.DebuggerDisplay("Name: {Name}, Initialized: {Initialized}")]
|
||||||
public class HierarchyObject : BaseEntity, IHierarchyObject
|
public class UniverseObject : BaseEntity, IUniverseObject
|
||||||
{
|
{
|
||||||
public event IHierarchyObject.EnteredHierarchyEventHandler? OnEnteredHierarchy = null;
|
public event IUniverseObject.EnteredUniverseEventHandler? OnEnteredUniverse = null;
|
||||||
public event IHierarchyObject.ExitedHierarchyEventHandler? OnExitedHierarchy = null;
|
public event IUniverseObject.ExitedUniverseEventHandler? OnExitedUniverse = null;
|
||||||
public event IHierarchyObject.ParentChangedEventHandler? OnParentChanged = null;
|
public event IUniverseObject.ParentChangedEventHandler? OnParentChanged = null;
|
||||||
public event IHierarchyObject.ChildrenAddedEventHandler? OnChildrenAdded = null;
|
public event IUniverseObject.ChildrenAddedEventHandler? OnChildrenAdded = null;
|
||||||
public event IHierarchyObject.ChildrenRemovedEventHandler? OnChildrenRemoved = null;
|
public event IUniverseObject.ChildrenRemovedEventHandler? OnChildrenRemoved = null;
|
||||||
public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null;
|
public event IHasBehaviourController.BehaviourControllerAssignedEventHandler? OnBehaviourControllerAssigned = null;
|
||||||
public event INameable.NameChangedEventHandler? OnNameChanged = null;
|
public event INameable.NameChangedEventHandler? OnNameChanged = null;
|
||||||
public event IActive.ActiveChangedEventHandler? OnActiveChanged = null;
|
public event IActive.ActiveChangedEventHandler? OnActiveChanged = null;
|
||||||
|
|
||||||
private string _name = nameof(HierarchyObject);
|
private string _name = nameof(UniverseObject);
|
||||||
private IGameManager _gameManager = null!;
|
private IUniverse _universe = null!;
|
||||||
private IBehaviourController _behaviourController = null!;
|
private IBehaviourController _behaviourController = null!;
|
||||||
private bool _isActive = false;
|
private bool _isActive = false;
|
||||||
private readonly List<IHierarchyObject> _children = [];
|
private readonly List<IUniverseObject> _children = [];
|
||||||
|
|
||||||
public IHierarchyObject? Parent { get; private set; } = null;
|
public IUniverseObject? Parent { get; private set; } = null;
|
||||||
public IReadOnlyList<IHierarchyObject> Children => _children;
|
public IReadOnlyList<IUniverseObject> Children => _children;
|
||||||
public IBehaviourController BehaviourController => _behaviourController;
|
public IBehaviourController BehaviourController => _behaviourController;
|
||||||
public IGameManager GameManager => _gameManager;
|
public IUniverse Universe => _universe;
|
||||||
public bool IsInHierarchy => _gameManager is not null;
|
public bool IsInUniverse => _universe is not null;
|
||||||
public bool IsActive => _isActive;
|
public bool IsActive => _isActive;
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
@@ -39,45 +37,44 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
|||||||
|
|
||||||
string previousName = _name;
|
string previousName = _name;
|
||||||
_name = value;
|
_name = value;
|
||||||
OnNameChanged?.Invoke(this, previousName);
|
OnNameChanged?.InvokeSafe(this, previousName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnEnteringHierarchy(IGameManager gameManager) { }
|
protected virtual void OnEnteringUniverse(IUniverse universe) { }
|
||||||
bool IHierarchyObject.EnterHierarchy(IGameManager gameManager)
|
bool IUniverseObject.EnterUniverse(IUniverse universe)
|
||||||
{
|
{
|
||||||
if (IsInHierarchy)
|
if (IsInUniverse)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_gameManager = gameManager;
|
_universe = universe;
|
||||||
UpdateActive();
|
UpdateActive();
|
||||||
OnEnteringHierarchy(gameManager);
|
OnEnteringUniverse(universe);
|
||||||
OnEnteredHierarchy?.Invoke(this, gameManager);
|
OnEnteredUniverse?.InvokeSafe(this, universe);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnExitingHierarchy(IGameManager gameManager) { }
|
protected virtual void OnExitingUniverse(IUniverse universe) { }
|
||||||
bool IHierarchyObject.ExitHierarchy()
|
bool IUniverseObject.ExitUniverse()
|
||||||
{
|
{
|
||||||
if (!IsInHierarchy || _gameManager is not IGameManager gameManager)
|
if (!IsInUniverse || _universe is not IUniverse universe)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
OnExitingHierarchy(gameManager);
|
OnExitingUniverse(universe);
|
||||||
_gameManager = null!;
|
_universe = null!;
|
||||||
SetParent(null);
|
OnExitedUniverse?.InvokeSafe(this, universe);
|
||||||
OnExitedHierarchy?.Invoke(this, gameManager);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetParent(IHierarchyObject? parent)
|
public void SetParent(IUniverseObject? 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;
|
||||||
|
|
||||||
IHierarchyObject? previousParent = Parent;
|
IUniverseObject? previousParent = Parent;
|
||||||
if (previousParent is not null)
|
if (previousParent is not null)
|
||||||
{
|
{
|
||||||
previousParent.RemoveChild(this);
|
previousParent.RemoveChild(this);
|
||||||
@@ -88,34 +85,34 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
|||||||
|
|
||||||
if (parent is not null)
|
if (parent is not null)
|
||||||
{
|
{
|
||||||
if (parent.IsInHierarchy && !IsInHierarchy)
|
if (parent.IsInUniverse && !IsInUniverse)
|
||||||
parent.GameManager.Register(this);
|
parent.Universe.Register(this);
|
||||||
|
|
||||||
parent.AddChild(this);
|
parent.AddChild(this);
|
||||||
parent.OnActiveChanged += OnParentActiveChanged;
|
parent.OnActiveChanged += OnParentActiveChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateActive();
|
UpdateActive();
|
||||||
OnParentChanged?.Invoke(this, previousParent, parent);
|
OnParentChanged?.InvokeSafe(this, previousParent, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddChild(IHierarchyObject parent)
|
public void AddChild(IUniverseObject parent)
|
||||||
{
|
{
|
||||||
if (_children.Contains(parent))
|
if (_children.Contains(parent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_children.Add(parent);
|
_children.Add(parent);
|
||||||
parent.SetParent(this);
|
parent.SetParent(this);
|
||||||
OnChildrenAdded?.Invoke(this, parent);
|
OnChildrenAdded?.InvokeSafe(this, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveChild(IHierarchyObject parent)
|
public void RemoveChild(IUniverseObject child)
|
||||||
{
|
{
|
||||||
if (!_children.Remove(parent))
|
if (!_children.Remove(child))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
parent.SetParent(null);
|
child.SetParent(null);
|
||||||
OnChildrenRemoved?.Invoke(this, parent);
|
OnChildrenRemoved?.InvokeSafe(this, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnAssign(IBehaviourController behaviourController) { }
|
protected virtual void OnAssign(IBehaviourController behaviourController) { }
|
||||||
@@ -126,7 +123,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
|||||||
|
|
||||||
_behaviourController = behaviourController;
|
_behaviourController = behaviourController;
|
||||||
OnAssign(behaviourController);
|
OnAssign(behaviourController);
|
||||||
OnBehaviourControllerAssigned?.Invoke(this);
|
OnBehaviourControllerAssigned?.InvokeSafe(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +143,7 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
|||||||
_isActive = StateEnable.Enabled && (Parent?.IsActive ?? true);
|
_isActive = StateEnable.Enabled && (Parent?.IsActive ?? true);
|
||||||
|
|
||||||
if (previousActive != IsActive)
|
if (previousActive != IsActive)
|
||||||
OnActiveChanged?.Invoke(this, previousActive);
|
OnActiveChanged?.InvokeSafe(this, previousActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UnassignInternal()
|
protected override void UnassignInternal()
|
||||||
@@ -159,8 +156,14 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
|||||||
{
|
{
|
||||||
base.InitializeInternal();
|
base.InitializeInternal();
|
||||||
_behaviourController ??= Factory.BehaviourControllerFactory.Instantiate(this);
|
_behaviourController ??= Factory.BehaviourControllerFactory.Instantiate(this);
|
||||||
|
_behaviourController.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<IHierarchyObject> GetEnumerator() => _children.GetEnumerator();
|
public UniverseObject()
|
||||||
|
{
|
||||||
|
_name = GetType().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IUniverseObject> GetEnumerator() => _children.GetEnumerator();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator();
|
||||||
}
|
}
|
@@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public readonly struct EngineTime(TimeSpan TimeSinceStart, TimeSpan TimeDelta)
|
public readonly struct UniverseTime(TimeSpan TimeSinceStart, TimeSpan TimeDelta)
|
||||||
{
|
{
|
||||||
public readonly TimeSpan TimeSinceStart = TimeSinceStart;
|
public readonly TimeSpan TimeSinceStart = TimeSinceStart;
|
||||||
public readonly TimeSpan DeltaSpan = TimeDelta;
|
public readonly TimeSpan DeltaSpan = TimeDelta;
|
@@ -1,6 +1,6 @@
|
|||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a <see cref="ICollider2D"/> with the shape of a <see cref="Circle"/>.
|
/// Represents a <see cref="ICollider2D"/> with the shape of a <see cref="Circle"/>.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using Syntriax.Engine.Core.Abstract;
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a 2D collider.
|
/// Represents a 2D collider.
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user