CrabUI
Loading...
Searching...
No Matches
CUIAnimation.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5using System.Diagnostics;
6using System.IO;
7
8using Barotrauma;
9using Microsoft.Xna.Framework;
10
11namespace CrabUI
12{
13 /// <summary>
14 /// WIP, can animate any property on any object
15 /// Can run back and forth in [0..1] interval and
16 /// interpolate any property between StartValue and EndValue
17 /// </summary>
18 public class CUIAnimation
19 {
20 internal static void InitStatic()
21 {
22 CUI.OnDispose += () => ActiveAnimations.Clear();
23 }
24
25 public static HashSet<CUIAnimation> ActiveAnimations = new();
26 /// <summary>
27 /// This is called in CUIUpdate
28 /// </summary>
29 internal static void UpdateAllAnimations(double time)
30 {
31 foreach (CUIAnimation animation in ActiveAnimations)
32 {
33 animation.Step(time);
34 }
35 }
36
37 public bool Debug { get; set; }
38 public static float StartLambda = 0.0f;
39 public static float EndLambda = 1.0f;
40
41
42 private object target;
43 /// <summary>
44 /// Object containing animated property
45 /// </summary>
46 public object Target
47 {
48 get => target;
49 set
50 {
51 target = value;
52 UpdateSetter();
53 }
54 }
55 private bool active;
56 public bool Active
57 {
58 get => active;
59 set
60 {
61 if (Blocked || active == value) return;
62 active = value;
63
64 if (active) ActiveAnimations.Add(this);
65 else ActiveAnimations.Remove(this);
66 ApplyValue();
67 }
68 }
69
70 /// <summary>
71 /// In seconds
72 /// </summary>
73 public double Duration
74 {
75 get => 1.0 / Speed * Timing.Step;
76 set
77 {
78 double steps = value / Timing.Step;
79 Speed = 1.0 / steps;
80 }
81 }
82
83 public double ReverseDuration
84 {
85 get => 1.0 / (BackSpeed ?? 0) * Timing.Step;
86 set
87 {
88 double steps = value / Timing.Step;
89 BackSpeed = 1.0 / steps;
90 }
91 }
92
93 /// <summary>
94 /// Will prevent it from starting
95 /// </summary>
96 public bool Blocked { get; set; }
97 /// <summary>
98 /// Progress of animation [0..1]
99 /// </summary>
100 public double Lambda { get; set; }
101 /// <summary>
102 /// Lambda increase per update step, calculated when you set Duration
103 /// </summary>
104 public double Speed { get; set; } = 0.01;
105 public double? BackSpeed { get; set; }
106 /// <summary>
107 /// If true animation won't stop when reaching end, it will change direction
108 /// </summary>
109 public bool Bounce { get; set; }
110 public bool Repeat { get; set; }
111 /// <summary>
112 /// Straight, Reverse
113 /// </summary>
114 public CUIDirection Direction { get; set; }
115 /// <summary>
116 /// Value will be interpolated between these values
117 /// </summary>
118 public object StartValue { get; set; }
119 public object EndValue { get; set; }
120
121 private string property;
122 private Action<object> setter;
123 private Type propertyType;
124 /// <summary>
125 /// Property name that is animated
126 /// </summary>
127 public string Property
128 {
129 get => property;
130 set
131 {
132 property = value;
133 UpdateSetter();
134 }
135 }
136
137 public event Action<CUIDirection> OnStop;
138 /// <summary>
139 /// You can set custon Interpolate function
140 /// </summary>
141 public Func<float, object> Interpolate
142 {
143 get => interpolate;
144 set
145 {
146 customInterpolate = value;
147 UpdateSetter();
148 }
149 }
150 private Func<float, object> customInterpolate;
151 private Func<float, object> interpolate;
152 //...
153 public Action<object> Convert<T>(Action<T> myActionT)
154 {
155 if (myActionT == null) return null;
156 else return new Action<object>(o => myActionT((T)o));
157 }
158
159
160 private void UpdateSetter()
161 {
162 if (Target != null && Property != null)
163 {
164 PropertyInfo pi = Target.GetType().GetProperty(Property);
165 if (pi == null)
166 {
167 CUI.Warning($"CUIAnimation couldn't find {Property} in {Target}");
168 return;
169 }
170
171 propertyType = pi.PropertyType;
172
173 interpolate = customInterpolate ?? ((l) => CUIInterpolate.Interpolate[propertyType].Invoke(StartValue, EndValue, l));
174
175
176 // https://coub.com/view/1mast0
177 if (propertyType == typeof(float))
178 {
179 setter = Convert<float>(pi.GetSetMethod()?.CreateDelegate<Action<float>>(Target));
180 }
181
182 if (propertyType == typeof(Color))
183 {
184 setter = Convert<Color>(pi.GetSetMethod()?.CreateDelegate<Action<Color>>(Target));
185 }
186 }
187 }
188
189
190 /// <summary>
191 /// Resumes animation in the same direction
192 /// </summary>
193 public void Start() => Active = true;
194 public void Stop()
195 {
196 Active = false;
197 OnStop?.Invoke(Direction);
198 }
199 /// <summary>
200 /// Set Direction to Straight and Start
201 /// </summary>
202 public void Forward()
203 {
204 Direction = CUIDirection.Straight;
205 Active = true;
206 }
207 /// <summary>
208 /// Set Direction to Reverse and Start
209 /// </summary>
210 public void Back()
211 {
212 Direction = CUIDirection.Reverse;
213 Active = true;
214 }
215
216 /// <summary>
217 /// Set Lambda to 0
218 /// </summary>
219 public void SetToStart() => Lambda = StartLambda;
220 /// <summary>
221 /// Set Lambda to 1
222 /// </summary>
223 public void SetToEnd() => Lambda = EndLambda;
224
225
226 private void UpdateState()
227 {
228 if (Direction == CUIDirection.Straight && Lambda >= EndLambda)
229 {
230 Lambda = EndLambda;
231 if (Bounce) Direction = CUIDirection.Reverse;
232 else if (Repeat) SetToStart();
233 else Stop();
234 }
235
236 if (Direction == CUIDirection.Reverse && Lambda <= StartLambda)
237 {
238 Lambda = StartLambda;
239 if (Bounce) Direction = CUIDirection.Straight;
240 else if (Repeat) SetToEnd();
241 else Stop();
242 }
243 }
244
245 public void ApplyValue()
246 {
247 if (interpolate == null) return;
248 object value = interpolate.Invoke((float)Lambda);
249 setter?.Invoke(value);
250 }
251
252 public void Step(double time)
253 {
254 UpdateState();
255 ApplyValue();
256 Lambda += Direction == CUIDirection.Straight ? Speed : -(BackSpeed ?? Speed);
257 if (Debug) LogStatus();
258 }
259
260 public void LogStatus() => CUI.Log($"Active:{Active} Direction:{Direction} Lambda:{Lambda}");
261
262 }
263}
WIP, can animate any property on any object Can run back and forth in [0..1] interval and interpolate...
double Speed
Lambda increase per update step, calculated when you set Duration.
void Back()
Set Direction to Reverse and Start.
void Start()
Resumes animation in the same direction.
Func< float, object > Interpolate
You can set custon Interpolate function.
double Duration
In seconds.
string Property
Property name that is animated.
object StartValue
Value will be interpolated between these values.
double Lambda
Progress of animation [0..1].
void SetToStart()
Set Lambda to 0.
CUIDirection Direction
Straight, Reverse.
bool Blocked
Will prevent it from starting.
bool Bounce
If true animation won't stop when reaching end, it will change direction.
void Forward()
Set Direction to Straight and Start.
object Target
Object containing animated property.
void SetToEnd()
Set Lambda to 1.