monogame-moontools.ecs-temp.../MonoGameBlank2dStartKit/MonoGameBlank2dStartKit.Core/Systems/EasingSystem.cs

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 });
}
}
}