// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved. using UnityEngine; namespace HutongGames.PlayMaker.Actions { [Tooltip("Animate base action - DON'T USE IT!")] public abstract class CurveFsmAction : FsmStateAction { [Tooltip("Define animation time, scaling the curve to fit.")] public FsmFloat time; [Tooltip("If you define speed, your animation will speed up or slow down.")] public FsmFloat speed; [Tooltip("Delayed animation start.")] public FsmFloat delay; [Tooltip("Animation curve start from any time. If IgnoreCurveOffset is true the animation starts right after the state become entered.")] public FsmBool ignoreCurveOffset; [Tooltip("Optionally send an Event when the animation finishes.")] public FsmEvent finishEvent; [Tooltip("Ignore TimeScale. Useful if the game is paused.")] public bool realTime; private float startTime; private float currentTime; private float[] endTimes; private float lastTime; private float deltaTime; private float delayTime; private float[] keyOffsets; protected AnimationCurve[] curves; protected Calculation[] calculations; protected float[] resultFloats; protected float[] fromFloats; protected float[] toFloats; private float[] distances; protected bool finishAction = false; protected bool isRunning; protected bool looping; private bool start = false; private float largestEndTime = 0f; public enum Calculation{ None, AddToValue, SubtractFromValue, SubtractValueFromCurve, MultiplyValue, DivideValue, DivideCurveByValue, } public override void Reset() { finishEvent = null; realTime = false; time = new FsmFloat { UseVariable = true }; speed = new FsmFloat { UseVariable = true }; delay = new FsmFloat { UseVariable = true }; ignoreCurveOffset = new FsmBool{ Value = true}; resultFloats = new float[0]; fromFloats = new float[0]; toFloats = new float[0]; distances = new float[0]; endTimes = new float[0]; keyOffsets = new float[0]; curves = new AnimationCurve[0]; finishAction = false; start = false; } public override void OnEnter() { startTime = FsmTime.RealtimeSinceStartup; lastTime = FsmTime.RealtimeSinceStartup - startTime; deltaTime = 0f; currentTime = 0f; isRunning = false; finishAction = false; looping = false; delayTime = delay.IsNone ? 0f : delayTime = delay.Value; start = true; } protected void Init(){ endTimes = new float[curves.Length]; keyOffsets = new float[curves.Length]; largestEndTime = 0f; for(int i = 0; i 0) { keyOffsets[i] = curves[i].keys.Length > 0 ? (time.IsNone ? curves[i].keys[0].time : (time.Value/curves[i].keys[curves[i].length-1].time)*curves[i].keys[0].time) : 0f; currentTime = ignoreCurveOffset.IsNone ? 0f : (ignoreCurveOffset.Value ? keyOffsets[i] : 0f); if(!time.IsNone) endTimes[i] = time.Value; else endTimes[i] = curves[i].keys[curves[i].length-1].time; if(largestEndTime < endTimes[i]) largestEndTime = endTimes[i]; if(!looping) looping = ActionHelpers.IsLoopingWrapMode(curves[i].postWrapMode); } else { endTimes[i] = -1f; } } for(int i = 0; i 0f && endTimes[i] == -1f) endTimes[i] = largestEndTime; else { if(largestEndTime == 0f && endTimes[i] == -1f) { if(time.IsNone) endTimes[i] = 1f; else endTimes[i] = time.Value; } } } distances = new float[fromFloats.Length]; for(int i = 0; i= 0) { if(realTime){ deltaTime = (FsmTime.RealtimeSinceStartup - startTime) - lastTime; lastTime = FsmTime.RealtimeSinceStartup - startTime; delayTime -= deltaTime; } else { delayTime -= Time.deltaTime; } } else { isRunning = true; start = false; startTime = FsmTime.RealtimeSinceStartup; lastTime = FsmTime.RealtimeSinceStartup - startTime; } } if(isRunning && !finishAction){ if (realTime) { deltaTime = (FsmTime.RealtimeSinceStartup - startTime) - lastTime; lastTime = FsmTime.RealtimeSinceStartup - startTime; if(!speed.IsNone) currentTime += deltaTime*speed.Value; else currentTime += deltaTime; } else { if(!speed.IsNone) currentTime += Time.deltaTime*speed.Value; else currentTime += Time.deltaTime; } // update animation for(var k = 0; k 0) { if(calculations[k] != CurveFsmAction.Calculation.None){ switch(calculations[k]){ case Calculation.AddToValue: if(!time.IsNone) resultFloats[k] = fromFloats[k] + (distances[k]*(currentTime/time.Value) + curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time)); else resultFloats[k] = fromFloats[k] + (distances[k]*(currentTime/endTimes[k]) + curves[k].Evaluate(currentTime)); break; case Calculation.SubtractFromValue: if(!time.IsNone) resultFloats[k] = fromFloats[k] + (distances[k]*(currentTime/time.Value) - curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time)); else resultFloats[k] = fromFloats[k] + (distances[k]*(currentTime/endTimes[k]) - curves[k].Evaluate(currentTime)); break; case Calculation.SubtractValueFromCurve: if(!time.IsNone) resultFloats[k] = (curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time) - distances[k]*(currentTime/time.Value)) + fromFloats[k]; else resultFloats[k] = (curves[k].Evaluate(currentTime) - distances[k]*(currentTime/endTimes[k])) + fromFloats[k]; break; case Calculation.MultiplyValue: if(!time.IsNone) resultFloats[k] = (curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time) * distances[k]*(currentTime/time.Value)) + fromFloats[k]; else resultFloats[k] = (curves[k].Evaluate(currentTime) * distances[k]*(currentTime/endTimes[k])) + fromFloats[k]; break; case Calculation.DivideValue : if(!time.IsNone) resultFloats[k] = curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time) != 0f ? fromFloats[k]+ (distances[k]*(currentTime/time.Value))/curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time) : float.MaxValue; else resultFloats[k] = curves[k].Evaluate(currentTime) != 0 ? fromFloats[k] + (distances[k]*(currentTime/endTimes[k]))/curves[k].Evaluate(currentTime) : float.MaxValue; break; case Calculation.DivideCurveByValue : if(!time.IsNone) resultFloats[k] = fromFloats[k] != 0f ? curves[k].Evaluate((currentTime/time.Value)*curves[k].keys[curves[k].length-1].time)/(distances[k]*(currentTime/time.Value)) + fromFloats[k] : float.MaxValue; else resultFloats[k] = fromFloats[k] != 0 ? curves[k].Evaluate(currentTime)/(distances[k]*(currentTime/endTimes[k])) + fromFloats[k] : float.MaxValue; break; } } else { //Linear interpolation between color components if(!time.IsNone) resultFloats[k] = (fromFloats[k] + distances[k]*(currentTime/time.Value)); else resultFloats[k] = (fromFloats[k] + distances[k]*(currentTime/endTimes[k])); } } else { if(!time.IsNone) resultFloats[k] = (fromFloats[k] + distances[k]*(currentTime/time.Value)); else { if(largestEndTime == 0f){ resultFloats[k] = (fromFloats[k] + distances[k]*(currentTime/1f)); } else { resultFloats[k] = (fromFloats[k] + distances[k]*(currentTime/largestEndTime)); } } } } if(isRunning) { finishAction = true; for(int i = 0; i