Compare commits
5 Commits
8f8558a262
...
feb2a05aa3
Author | SHA1 | Date | |
---|---|---|---|
feb2a05aa3 | |||
cd30047e4a | |||
a3b03efd47 | |||
4213b3f8b5 | |||
d3fb612904 |
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
@@ -38,6 +39,19 @@ public static class BehaviourControllerExtensions
|
||||
public static T GetOrAddBehaviour<T>(this IBehaviourController behaviourController, params object?[]? args) where T : class, IBehaviour
|
||||
=> behaviourController.GetBehaviour<T>() ?? behaviourController.AddBehaviour<T>(args);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an existing <see cref="IBehaviour"/> of the specified type, or adds and returns the fallback type if it doesn't exist.
|
||||
/// </summary>
|
||||
/// <typeparam name="TOriginal">The type of <see cref="IBehaviour"/> to get.</typeparam>
|
||||
/// <typeparam name="TFallback">The type of <see cref="IBehaviour"/> to add. It must be assignable from <typeparamref name="TOriginal"/></typeparam>
|
||||
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to search in.</param>
|
||||
/// <param name="args">Optional arguments to pass to the constructor of the <see cref="IBehaviour"/> if a new one is added.</param>
|
||||
/// <returns>The existing or newly added <see cref="IBehaviour"/> of the specified type.</returns>
|
||||
public static TOriginal GetOrAddBehaviour<TOriginal, TFallback>(this IBehaviourController behaviourController, params object?[]? args)
|
||||
where TOriginal : class
|
||||
where TFallback : class, IBehaviour, TOriginal
|
||||
=> behaviourController.GetBehaviour<TOriginal>() ?? behaviourController.AddBehaviour<TFallback>(args);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively.
|
||||
/// </summary>
|
||||
@@ -81,6 +95,27 @@ public static class BehaviourControllerExtensions
|
||||
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>
|
||||
/// Gets all <see cref="IBehaviour"/>s of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively and stores them in the provided list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of <see cref="IBehaviour"/>s to get.</typeparam>
|
||||
/// <param name="behavioursInParent">The list to store the <see cref="IBehaviour"/>s.</param>
|
||||
public static void GetBehavioursInParent<T>(this IBehaviourController behaviourController, IList<T> behavioursInParent) where T : class
|
||||
{
|
||||
IBehaviourController? controller = behaviourController;
|
||||
List<T> cache = [];
|
||||
behavioursInParent.Clear();
|
||||
|
||||
while (controller is not null)
|
||||
{
|
||||
controller.GetBehaviours(cache);
|
||||
foreach (T behaviour in cache)
|
||||
behavioursInParent.Add(behaviour);
|
||||
|
||||
controller = controller.UniverseObject.Parent?.BehaviourController;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a <see cref="IBehaviour"/> of the specified type in it's <see cref="IUniverseObject"/>'s children recursively.
|
||||
/// </summary>
|
||||
@@ -120,4 +155,28 @@ public static class BehaviourControllerExtensions
|
||||
/// <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 ");
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="IBehaviour"/>s of the specified type in it's <see cref="IUniverseObject"/>'s children recursively and stores them in the provided list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of <see cref="IBehaviour"/>s to get.</typeparam>
|
||||
/// <param name="behavioursInChildren">The list to store the <see cref="IBehaviour"/>s.</param>
|
||||
public static void GetBehavioursInChildren<T>(this IBehaviourController behaviourController, IList<T> behavioursInChildren) where T : class
|
||||
{
|
||||
List<T> cache = [];
|
||||
behavioursInChildren.Clear();
|
||||
|
||||
TraverseChildrenForBehaviour(behaviourController.UniverseObject, behavioursInChildren, cache);
|
||||
}
|
||||
|
||||
private static void TraverseChildrenForBehaviour<T>(IUniverseObject universeObject, IList<T> behaviours, IList<T> cache) where T : class
|
||||
{
|
||||
universeObject.BehaviourController.GetBehaviours(cache);
|
||||
|
||||
foreach (T behaviour in cache)
|
||||
behaviours.Add(behaviour);
|
||||
|
||||
foreach (IUniverseObject child in universeObject)
|
||||
TraverseChildrenForBehaviour(child, behaviours, cache);
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,13 @@ public interface IPhysicsEngine2D
|
||||
/// <param name="deltaTime">The time step.</param>
|
||||
void Step(float deltaTime);
|
||||
|
||||
/// <summary>
|
||||
/// Advances the physics simulation by the specified time on a single <see cref="IRigidBody2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="rigidBody">The <see cref="IRigidBody2D"/> to be progressed individually.</param>
|
||||
/// <param name="deltaTime">The time step.</param>
|
||||
void StepIndividual(IRigidBody2D rigidBody, float deltaTime);
|
||||
|
||||
delegate void PhysicsIterationEventHandler(IPhysicsEngine2D sender, float iterationDeltaTime);
|
||||
delegate void PhysicsStepEventHandler(IPhysicsEngine2D sender, float stepDeltaTime);
|
||||
}
|
||||
|
@@ -49,37 +49,102 @@ public class PhysicsEngine2D : UniverseObject, IPhysicsEngine2D
|
||||
{
|
||||
ICollider2D? colliderX = colliderCollector.Behaviours[x];
|
||||
if (!colliderX.IsActive)
|
||||
return;
|
||||
continue;
|
||||
|
||||
for (int y = x + 1; y < colliderCollector.Behaviours.Count; y++)
|
||||
{
|
||||
ICollider2D? colliderY = colliderCollector.Behaviours[y];
|
||||
|
||||
if (!colliderY.IsActive)
|
||||
return;
|
||||
|
||||
if (colliderX.RigidBody2D == colliderY.RigidBody2D)
|
||||
continue;
|
||||
|
||||
ResolveColliders(colliderX, colliderY);
|
||||
}
|
||||
}
|
||||
|
||||
OnPhysicsIteration?.InvokeSafe(this, intervalDeltaTime);
|
||||
}
|
||||
|
||||
foreach (IPostPhysicsUpdate physicsPostUpdate in physicsPostUpdateCollector)
|
||||
physicsPostUpdate.PostPhysicsUpdate(deltaTime);
|
||||
|
||||
OnPhysicsStep?.InvokeSafe(this, deltaTime);
|
||||
}
|
||||
|
||||
public void StepIndividual(IRigidBody2D rigidBody, float deltaTime)
|
||||
{
|
||||
float intervalDeltaTime = deltaTime / IterationPerStep;
|
||||
|
||||
System.Collections.Generic.List<ICollider2D> childColliders = [];
|
||||
System.Collections.Generic.List<IPrePhysicsUpdate> physicsPreUpdates = [];
|
||||
System.Collections.Generic.List<IPhysicsUpdate> physicsUpdates = [];
|
||||
System.Collections.Generic.List<IPostPhysicsUpdate> physicsPostUpdates = [];
|
||||
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(childColliders);
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(physicsPreUpdates);
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(physicsUpdates);
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(physicsPostUpdates);
|
||||
|
||||
foreach (IPrePhysicsUpdate physicsPreUpdate in physicsPreUpdates)
|
||||
physicsPreUpdate.PrePhysicsUpdate(deltaTime);
|
||||
|
||||
foreach (IPhysicsUpdate physicsUpdate in physicsUpdates)
|
||||
physicsUpdate.PhysicsUpdate(deltaTime);
|
||||
|
||||
for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++)
|
||||
{
|
||||
StepRigidBody(rigidBody, intervalDeltaTime);
|
||||
|
||||
foreach (ICollider2D collider in childColliders)
|
||||
collider.Recalculate();
|
||||
|
||||
for (int x = 0; x < childColliders.Count; x++)
|
||||
{
|
||||
ICollider2D? colliderX = childColliders[x];
|
||||
if (!colliderX.IsActive)
|
||||
continue;
|
||||
|
||||
for (int y = 0; y < colliderCollector.Behaviours.Count; y++)
|
||||
{
|
||||
ICollider2D? colliderY = colliderCollector.Behaviours[y];
|
||||
|
||||
if (!colliderY.IsActive)
|
||||
continue;
|
||||
|
||||
ResolveColliders(colliderX, colliderY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IPostPhysicsUpdate physicsPostUpdate in physicsPostUpdates)
|
||||
physicsPostUpdate.PostPhysicsUpdate(deltaTime);
|
||||
}
|
||||
|
||||
private void ResolveColliders(ICollider2D colliderX, ICollider2D colliderY)
|
||||
{
|
||||
if (colliderX.RigidBody2D == colliderY.RigidBody2D)
|
||||
return;
|
||||
|
||||
bool bothCollidersAreTriggers = colliderX.IsTrigger && colliderX.IsTrigger == colliderY.IsTrigger;
|
||||
if (bothCollidersAreTriggers)
|
||||
continue;
|
||||
return;
|
||||
|
||||
bool bothCollidersAreStatic = (colliderX.RigidBody2D?.IsStatic ?? true) && (colliderY.RigidBody2D?.IsStatic ?? true);
|
||||
if (bothCollidersAreStatic)
|
||||
continue;
|
||||
return;
|
||||
|
||||
if (!collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information))
|
||||
return;
|
||||
|
||||
if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information))
|
||||
{
|
||||
if (colliderX.IsTrigger)
|
||||
{
|
||||
colliderX.Trigger(colliderY);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
else if (colliderY.IsTrigger)
|
||||
{
|
||||
colliderY.Trigger(colliderX);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (information.Detector == colliderX)
|
||||
@@ -95,17 +160,6 @@ public class PhysicsEngine2D : UniverseObject, IPhysicsEngine2D
|
||||
|
||||
collisionResolver?.Resolve(information);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnPhysicsIteration?.InvokeSafe(this, intervalDeltaTime);
|
||||
}
|
||||
|
||||
foreach (IPostPhysicsUpdate physicsPostUpdate in physicsPostUpdateCollector)
|
||||
physicsPostUpdate.PostPhysicsUpdate(deltaTime);
|
||||
|
||||
OnPhysicsStep?.InvokeSafe(this, deltaTime);
|
||||
}
|
||||
|
||||
private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime)
|
||||
{
|
||||
|
@@ -57,37 +57,96 @@ public class PhysicsEngine2DStandalone : IPhysicsEngine2D
|
||||
{
|
||||
ICollider2D? colliderX = colliders[x];
|
||||
if (!colliderX.IsActive)
|
||||
return;
|
||||
continue;
|
||||
|
||||
for (int y = x + 1; y < colliders.Count; y++)
|
||||
{
|
||||
ICollider2D? colliderY = colliders[y];
|
||||
|
||||
if (!colliderY.IsActive)
|
||||
return;
|
||||
|
||||
if (colliderX.RigidBody2D == colliderY.RigidBody2D)
|
||||
ResolveColliders(colliderX, colliderY);
|
||||
}
|
||||
}
|
||||
OnPhysicsIteration?.InvokeSafe(this, intervalDeltaTime);
|
||||
}
|
||||
OnPhysicsStep?.InvokeSafe(this, deltaTime);
|
||||
}
|
||||
|
||||
public void StepIndividual(IRigidBody2D rigidBody, float deltaTime)
|
||||
{
|
||||
float intervalDeltaTime = deltaTime / IterationPerStep;
|
||||
|
||||
List<ICollider2D> childColliders = [];
|
||||
List<IPrePhysicsUpdate> physicsPreUpdates = [];
|
||||
List<IPhysicsUpdate> physicsUpdates = [];
|
||||
List<IPostPhysicsUpdate> physicsPostUpdates = [];
|
||||
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(childColliders);
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(physicsPreUpdates);
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(physicsUpdates);
|
||||
rigidBody.BehaviourController.GetBehavioursInChildren(physicsPostUpdates);
|
||||
|
||||
foreach (IPrePhysicsUpdate physicsPreUpdate in physicsPreUpdates)
|
||||
physicsPreUpdate.PrePhysicsUpdate(deltaTime);
|
||||
|
||||
foreach (IPhysicsUpdate physicsUpdate in physicsUpdates)
|
||||
physicsUpdate.PhysicsUpdate(deltaTime);
|
||||
|
||||
for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++)
|
||||
{
|
||||
StepRigidBody(rigidBody, intervalDeltaTime);
|
||||
|
||||
foreach (ICollider2D collider in childColliders)
|
||||
collider.Recalculate();
|
||||
|
||||
for (int x = 0; x < childColliders.Count; x++)
|
||||
{
|
||||
ICollider2D? colliderX = childColliders[x];
|
||||
if (!colliderX.IsActive)
|
||||
continue;
|
||||
|
||||
for (int y = 0; y < colliders.Count; y++)
|
||||
{
|
||||
ICollider2D? colliderY = colliders[y];
|
||||
|
||||
if (!colliderY.IsActive)
|
||||
continue;
|
||||
|
||||
ResolveColliders(colliderX, colliderY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IPostPhysicsUpdate physicsPostUpdate in physicsPostUpdates)
|
||||
physicsPostUpdate.PostPhysicsUpdate(deltaTime);
|
||||
}
|
||||
|
||||
private void ResolveColliders(ICollider2D colliderX, ICollider2D colliderY)
|
||||
{
|
||||
if (colliderX.RigidBody2D == colliderY.RigidBody2D)
|
||||
return;
|
||||
|
||||
bool bothCollidersAreTriggers = colliderX.IsTrigger && colliderX.IsTrigger == colliderY.IsTrigger;
|
||||
if (bothCollidersAreTriggers)
|
||||
continue;
|
||||
return;
|
||||
|
||||
bool bothCollidersAreStatic = (colliderX.RigidBody2D?.IsStatic ?? true) && (colliderY.RigidBody2D?.IsStatic ?? true);
|
||||
if (bothCollidersAreStatic)
|
||||
continue;
|
||||
return;
|
||||
|
||||
if (!collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information))
|
||||
return;
|
||||
|
||||
if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information))
|
||||
{
|
||||
if (colliderX.IsTrigger)
|
||||
{
|
||||
colliderX.Trigger(colliderY);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
else if (colliderY.IsTrigger)
|
||||
{
|
||||
colliderY.Trigger(colliderX);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (information.Detector == colliderX)
|
||||
@@ -103,12 +162,6 @@ public class PhysicsEngine2DStandalone : IPhysicsEngine2D
|
||||
|
||||
collisionResolver?.Resolve(information);
|
||||
}
|
||||
}
|
||||
}
|
||||
OnPhysicsIteration?.InvokeSafe(this, intervalDeltaTime);
|
||||
}
|
||||
OnPhysicsStep?.InvokeSafe(this, deltaTime);
|
||||
}
|
||||
|
||||
private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime)
|
||||
{
|
||||
|
@@ -39,4 +39,69 @@ public static class TweenTransform2DExtensions
|
||||
float initialLocalRotation = transform2D.LocalRotation;
|
||||
return tweenManager.StartTween(duration, t => transform2D.LocalRotation = initialLocalRotation.Lerp(targetLocalRotation, t));
|
||||
}
|
||||
public static ITween TweenPositionAdditive(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D additivePosition)
|
||||
{
|
||||
Vector2D progressedPosition = Vector2D.Zero;
|
||||
return tweenManager.StartTween(duration, t =>
|
||||
{
|
||||
Vector2D displacement = Vector2D.Zero.Lerp(additivePosition, t) - progressedPosition;
|
||||
transform2D.Position += displacement;
|
||||
progressedPosition += displacement;
|
||||
});
|
||||
}
|
||||
|
||||
public static ITween TweenScaleAdditive(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D additiveScale)
|
||||
{
|
||||
Vector2D progressedScale = Vector2D.Zero;
|
||||
return tweenManager.StartTween(duration, t =>
|
||||
{
|
||||
Vector2D displacement = Vector2D.Zero.Lerp(additiveScale, t) - progressedScale;
|
||||
transform2D.Scale += displacement;
|
||||
progressedScale += displacement;
|
||||
});
|
||||
}
|
||||
|
||||
public static ITween TweenRotationAdditive(this ITransform2D transform2D, ITweenManager tweenManager, float duration, float additiveRotation)
|
||||
{
|
||||
float progressedRotation = 0f;
|
||||
return tweenManager.StartTween(duration, t =>
|
||||
{
|
||||
float displacement = 0f.Lerp(additiveRotation, t) - progressedRotation;
|
||||
transform2D.Rotation += displacement;
|
||||
progressedRotation += displacement;
|
||||
});
|
||||
}
|
||||
|
||||
public static ITween TweenLocalPositionAdditive(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D additiveLocalPosition)
|
||||
{
|
||||
Vector2D progressedLocalPosition = Vector2D.Zero;
|
||||
return tweenManager.StartTween(duration, t =>
|
||||
{
|
||||
Vector2D displacement = Vector2D.Zero.Lerp(additiveLocalPosition, t) - progressedLocalPosition;
|
||||
transform2D.LocalPosition += displacement;
|
||||
progressedLocalPosition += displacement;
|
||||
});
|
||||
}
|
||||
|
||||
public static ITween TweenLocalScaleAdditive(this ITransform2D transform2D, ITweenManager tweenManager, float duration, Vector2D additiveLocalScale)
|
||||
{
|
||||
Vector2D progressedLocalScale = Vector2D.Zero;
|
||||
return tweenManager.StartTween(duration, t =>
|
||||
{
|
||||
Vector2D displacement = Vector2D.Zero.Lerp(additiveLocalScale, t) - progressedLocalScale;
|
||||
transform2D.LocalScale += displacement;
|
||||
progressedLocalScale += displacement;
|
||||
});
|
||||
}
|
||||
|
||||
public static ITween TweenLocalRotationAdditive(this ITransform2D transform2D, ITweenManager tweenManager, float duration, float additiveLocalRotation)
|
||||
{
|
||||
float progressedLocalRotation = 0f;
|
||||
return tweenManager.StartTween(duration, t =>
|
||||
{
|
||||
float displacement = 0f.Lerp(additiveLocalRotation, t) - progressedLocalRotation;
|
||||
transform2D.LocalRotation += displacement;
|
||||
progressedLocalRotation += displacement;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user