-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathKModuleAnimate.cs
249 lines (207 loc) · 7.78 KB
/
KModuleAnimate.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/* * * * * * * * * * * * * * * */
/* Author: Dustin 'Kine' Judson
/*
/* This work is licensed under the
/* Creative Commons Attribution-ShareAlike 3.0 Unported License.
/*
/* To view a copy of this license, visit:
/* http://creativecommons.org/licenses/by-sa/3.0/
/*
/* A the following must be included with
/* any and all formats using this work or any
/* derivatives of this work:
/*
/* "Kine-Tech Animation Library by Dustin 'Kine' Judson is viewable at: https://github.com/KineMorto/KineTechAnimationLibrary"
/*
/* * * * * * * * * * * * * * * */
using UnityEngine;
/// <summary>
/// The base 'Super Class' for animation modules in the framework.
/// </summary>
public abstract class KModuleAnimate : PartModule
{
#region KSPFields
/// <summary>
/// The name of the animation to be played with this module.
/// </summary>
[KPartModuleFieldConfigurationDocumentation(
"nameOfAnimation",
"The name of the animation to be played with this module.")]
[KSPFieldDebug("AnimationName")]
public string AnimationName = string.Empty;
/// <summary>
/// When True the animation will be played in reverse.
/// </summary>
[KPartModuleFieldConfigurationDocumentation(
"False",
"When True the animation will be played in reverse.")]
[KSPFieldDebug("PlayInReverse")]
public bool PlayInReverse = false;
/// <summary>
/// When TRUE, the animation will not be updated.
/// </summary>
[KPartModuleFieldConfigurationDocumentation(
"False",
"When TRUE, the animation will not be updated.")]
[KSPFieldDebug("AnimationIsLocked?", isPersistant = true)]
public bool IsLocked = false;
/// <summary>
/// When TRUE, the Normalized Animation Time of the module is
/// interpolated between frames based on the 'LerpDampening'
/// value.
/// </summary>
[KPartModuleFieldConfigurationDocumentation(
"True",
"When TRUE, the Normalized Animation Time of the module is" +
"\n\t//interpolated between frames based on the 'LerpDampening'" +
"\n\t//value.")]
[KSPFieldDebug("UseInterpolation?")]
public bool UseInterpolation = true;
/// <summary>
/// The coefficient applied to Time.deltaTime that dictates
/// the speed our animation is played when interpolating,
/// as large changes in the normalized time could result in
/// undesired playback.
/// </summary>
[KPartModuleFieldConfigurationDocumentation(
"1",
"The coefficient applied to Time.deltaTime that dictates" +
"\n\t//the speed our animation is played when interpolating, " +
"\n\t//as large changes in the normalized time could result in" +
"\n\t//undesired playback.")]
[KSPFieldDebug("LerpDamp")]
public float LerpDampening = 1;
/// <summary>
/// The range at which interpolation starts playing at linear speed
/// to prevent it from taking infinite time to get to the target.
/// </summary>
[KPartModuleFieldConfigurationDocumentation(
"0.01",
"The range at which interpolation starts playing at linear speed" +
"\n\t//to prevent it from taking infinite time to get to the target")]
[KSPFieldDebug("LerpBoundary")]
public float LerpBoundary = 0.01f;
#endregion
#region Fields
protected AnimationState[] _AnimationStates;
[KSPFieldDebug("IsSetup?")]
private bool _IsSetup = false;
[KSPFieldDebug("SetupWasFailed?")]
private bool _SetupWasFailed = false;
/// <summary>
/// The Normalized Animation Time of the previous frame for interpolation purposes.
/// </summary>
[KSPFieldDebug("LastNormalTime")]
protected float LastNormalTime = 0;
/// <summary>
/// Cached iteration value so we do not have to make a new one every frame.
/// </summary>
private int it = 0;
#endregion
#region PartModule
public override void OnAwake()
{
base.OnAwake();
//If requirements are not met for the module
//Shut down immediately!
if (!KRequiresModuleAttribute.RequirementsMet(this))
{
Debug.LogWarning(
string.Format(
"Module '{0}' requires another module which is not present! Shutting down.",
this.name));
DestroyImmediate(this);
}
}
public override void OnStart(StartState state)
{
SetupAnimation();
if(!_SetupWasFailed)
OnModuleStateChanged(state);
}
public override void OnUpdate()
{
if(IsLocked || !_IsSetup || _SetupWasFailed)
return;
if(UseInterpolation) //Interpolate the time.
{
float DeltaTime = Mathf.Clamp(TimeWarp.deltaTime, 0.000000001f, 3600);
float NormalTime = Mathf.Clamp01(SolveNormalTime());
float NormalDistance = Mathf.Abs(LastNormalTime - NormalTime);
float LerpTime = (NormalDistance > LerpBoundary) ?
DeltaTime * LerpDampening :
(DeltaTime * LerpDampening) / (Mathf.Clamp(NormalDistance, 0.0000000001f, 9999999999) / LerpBoundary);
this.LastNormalTime = Mathf.Lerp(LastNormalTime, NormalTime, LerpTime);
}
else //Just roll with what we have.
{
this.LastNormalTime = Mathf.Clamp01(SolveNormalTime());
}
UpdateModule();
SetAllNormalTimeTo(LastNormalTime);
}
public override string GetInfo()
{
//Tell them who is coding :)
return "Powered by: [Kine-Tech Animation Library]";
}
#endregion
/// <summary>
/// Sets up the animation allowing for children to also setup.
/// </summary>
private void SetupAnimation()
{
if (_IsSetup)
return;
Animation[] anims = base.part.FindModelAnimators(this.AnimationName);
_AnimationStates = new AnimationState[anims.Length];
for (int it = 0; it < anims.Length; it++)
{
Animation current = anims[it];
AnimationState animationState = current[this.AnimationName];
animationState.speed = 0f;
current.Play(this.AnimationName);
_AnimationStates[it] = animationState;
}
if (!SetupModule())
this.enabled = false;
_IsSetup = true;
}
/// <summary>
/// Sets the AnimationStates within this animation to the
/// specified normal time while keeping the value clamped
/// between 0.0f and 1.0f.
/// </summary>
/// <param name="normalTime">The Normalized Animation Time to set our Animation States to.</param>
protected void SetAllNormalTimeTo(float normalTime)
{
if(this.IsLocked)
return;
normalTime = PlayInReverse ?
(Mathf.Clamp01(normalTime) * -1) + 1 :
(Mathf.Clamp01(normalTime));
for (it = 0; it < _AnimationStates.Length; it++)
_AnimationStates[it].normalizedTime = normalTime;
}
#region Abstract Interface
/// <summary>
/// Called when the state of the partmodule has changed.
/// </summary>
/// <param name="state">The new state of the module.</param>
protected virtual void OnModuleStateChanged(StartState state) { }
/// <summary>
/// Allows children to set themselves up initially.
/// </summary>
/// <returns>When TRUE, setup was successful; otherwise FALSE.</returns>
protected abstract bool SetupModule();
/// <summary>
/// Allows the child to update itself every frame
/// </summary>
protected abstract void UpdateModule();
/// <summary>
/// Allows the child to determine the normalized animation time.
/// </summary>
/// <returns>A value from 0.0f to 1.0f describing the current time of the animation.</returns>
protected abstract float SolveNormalTime();
#endregion
}