/Assets/NGUI/Scripts/Internal/ActiveAnimation.cs
C# | 352 lines | 241 code | 54 blank | 57 comment | 104 complexity | f586ede7eef54a54e22bbcf7d9e96162 MD5 | raw file
1//----------------------------------------------
2// NGUI: Next-Gen UI kit
3// Copyright © 2011-2014 Tasharen Entertainment
4//----------------------------------------------
5
6#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_1 && !UNITY_4_2
7#define USE_MECANIM
8#endif
9
10using UnityEngine;
11using AnimationOrTween;
12using System.Collections.Generic;
13
14/// <summary>
15/// Mainly an internal script used by UIButtonPlayAnimation, but can also be used to call
16/// the specified function on the game object after it finishes animating.
17/// </summary>
18
19[AddComponentMenu("NGUI/Internal/Active Animation")]
20public class ActiveAnimation : MonoBehaviour
21{
22 /// <summary>
23 /// Active animation that resulted in the event notification.
24 /// </summary>
25
26 static public ActiveAnimation current;
27
28 /// <summary>
29 /// Event delegates called when the animation finishes.
30 /// </summary>
31
32 public List<EventDelegate> onFinished = new List<EventDelegate>();
33
34 // Deprecated functionality, kept for backwards compatibility
35 [HideInInspector] public GameObject eventReceiver;
36 [HideInInspector] public string callWhenFinished;
37
38 Animation mAnim;
39 Direction mLastDirection = Direction.Toggle;
40 Direction mDisableDirection = Direction.Toggle;
41 bool mNotify = false;
42
43#if USE_MECANIM
44 Animator mAnimator;
45 string mClip = "";
46
47 float playbackTime
48 {
49 get
50 {
51 AnimatorStateInfo state = mAnimator.GetCurrentAnimatorStateInfo(0);
52 return Mathf.Clamp01(state.normalizedTime);
53 }
54 }
55#endif
56
57 /// <summary>
58 /// Whether the animation is currently playing.
59 /// </summary>
60
61 public bool isPlaying
62 {
63 get
64 {
65 if (mAnim == null)
66 {
67#if USE_MECANIM
68 if (mAnimator != null)
69 {
70 if (mLastDirection == Direction.Reverse)
71 {
72 if (playbackTime == 0f) return false;
73 }
74 else if (playbackTime == 1f) return false;
75 return true;
76 }
77#endif
78 return false;
79 }
80
81 foreach (AnimationState state in mAnim)
82 {
83 if (!mAnim.IsPlaying(state.name)) continue;
84
85 if (mLastDirection == Direction.Forward)
86 {
87 if (state.time < state.length) return true;
88 }
89 else if (mLastDirection == Direction.Reverse)
90 {
91 if (state.time > 0f) return true;
92 }
93 else return true;
94 }
95 return false;
96 }
97 }
98
99 /// <summary>
100 /// Manually reset the active animation to the beginning.
101 /// </summary>
102
103 public void Reset ()
104 {
105 if (mAnim != null)
106 {
107 foreach (AnimationState state in mAnim)
108 {
109 if (mLastDirection == Direction.Reverse) state.time = state.length;
110 else if (mLastDirection == Direction.Forward) state.time = 0f;
111 }
112 }
113#if USE_MECANIM
114 else if (mAnimator != null)
115 {
116 mAnimator.Play(mClip, 0, (mLastDirection == Direction.Reverse) ? 1f : 0f);
117 }
118#endif
119 }
120
121 /// <summary>
122 /// Event receiver is only kept for backwards compatibility purposes. It's removed on start if new functionality is used.
123 /// </summary>
124
125 void Start ()
126 {
127 if (eventReceiver != null && EventDelegate.IsValid(onFinished))
128 {
129 eventReceiver = null;
130 callWhenFinished = null;
131 }
132 }
133
134 /// <summary>
135 /// Notify the target when the animation finishes playing.
136 /// </summary>
137
138 void Update ()
139 {
140 float delta = RealTime.deltaTime;
141 if (delta == 0f) return;
142
143#if USE_MECANIM
144 if (mAnimator != null)
145 {
146 mAnimator.Update((mLastDirection == Direction.Reverse) ? -delta : delta);
147 if (isPlaying) return;
148 mAnimator.enabled = false;
149 enabled = false;
150 }
151 else if (mAnim != null)
152#else
153 if (mAnim != null)
154#endif
155 {
156 bool playing = false;
157
158 foreach (AnimationState state in mAnim)
159 {
160 if (!mAnim.IsPlaying(state.name)) continue;
161 float movement = state.speed * delta;
162 state.time += movement;
163
164 if (movement < 0f)
165 {
166 if (state.time > 0f) playing = true;
167 else state.time = 0f;
168 }
169 else
170 {
171 if (state.time < state.length) playing = true;
172 else state.time = state.length;
173 }
174 }
175
176 mAnim.Sample();
177 if (playing) return;
178 enabled = false;
179 }
180 else
181 {
182 enabled = false;
183 return;
184 }
185
186 if (mNotify)
187 {
188 mNotify = false;
189
190 current = this;
191 EventDelegate.Execute(onFinished);
192
193 // Deprecated functionality, kept for backwards compatibility
194 if (eventReceiver != null && !string.IsNullOrEmpty(callWhenFinished))
195 eventReceiver.SendMessage(callWhenFinished, SendMessageOptions.DontRequireReceiver);
196
197 current = null;
198
199 if (mDisableDirection != Direction.Toggle && mLastDirection == mDisableDirection)
200 NGUITools.SetActive(gameObject, false);
201 }
202 }
203
204 /// <summary>
205 /// Play the specified animation.
206 /// </summary>
207
208 void Play (string clipName, Direction playDirection)
209 {
210 // Determine the play direction
211 if (playDirection == Direction.Toggle)
212 playDirection = (mLastDirection != Direction.Forward) ? Direction.Forward : Direction.Reverse;
213
214 if (mAnim != null)
215 {
216 // We will sample the animation manually so that it works when the time is paused
217 enabled = true;
218 mAnim.enabled = false;
219
220 bool noName = string.IsNullOrEmpty(clipName);
221
222 // Play the animation if it's not playing already
223 if (noName)
224 {
225 if (!mAnim.isPlaying) mAnim.Play();
226 }
227 else if (!mAnim.IsPlaying(clipName))
228 {
229 mAnim.Play(clipName);
230 }
231
232 // Update the animation speed based on direction -- forward or back
233 foreach (AnimationState state in mAnim)
234 {
235 if (string.IsNullOrEmpty(clipName) || state.name == clipName)
236 {
237 float speed = Mathf.Abs(state.speed);
238 state.speed = speed * (int)playDirection;
239
240 // Automatically start the animation from the end if it's playing in reverse
241 if (playDirection == Direction.Reverse && state.time == 0f) state.time = state.length;
242 else if (playDirection == Direction.Forward && state.time == state.length) state.time = 0f;
243 }
244 }
245
246 // Remember the direction for disable checks in Update()
247 mLastDirection = playDirection;
248 mNotify = true;
249 mAnim.Sample();
250 }
251#if USE_MECANIM
252 else if (mAnimator != null)
253 {
254 if (enabled && isPlaying)
255 {
256 if (mClip == clipName)
257 {
258 mLastDirection = playDirection;
259 return;
260 }
261 }
262
263 enabled = true;
264 mNotify = true;
265 mLastDirection = playDirection;
266 mClip = clipName;
267 mAnimator.Play(mClip, 0, (playDirection == Direction.Forward) ? 0f : 1f);
268
269 // NOTE: If you are getting a message "Animator.GotoState: HealthState could not be found"
270 // it means that you chose a state name that doesn't exist in the Animator window.
271 }
272#endif
273 }
274
275 /// <summary>
276 /// Play the specified animation on the specified object.
277 /// </summary>
278
279 static public ActiveAnimation Play (Animation anim, string clipName, Direction playDirection,
280 EnableCondition enableBeforePlay, DisableCondition disableCondition)
281 {
282 if (!NGUITools.GetActive(anim.gameObject))
283 {
284 // If the object is disabled, don't do anything
285 if (enableBeforePlay != EnableCondition.EnableThenPlay) return null;
286
287 // Enable the game object before animating it
288 NGUITools.SetActive(anim.gameObject, true);
289
290 // Refresh all panels right away so that there is no one frame delay
291 UIPanel[] panels = anim.gameObject.GetComponentsInChildren<UIPanel>();
292 for (int i = 0, imax = panels.Length; i < imax; ++i) panels[i].Refresh();
293 }
294
295 ActiveAnimation aa = anim.GetComponent<ActiveAnimation>();
296 if (aa == null) aa = anim.gameObject.AddComponent<ActiveAnimation>();
297 aa.mAnim = anim;
298 aa.mDisableDirection = (Direction)(int)disableCondition;
299 aa.onFinished.Clear();
300 aa.Play(clipName, playDirection);
301 return aa;
302 }
303
304 /// <summary>
305 /// Play the specified animation.
306 /// </summary>
307
308 static public ActiveAnimation Play (Animation anim, string clipName, Direction playDirection)
309 {
310 return Play(anim, clipName, playDirection, EnableCondition.DoNothing, DisableCondition.DoNotDisable);
311 }
312
313 /// <summary>
314 /// Play the specified animation.
315 /// </summary>
316
317 static public ActiveAnimation Play (Animation anim, Direction playDirection)
318 {
319 return Play(anim, null, playDirection, EnableCondition.DoNothing, DisableCondition.DoNotDisable);
320 }
321
322#if USE_MECANIM
323 /// <summary>
324 /// Play the specified animation on the specified object.
325 /// </summary>
326
327 static public ActiveAnimation Play (Animator anim, string clipName, Direction playDirection,
328 EnableCondition enableBeforePlay, DisableCondition disableCondition)
329 {
330 if (!NGUITools.GetActive(anim.gameObject))
331 {
332 // If the object is disabled, don't do anything
333 if (enableBeforePlay != EnableCondition.EnableThenPlay) return null;
334
335 // Enable the game object before animating it
336 NGUITools.SetActive(anim.gameObject, true);
337
338 // Refresh all panels right away so that there is no one frame delay
339 UIPanel[] panels = anim.gameObject.GetComponentsInChildren<UIPanel>();
340 for (int i = 0, imax = panels.Length; i < imax; ++i) panels[i].Refresh();
341 }
342
343 ActiveAnimation aa = anim.GetComponent<ActiveAnimation>();
344 if (aa == null) aa = anim.gameObject.AddComponent<ActiveAnimation>();
345 aa.mAnimator = anim;
346 aa.mDisableDirection = (Direction)(int)disableCondition;
347 aa.onFinished.Clear();
348 aa.Play(clipName, playDirection);
349 return aa;
350 }
351#endif
352}