87 lines
2.7 KiB
C#
87 lines
2.7 KiB
C#
using System;
|
|
using MonoGameBlank2dStartKit.Core.Utils;
|
|
using MoonTools.ECS;
|
|
|
|
namespace MonoGameBlank2dStartKit.Core.Systems;
|
|
|
|
public class EasingSystem : MoonTools.ECS.System
|
|
{
|
|
private record EasingFilter(Filter Filter, Action<ReverseSpanEnumerator<Entity>, float> ProcessEntities);
|
|
|
|
private readonly EasingFilter[] _easingFilters;
|
|
|
|
public EasingSystem(World world) : base(world)
|
|
{
|
|
_easingFilters =
|
|
[
|
|
BuildEasingFilter<MoveLinearly>(p => p),
|
|
BuildEasingFilter<CubicEaseIn>(p => p * p * p),
|
|
BuildEasingFilter<CubicEaseOut>(p =>
|
|
{
|
|
float f = p - 1;
|
|
return (f * f * f) + 1;
|
|
}),
|
|
BuildEasingFilter<CubicEaseInOut>(p =>
|
|
{
|
|
if (p < 0.5)
|
|
{
|
|
return 4 * p * p * p;
|
|
}
|
|
|
|
float f = 2 * p - 2;
|
|
return 0.5f * f * f * f + 1;
|
|
}),
|
|
BuildEasingFilter<QuinticEaseIn>(p => p * p * p * p * p),
|
|
BuildEasingFilter<QuinticEaseOut>(p =>
|
|
{
|
|
float f = p - 1;
|
|
return (f * f * f * f * f) + 1;
|
|
}),
|
|
];
|
|
}
|
|
|
|
private EasingFilter BuildEasingFilter<T>(Func<float, float> easingFunc) where T : unmanaged, IMovement
|
|
{
|
|
var filter = FilterBuilder.Include<T>().Build();
|
|
return new EasingFilter(filter, (entities, deltaSec) =>
|
|
{
|
|
foreach (var entity in entities)
|
|
{
|
|
var currentMovement = World.Get<T>(entity);
|
|
ApplyMovement(deltaSec, entity, currentMovement, easingFunc);
|
|
}
|
|
});
|
|
}
|
|
|
|
public override void Update(TimeSpan delta)
|
|
{
|
|
float deltaSec = delta.SecFloat();
|
|
|
|
foreach (var easingFilter in _easingFilters)
|
|
{
|
|
easingFilter.ProcessEntities(easingFilter.Filter.Entities, deltaSec);
|
|
}
|
|
}
|
|
|
|
private void ApplyMovement<T>(
|
|
float deltaSec,
|
|
Entity entity,
|
|
T currentMovement,
|
|
Func<float, float> easingFunction) where T : unmanaged, IMovement
|
|
{
|
|
float newProgressSec = currentMovement.ProgressSec + deltaSec;
|
|
float percentComplete = newProgressSec / currentMovement.DurationSec;
|
|
if (percentComplete >= 1)
|
|
{
|
|
World.Set(entity, currentMovement.Target);
|
|
World.Remove<T>(entity);
|
|
}
|
|
else
|
|
{
|
|
var diff = currentMovement.Target.Vector2 - currentMovement.Start.Vector2;
|
|
var newPos = new Position((currentMovement.Start.Vector2) + (diff * easingFunction(percentComplete)));
|
|
World.Set(entity, newPos);
|
|
World.Set(entity, currentMovement with { ProgressSec = newProgressSec });
|
|
}
|
|
}
|
|
} |