Skip to content

Commit 9b30980

Browse files
committed
feat(tween): create tween system
1 parent ed8e9c9 commit 9b30980

File tree

9 files changed

+320
-1
lines changed

9 files changed

+320
-1
lines changed

SharpEngine.Core/Manager/TimerManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class TimerManager
1212
private readonly Dictionary<string, Timer> _timers = [];
1313

1414
/// <summary>
15-
/// Get All Musics
15+
/// Get All Timers
1616
/// </summary>
1717
public List<Timer> Timers => new(_timers.Values);
1818

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using SharpEngine.Core.Utils;
2+
using SharpEngine.Core.Utils.Tween;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
8+
namespace SharpEngine.Core.Manager
9+
{
10+
/// <summary>
11+
/// Class which manage tweens
12+
/// </summary>
13+
public class TweenManager
14+
{
15+
/// <summary>
16+
/// Gets or sets the collection of active tweens managed by this instance.
17+
/// </summary>
18+
/// <remarks>The list contains all currently tracked tween animations. Modifying this collection
19+
/// directly may affect the behavior of the tween manager.</remarks>
20+
public List<Tween> Tweens { get; set; } = [];
21+
22+
internal void Update(float delta)
23+
{
24+
for (var i = Tweens.Count - 1; i > -1; i--)
25+
{
26+
if (Tweens[i].Update(delta))
27+
Tweens.RemoveAt(i);
28+
}
29+
}
30+
}
31+
}

SharpEngine.Core/Utils/SeImGui/SeImGuiWindows.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static void CreateSeImGuiWindow(Window window)
4949
ImGui.Text($"Sounds Number : {window.SoundManager.Sounds.Count}");
5050
ImGui.Text($"Musics Number : {window.MusicManager.Musics.Count}");
5151
ImGui.Text($"Timers Number : {window.TimerManager.Timers.Count}");
52+
ImGui.Text($"Tweens Number : {window.TweenManager.Tweens.Count}");
5253
ImGui.Text($"Langs Number : {LangManager.Langs.Count}");
5354
ImGui.Text($"Saves Number : {SaveManager.Saves.Count}");
5455
ImGui.Text($"DataTable Number : {DataTableManager.DataTableNames.Count}");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace SharpEngine.Core.Utils.Tween;
6+
7+
internal record ColorStep(
8+
short RStep,
9+
short GStep,
10+
short BStep,
11+
short AStep
12+
);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace SharpEngine.Core.Utils.Tween
6+
{
7+
/// <summary>
8+
/// Represents an animation or value interpolation that transitions smoothly between states over time.
9+
/// </summary>
10+
/// <remarks>A Tween is typically used to animate properties or values in a gradual manner, such as moving
11+
/// an object, fading colors, or scaling elements. The specific behavior and configuration of the tween depend on
12+
/// the implementation and usage context.</remarks>
13+
public class Tween
14+
{
15+
/// <summary>
16+
/// Steps of Tween
17+
/// </summary>
18+
public List<TweenStep> Steps { get; set; }
19+
20+
/// <summary>
21+
/// Function which be called when Tween ends
22+
/// </summary>
23+
public Action? EndFunction { get; set; }
24+
25+
/// <summary>
26+
/// Gets or sets the zero-based index of the current step in the workflow.
27+
/// </summary>
28+
public int CurrentStepIndex { get; set; } = 0;
29+
30+
/// <summary>
31+
/// Initializes a new instance of the Tween class with the specified steps and an optional end function.
32+
/// </summary>
33+
/// <param name="steps">Steps</param>
34+
/// <param name="endFunction">End Function</param>
35+
public Tween(List<TweenStep> steps, Action? endFunction = null)
36+
{
37+
Steps = steps;
38+
EndFunction = endFunction;
39+
if (Steps.Count > 0)
40+
Steps[0].Launch();
41+
}
42+
43+
/// <summary>
44+
/// Updates the tween based on the elapsed time since the last update.
45+
/// </summary>
46+
/// <param name="deltaTime">Delta Time</param>
47+
/// <returns>If the tween has completed</returns>
48+
public bool Update(float deltaTime)
49+
{
50+
if (Steps.Count == 0)
51+
return true;
52+
var currentStep = Steps[CurrentStepIndex];
53+
if (currentStep.Update(deltaTime))
54+
{
55+
CurrentStepIndex++;
56+
if (CurrentStepIndex >= Steps.Count)
57+
{
58+
EndFunction?.Invoke();
59+
return true;
60+
}
61+
else
62+
Steps[CurrentStepIndex].Launch();
63+
}
64+
return false;
65+
}
66+
}
67+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using SharpEngine.Core.Manager;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq.Expressions;
5+
using System.Reflection;
6+
using System.Text;
7+
8+
namespace SharpEngine.Core.Utils.Tween
9+
{
10+
internal class TweenData<D, DStep> where D : notnull
11+
{
12+
public object Obj { get; set; }
13+
public Expression<Func<object, D>> Property { get; set; }
14+
public D From { get; set; }
15+
public D To { get; set; }
16+
public float Duration { get; set; }
17+
public D CurrentValue { get; set; } = default!;
18+
public DStep Step { get; set; } = default!;
19+
20+
public bool UseFrom { get; set; }
21+
22+
public TweenData(object obj, Expression<Func<object, D>> property, D from, D to, float duration, bool useFrom = true)
23+
{
24+
Obj = obj;
25+
Property = property;
26+
From = from;
27+
To = to;
28+
Duration = duration;
29+
UseFrom = useFrom;
30+
}
31+
32+
public void Launch()
33+
{
34+
CurrentValue = UseFrom ? From : Property.Compile()(Obj);
35+
Step = CurrentValue switch
36+
{
37+
float fFrom when To is float fTo => (DStep)(object)((fTo - fFrom) / Duration),
38+
int iFrom when To is int iTo => (DStep)(object)((iTo - iFrom) / Duration),
39+
Color cFrom when To is Color cTo => (DStep)(object)new ColorStep(
40+
(short)((cTo.R - cFrom.R) / Duration),
41+
(short)((cTo.G - cFrom.G) / Duration),
42+
(short)((cTo.B - cFrom.B) / Duration),
43+
(short)((cTo.A - cFrom.A) / Duration)
44+
),
45+
_ => throw new NotSupportedException("Unsupported type for tweening.")
46+
};
47+
48+
DebugManager.Log(LogLevel.LogInfo, $"Tween Launched: From = {From}, To = {To}, Duration = {Duration}, Step = {Step}");
49+
}
50+
51+
public void Update(float deltaTime)
52+
{
53+
if (Duration <= 0)
54+
{
55+
((PropertyInfo)((MemberExpression)Property.Body).Member).SetValue(Obj, To);
56+
return;
57+
}
58+
59+
CurrentValue = CurrentValue switch
60+
{
61+
float cVal when Step is float step => (D)(object)(cVal + step * deltaTime),
62+
int cVal when Step is int step => (D)(object)(cVal + (int)(step * deltaTime)),
63+
Color cVal when Step is ColorStep step => (D)(object)new Color(
64+
(byte)(cVal.R + step.RStep * deltaTime),
65+
(byte)(cVal.G + step.GStep * deltaTime),
66+
(byte)(cVal.B + step.BStep * deltaTime),
67+
(byte)(cVal.A + step.AStep * deltaTime)
68+
),
69+
_ => CurrentValue
70+
};
71+
72+
((PropertyInfo)((MemberExpression)Property.Body).Member).SetValue(Obj, CurrentValue);
73+
Duration -= deltaTime;
74+
}
75+
}
76+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq.Expressions;
4+
using System.Reflection;
5+
using System.Text;
6+
7+
namespace SharpEngine.Core.Utils.Tween
8+
{
9+
/// <summary>
10+
/// Represents a single step in a tween animation sequence.
11+
/// </summary>
12+
/// <remarks>A TweenStep typically encapsulates the logic for updating a portion of an animation over
13+
/// time. Instances of this class are commonly used within tweening frameworks to manage incremental changes to
14+
/// animated properties.</remarks>
15+
public class TweenStep
16+
{
17+
/// <summary>
18+
/// Duration of the step
19+
/// </summary>
20+
public float CurrentDuration { get; set; }
21+
22+
private readonly List<TweenData<float, float>> _floatTweens = [];
23+
private readonly List<TweenData<int, int>> _intTweens = [];
24+
private readonly List<TweenData<Color, ColorStep>> _colorTweens = [];
25+
26+
/// <summary>
27+
/// Initializes a new instance of the TweenStep class with the specified duration.
28+
/// </summary>
29+
/// <param name="duration">The duration, in seconds, for this tween step. Must be greater than or equal to zero.</param>
30+
public TweenStep(float duration)
31+
{
32+
CurrentDuration = duration;
33+
}
34+
35+
/// <summary>
36+
/// Add a float tween to the step
37+
/// </summary>
38+
/// <param name="entity">Entity</param>
39+
/// <param name="property">Property which be modified</param>
40+
/// <param name="to">Target Value</param>
41+
/// <param name="duration">Duration of the tween</param>
42+
/// <param name="from">Source Value</param>
43+
/// <returns>Tween Step</returns>
44+
public TweenStep Float(object entity, Expression<Func<object, float>> property, float to, float duration, float? from = null)
45+
{
46+
_floatTweens.Add(new TweenData<float, float>(entity, property, from ?? 0, to, duration, from is not null));
47+
return this;
48+
}
49+
50+
/// <summary>
51+
/// Add an int tween to the step
52+
/// </summary>
53+
/// <param name="entity">Entity</param>
54+
/// <param name="property">Property which be modified</param>
55+
/// <param name="to">Target Value</param>
56+
/// <param name="duration">Duration of the tween</param>
57+
/// <param name="from">Source Value</param>
58+
/// <returns>Tween Step</returns>
59+
public TweenStep Int(object entity, Expression<Func<object, int>> property, int to, float duration, int? from = null)
60+
{
61+
_intTweens.Add(new TweenData<int, int>(entity, property, from ?? 0, to, duration, from is not null));
62+
return this;
63+
}
64+
65+
/// <summary>
66+
/// Animates a color property of the specified entity from a starting value to a target value over the given
67+
/// duration.
68+
/// </summary>
69+
/// <param name="entity">The entity whose color property will be animated.</param>
70+
/// <param name="property">An expression that selects the color property of the entity to animate.</param>
71+
/// <param name="to">The target color value to animate to.</param>
72+
/// <param name="duration">The duration, in seconds, over which the animation occurs. Must be greater than zero.</param>
73+
/// <param name="from">The initial color value to animate from. If null, the current value of the property is used.</param>
74+
/// <returns>The current <see cref="TweenStep"/> instance, allowing for method chaining.</returns>
75+
public TweenStep Color(object entity, Expression<Func<object, Color>> property, Color to, float duration, Color? from = null)
76+
{
77+
_colorTweens.Add(new TweenData<Color, ColorStep>(entity, property, from ?? Utils.Color.White, to, duration, from is not null));
78+
return this;
79+
}
80+
81+
/// <summary>
82+
/// Update the tween step
83+
/// </summary>
84+
/// <param name="deltaTime">Delta time</param>
85+
/// <returns>If step ended</returns>
86+
public bool Update(float deltaTime)
87+
{
88+
CurrentDuration -= deltaTime;
89+
foreach (var floatTween in _floatTweens)
90+
floatTween.Update(deltaTime);
91+
foreach (var intTween in _intTweens)
92+
intTween.Update(deltaTime);
93+
foreach (var colorTween in _colorTweens)
94+
colorTween.Update(deltaTime);
95+
return CurrentDuration <= 0f;
96+
}
97+
98+
internal void Launch()
99+
{
100+
foreach (var floatTween in _floatTweens)
101+
floatTween.Launch();
102+
foreach (var intTween in _intTweens)
103+
intTween.Launch();
104+
foreach (var colorTween in _colorTweens)
105+
colorTween.Launch();
106+
}
107+
}
108+
}

SharpEngine.Core/Window.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ public bool Debug
142142
/// </summary>
143143
public TimerManager TimerManager { get; }
144144

145+
/// <summary>
146+
/// Tween Manager of Window
147+
/// </summary>
148+
public TweenManager TweenManager { get; }
149+
145150
/// <summary>
146151
/// ImGui Management of Window
147152
/// </summary>
@@ -281,6 +286,7 @@ public Window(
281286
SoundManager = new SoundManager();
282287
MusicManager = new MusicManager();
283288
TimerManager = new TimerManager();
289+
TweenManager = new TweenManager();
284290
CameraManager.SetScreenSize(screenSize);
285291

286292
if (fps != null)
@@ -443,6 +449,7 @@ public void Run()
443449
CurrentScene.Update(delta);
444450
CameraManager.Update(delta);
445451
TimerManager.Update(delta);
452+
TweenManager.Update(delta);
446453

447454
#endregion
448455

Testing/MyScene.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using SharpEngine.Core.Math;
77
using SharpEngine.Core.Renderer;
88
using SharpEngine.Core.Utils;
9+
using SharpEngine.Core.Utils.Tween;
910
using SharpEngine.Core.Widget;
1011

1112
namespace Testing;
@@ -40,4 +41,20 @@ public MyScene()
4041
e3.AddComponent(new CollisionComponent(new Vec2(50), drawDebug: true));
4142
AddEntity(e3);
4243
}
44+
45+
public override void OpenScene()
46+
{
47+
base.OpenScene();
48+
49+
Window?.TweenManager.Tweens.Add(new Tween([
50+
new TweenStep(5)
51+
.Float(Entities[0].GetComponentAs<TransformComponent>()!, x => ((TransformComponent)x).LocalRotation, 360, 5)
52+
.Float(Entities[0].GetComponentAs<TransformComponent>()!.LocalPosition, x => ((Vec2)x).X, 100, 5)
53+
.Float(Entities[0].GetComponentAs<TransformComponent>()!.LocalPosition, x => ((Vec2)x).Y, 100, 5),
54+
new TweenStep(10)
55+
.Float(Entities[0].GetComponentAs<TransformComponent>()!, x => ((TransformComponent)x).LocalRotation, 720, 5)
56+
.Float(Entities[0].GetComponentAs<TransformComponent>()!.LocalPosition, x => ((Vec2)x).X, 0, 5)
57+
.Float(Entities[0].GetComponentAs<TransformComponent>()!.LocalPosition, x => ((Vec2)x).Y, 0, 5),
58+
], () => DebugManager.Log(LogLevel.LogInfo, "FIN DU TWEEN")));
59+
}
4360
}

0 commit comments

Comments
 (0)