Add a simple EasingSystem
This commit is contained in:
parent
1ff7806c7a
commit
61625a4add
|
@ -1,5 +1,6 @@
|
||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AContentManager_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F607c842ed163400ca987bebdb007e915137000_003F2c_003F08ef808b_003FContentManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AContentManager_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F607c842ed163400ca987bebdb007e915137000_003F2c_003F08ef808b_003FContentManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F65134d3e6ebe417ebdb98f66cb6df17eb528_003Fd0_003F1dd51100_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameTime_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F607c842ed163400ca987bebdb007e915137000_003F19_003F2ed69731_003FGameTime_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameTime_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F607c842ed163400ca987bebdb007e915137000_003F19_003F2ed69731_003FGameTime_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGame_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F607c842ed163400ca987bebdb007e915137000_003Fe8_003Fc288a217_003FGame_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGame_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F607c842ed163400ca987bebdb007e915137000_003Fe8_003Fc288a217_003FGame_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APath_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf07be36dfaa4f47b843d44a6617c8b9d19e00_003Fab_003Ffafcbf34_003FPath_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APath_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf07be36dfaa4f47b843d44a6617c8b9d19e00_003Fab_003Ffafcbf34_003FPath_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using MonoGameBlank2dStartKit.Core.Content;
|
using MonoGameBlank2dStartKit.Core.Content;
|
||||||
|
using MonoGameBlank2dStartKit.Core.Utils;
|
||||||
|
|
||||||
namespace MonoGameBlank2dStartKit.Core;
|
namespace MonoGameBlank2dStartKit.Core;
|
||||||
|
|
||||||
|
@ -19,6 +20,9 @@ public readonly record struct Mass(int Value);
|
||||||
|
|
||||||
public readonly record struct RotationSpeed(float Speed, float Amount = float.MaxValue, float Drag = 0)
|
public readonly record struct RotationSpeed(float Speed, float Amount = float.MaxValue, float Drag = 0)
|
||||||
{
|
{
|
||||||
|
public RotationSpeed(float speed, TimeSpan timeSpan) : this(speed, speed * timeSpan.SecFloat())
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly record struct Rotation(float Value, Vector2 Origin)
|
public readonly record struct Rotation(float Value, Vector2 Origin)
|
||||||
|
@ -32,3 +36,55 @@ public readonly record struct Rotation(float Value, Vector2 Origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly record struct Image(ImageId ImageId);
|
public readonly record struct Image(ImageId ImageId);
|
||||||
|
|
||||||
|
public interface IMovement
|
||||||
|
{
|
||||||
|
Position Start { get; init; }
|
||||||
|
Position Target { get; init; }
|
||||||
|
float DurationSec { get; init; }
|
||||||
|
float ProgressSec { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly record struct MoveLinearly(
|
||||||
|
Position Start,
|
||||||
|
Position Target,
|
||||||
|
float DurationSec,
|
||||||
|
float ProgressSec = 0f
|
||||||
|
) : IMovement;
|
||||||
|
|
||||||
|
public readonly record struct CubicEaseIn(
|
||||||
|
Position Start,
|
||||||
|
Position Target,
|
||||||
|
float DurationSec,
|
||||||
|
float ProgressSec = 0f
|
||||||
|
) : IMovement;
|
||||||
|
|
||||||
|
public readonly record struct CubicEaseOut(
|
||||||
|
Position Start,
|
||||||
|
Position Target,
|
||||||
|
float DurationSec,
|
||||||
|
float ProgressSec = 0f
|
||||||
|
) : IMovement;
|
||||||
|
|
||||||
|
public readonly record struct CubicEaseInOut(
|
||||||
|
Position Start,
|
||||||
|
Position Target,
|
||||||
|
float DurationSec,
|
||||||
|
float ProgressSec = 0f
|
||||||
|
) : IMovement;
|
||||||
|
|
||||||
|
public readonly record struct QuinticEaseIn(
|
||||||
|
Position Start,
|
||||||
|
Position Target,
|
||||||
|
float DurationSec,
|
||||||
|
float ProgressSec = 0f
|
||||||
|
) : IMovement;
|
||||||
|
|
||||||
|
public readonly record struct QuinticEaseOut(
|
||||||
|
Position Start,
|
||||||
|
Position Target,
|
||||||
|
float DurationSec,
|
||||||
|
float ProgressSec = 0f
|
||||||
|
) : IMovement;
|
||||||
|
|
||||||
|
public readonly record struct AddEntityOnStop();
|
|
@ -8,7 +8,6 @@ using Microsoft.Xna.Framework.Input;
|
||||||
using MonoGameBlank2dStartKit.Core.Content;
|
using MonoGameBlank2dStartKit.Core.Content;
|
||||||
using MonoGameBlank2dStartKit.Core.Systems;
|
using MonoGameBlank2dStartKit.Core.Systems;
|
||||||
using MoonTools.ECS;
|
using MoonTools.ECS;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
|
|
||||||
namespace MonoGameBlank2dStartKit.Core
|
namespace MonoGameBlank2dStartKit.Core
|
||||||
{
|
{
|
||||||
|
@ -21,6 +20,7 @@ namespace MonoGameBlank2dStartKit.Core
|
||||||
private TextureDrawSystem TextureDrawSystem { get; set; }
|
private TextureDrawSystem TextureDrawSystem { get; set; }
|
||||||
private VelocitySystem VelocitySystem { get; set; }
|
private VelocitySystem VelocitySystem { get; set; }
|
||||||
private RotationSystem RotationSystem { get; set; }
|
private RotationSystem RotationSystem { get; set; }
|
||||||
|
private EasingSystem EasingSystem { get; set; }
|
||||||
|
|
||||||
// Resources for drawing.
|
// Resources for drawing.
|
||||||
private readonly GraphicsDeviceManager graphicsDeviceManager;
|
private readonly GraphicsDeviceManager graphicsDeviceManager;
|
||||||
|
@ -94,6 +94,7 @@ namespace MonoGameBlank2dStartKit.Core
|
||||||
TextureDrawSystem = new TextureDrawSystem(World, _assets, _spriteBatch);
|
TextureDrawSystem = new TextureDrawSystem(World, _assets, _spriteBatch);
|
||||||
VelocitySystem = new VelocitySystem(World);
|
VelocitySystem = new VelocitySystem(World);
|
||||||
RotationSystem = new RotationSystem(World);
|
RotationSystem = new RotationSystem(World);
|
||||||
|
EasingSystem = new EasingSystem(World);
|
||||||
Scenarios.Basic(World, _assets);
|
Scenarios.Basic(World, _assets);
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
}
|
}
|
||||||
|
@ -114,6 +115,7 @@ namespace MonoGameBlank2dStartKit.Core
|
||||||
var elapsedGameTime = gameTime.ElapsedGameTime;
|
var elapsedGameTime = gameTime.ElapsedGameTime;
|
||||||
VelocitySystem.Update(elapsedGameTime);
|
VelocitySystem.Update(elapsedGameTime);
|
||||||
RotationSystem.Update(elapsedGameTime);
|
RotationSystem.Update(elapsedGameTime);
|
||||||
|
EasingSystem.Update(elapsedGameTime);
|
||||||
|
|
||||||
base.Update(gameTime);
|
base.Update(gameTime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using MonoGameBlank2dStartKit.Core.Content;
|
using MonoGameBlank2dStartKit.Core.Content;
|
||||||
using MoonTools.ECS;
|
using MoonTools.ECS;
|
||||||
|
@ -9,10 +10,15 @@ public static class Scenarios
|
||||||
public static void Basic(World world, Assets assets)
|
public static void Basic(World world, Assets assets)
|
||||||
{
|
{
|
||||||
var ball = world.CreateEntity();
|
var ball = world.CreateEntity();
|
||||||
world.Set(ball, new Position(new Vector2(10, 10)));
|
|
||||||
world.Set(ball, new Image(ImageId.Ball));
|
world.Set(ball, new Image(ImageId.Ball));
|
||||||
world.Set(ball, new Velocity(40f, 40f));
|
world.Set(ball, new MoveLinearly
|
||||||
|
{
|
||||||
|
Start = new Position(new Vector2(10, 10)),
|
||||||
|
Target = new Position(500, 300),
|
||||||
|
DurationSec = 1.5f,
|
||||||
|
});
|
||||||
|
// world.Set(ball, new Velocity(40f, 40f));
|
||||||
world.Set(ball, new Rotation(0, assets.GetTexture2D(ImageId.Ball)));
|
world.Set(ball, new Rotation(0, assets.GetTexture2D(ImageId.Ball)));
|
||||||
world.Set(ball, new RotationSpeed(3f, Drag: 0.03f));
|
world.Set(ball, new RotationSpeed(3f, TimeSpan.FromSeconds(1.5)));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,15 +17,17 @@ public class RotationSystem : MoonTools.ECS.System
|
||||||
|
|
||||||
public override void Update(TimeSpan delta)
|
public override void Update(TimeSpan delta)
|
||||||
{
|
{
|
||||||
|
float deltaSec = delta.SecFloat();
|
||||||
foreach (var entity in _filter.Entities)
|
foreach (var entity in _filter.Entities)
|
||||||
{
|
{
|
||||||
var currentRotation = World.Get<Rotation>(entity);
|
var currentRotation = World.Get<Rotation>(entity);
|
||||||
var rotationSpeed = World.Get<RotationSpeed>(entity);
|
var rotationSpeed = World.Get<RotationSpeed>(entity);
|
||||||
float change = rotationSpeed.Speed * delta.SecFloat();
|
float change = rotationSpeed.Speed * deltaSec;
|
||||||
World.Set(entity, currentRotation with { Value = currentRotation.Value + change });
|
World.Set(entity, currentRotation with { Value = currentRotation.Value + change });
|
||||||
|
|
||||||
var newSpeed = rotationSpeed.Speed - (rotationSpeed.Drag * delta.SecFloat());
|
float remainingRotation = rotationSpeed.Amount - change;
|
||||||
if (Math.Sign(newSpeed) != Math.Sign(rotationSpeed.Speed))
|
float newSpeed = rotationSpeed.Speed - (rotationSpeed.Drag * deltaSec);
|
||||||
|
if (Math.Sign(newSpeed) != Math.Sign(rotationSpeed.Speed) || remainingRotation <= 0)
|
||||||
{
|
{
|
||||||
World.Remove<RotationSpeed>(entity);
|
World.Remove<RotationSpeed>(entity);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +36,7 @@ public class RotationSystem : MoonTools.ECS.System
|
||||||
World.Set(entity, rotationSpeed with
|
World.Set(entity, rotationSpeed with
|
||||||
{
|
{
|
||||||
Speed = newSpeed,
|
Speed = newSpeed,
|
||||||
Amount = rotationSpeed.Amount - change,
|
Amount = remainingRotation,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue