/// <summary>Send a path tween to the given waypoint. /// Has no effect if this is not a path tween. /// <para>BEWARE, this is a special utility method: /// it works only with Linear eases. Also, the lookAt direction might be wrong after calling this and might need to be set manually /// (because it relies on a smooth path movement and doesn't work well with jumps that encompass dramatic direction changes)</para></summary> /// <param name="waypointIndex">Waypoint index to reach /// (if higher than the max waypoint index the tween will simply go to the last one)</param> /// <param name="andPlay">If TRUE will play the tween after reaching the given waypoint, otherwise it will pause it</param> public static void GotoWaypoint(this Tween t, int waypointIndex, bool andPlay = false) { if (t == null) { if (Debugger.logPriority > 1) { Debugger.LogNullTween(t); } return; } else if (!t.active) { if (Debugger.logPriority > 1) { Debugger.LogInvalidTween(t); } return; } else if (t.isSequenced) { if (Debugger.logPriority > 1) { Debugger.LogNestedTween(t); } return; } TweenerCore <Vector3, Path, PathOptions> pathTween = t as TweenerCore <Vector3, Path, PathOptions>; if (pathTween == null) { if (Debugger.logPriority > 1) { Debugger.LogNonPathTween(t); } return; } if (!t.startupDone) { TweenManager.ForceInit(t); // Initialize the tween if it's not initialized already (required) } if (waypointIndex < 0) { waypointIndex = 0; } else if (waypointIndex > pathTween.changeValue.wps.Length - 1) { waypointIndex = pathTween.changeValue.wps.Length - 1; } // Find path percentage relative to given waypoint float wpLength = 0; // Total length from start to the given waypoint for (int i = 0; i < waypointIndex + 1; i++) { wpLength += pathTween.changeValue.wpLengths[i]; } float wpPerc = wpLength / pathTween.changeValue.length; // Convert to time taking eventual inverse direction into account bool useInversePosition = t.loopType == LoopType.Yoyo && (t.position < t.duration ? t.completedLoops % 2 != 0 : t.completedLoops % 2 == 0); if (useInversePosition) { wpPerc = 1 - wpPerc; } float to = (t.isComplete ? t.completedLoops - 1 : t.completedLoops) * t.duration + wpPerc * t.duration; TweenManager.Goto(t, to, andPlay); }
public static void GotoWaypoint(this Tween t, int waypointIndex, bool andPlay = false) { if (t == null) { if (Debugger.logPriority > 1) { Debugger.LogNullTween(t); } return; } if (!t.active) { if (Debugger.logPriority > 1) { Debugger.LogInvalidTween(t); } return; } if (t.isSequenced) { if (Debugger.logPriority > 1) { Debugger.LogNestedTween(t); } return; } TweenerCore <Vector3, Path, PathOptions> tweenerCore = t as TweenerCore <Vector3, Path, PathOptions>; if (tweenerCore == null) { if (Debugger.logPriority > 1) { Debugger.LogNonPathTween(t); } return; } if (!t.startupDone) { TweenManager.ForceInit(t); } if (waypointIndex < 0) { waypointIndex = 0; } else if (waypointIndex > tweenerCore.changeValue.wps.Length - 1) { waypointIndex = tweenerCore.changeValue.wps.Length - 1; } float num = 0f; for (int i = 0; i < waypointIndex + 1; i++) { num += tweenerCore.changeValue.wpLengths[i]; } float num2 = num / tweenerCore.changeValue.length; bool flag = t.loopType == LoopType.Yoyo && ((t.position < t.duration) ? (t.completedLoops % 2 != 0) : (t.completedLoops % 2 == 0)); if (flag) { num2 = 1f - num2; } float to = (float)(t.isComplete ? (t.completedLoops - 1) : t.completedLoops) * t.duration + num2 * t.duration; TweenManager.Goto(t, to, andPlay, UpdateMode.Goto); }
// =================================================================================== // METHODS --------------------------------------------------------------------------- // Returns TRUE if the tween needs to be killed static bool ApplyInternalCycle(Sequence s, float fromPos, float toPos, UpdateMode updateMode, bool useInverse, bool prevPosIsInverse, bool multiCycleStep = false) { bool wasPlaying = s.isPlaying; // Used to interrupt for loops in case a callback pauses a running Sequence bool isBackwardsUpdate = toPos < fromPos; // Debug.Log(Time.frameCount + " " + s.id + " " + (multiCycleStep ? "<color=#FFEC03>Multicycle</color> > " : "Cycle > ") + s.position + "/" + s.duration + " - s.isBackwards: " + s.isBackwards + ", useInverse/prevInverse: " + useInverse + "/" + prevPosIsInverse + " - " + fromPos + " > " + toPos + " - UpdateMode: " + updateMode + ", isPlaying: " + s.isPlaying + ", completedLoops: " + s.completedLoops); if (isBackwardsUpdate) { int len = s._sequencedObjs.Count - 1; for (int i = len; i > -1; --i) { if (!s.active) { return(true); // Killed by some internal callback } if (!s.isPlaying && wasPlaying) { return(false); // Paused by internal callback } ABSSequentiable sequentiable = s._sequencedObjs[i]; if (sequentiable.sequencedEndPosition < toPos || sequentiable.sequencedPosition > fromPos) { continue; } if (sequentiable.tweenType == TweenType.Callback) { if (updateMode == UpdateMode.Update && prevPosIsInverse) { // Debug.Log("<color=#FFEC03>BACKWARDS Callback > " + s.id + " - s.isBackwards: " + s.isBackwards + ", useInverse/prevInverse: " + useInverse + "/" + prevPosIsInverse + " - " + fromPos + " > " + toPos + "</color>"); OnTweenCallback(sequentiable.onStart); } } else { // Nested Tweener/Sequence float gotoPos = toPos - sequentiable.sequencedPosition; // float gotoPos = (float)((decimal)toPos - (decimal)sequentiable.sequencedPosition); if (gotoPos < 0) { gotoPos = 0; } Tween t = (Tween)sequentiable; if (!t.startupDone) { continue; // since we're going backwards and this tween never started just ignore it } t.isBackwards = true; if (TweenManager.Goto(t, gotoPos, false, updateMode)) { // Nested tween failed. If it's the only tween and there's no callbacks mark for killing the whole sequence // (default behaviour in any case prior to v1.2.060)... if (DOTween.nestedTweenFailureBehaviour == NestedTweenFailureBehaviour.KillWholeSequence) { return(true); } if (s.sequencedTweens.Count == 1 && s._sequencedObjs.Count == 1 && !IsAnyCallbackSet(s)) { return(true); } // ...otherwise remove failed tween from Sequence and continue TweenManager.Despawn(t, false); s._sequencedObjs.RemoveAt(i); s.sequencedTweens.Remove(t); --i; --len; continue; } // Fixes nested callbacks not being called correctly if main sequence has loops and nested ones don't if (multiCycleStep && t.tweenType == TweenType.Sequence) { if (s.position <= 0 && s.completedLoops == 0) { t.position = 0; } else { bool toZero = s.completedLoops == 0 || s.isBackwards && (s.completedLoops < s.loops || s.loops == -1); if (t.isBackwards) { toZero = !toZero; } if (useInverse) { toZero = !toZero; } if (s.isBackwards && !useInverse && !prevPosIsInverse) { toZero = !toZero; } t.position = toZero ? 0 : t.duration; } } } } } else { int len = s._sequencedObjs.Count; for (int i = 0; i < len; ++i) { if (!s.active) { return(true); // Killed by some internal callback } if (!s.isPlaying && wasPlaying) { return(false); // Paused by internal callback } ABSSequentiable sequentiable = s._sequencedObjs[i]; // if (sequentiable.sequencedPosition > toPos || sequentiable.sequencedEndPosition < fromPos) continue; // Fix rare case with high FPS when a tween/callback might happen in same exact time as it's set // This fixes it but should check for backwards tweens and loops if ( sequentiable.sequencedPosition > toPos || sequentiable.sequencedPosition > 0 && sequentiable.sequencedEndPosition <= fromPos || sequentiable.sequencedPosition <= 0 && sequentiable.sequencedEndPosition < fromPos ) { continue; } if (sequentiable.tweenType == TweenType.Callback) { if (updateMode == UpdateMode.Update) { // Debug.Log("<color=#FFEC03>FORWARD Callback > " + s.id + " - s.isBackwards: " + s.isBackwards + ", useInverse/prevInverse: " + useInverse + "/" + prevPosIsInverse + " - " + fromPos + " > " + toPos + "</color>"); bool fire = !s.isBackwards && !useInverse && !prevPosIsInverse || s.isBackwards && useInverse && !prevPosIsInverse; if (fire) { OnTweenCallback(sequentiable.onStart); } } } else { // Nested Tweener/Sequence float gotoPos = toPos - sequentiable.sequencedPosition; // float gotoPos = (float)((decimal)toPos - (decimal)sequentiable.sequencedPosition); if (gotoPos < 0) { gotoPos = 0; } Tween t = (Tween)sequentiable; // Fix for final nested tween not calling OnComplete in some cases if (toPos >= sequentiable.sequencedEndPosition) { if (!t.startupDone) { TweenManager.ForceInit(t, true); } if (gotoPos < t.fullDuration) { gotoPos = t.fullDuration; } } // t.isBackwards = false; if (TweenManager.Goto(t, gotoPos, false, updateMode)) { // Nested tween failed. If it's the only tween and there's no callbacks mark for killing the whole sequence // (default behaviour in any case prior to v1.2.060)... if (DOTween.nestedTweenFailureBehaviour == NestedTweenFailureBehaviour.KillWholeSequence) { return(true); } if (s.sequencedTweens.Count == 1 && s._sequencedObjs.Count == 1 && !IsAnyCallbackSet(s)) { return(true); } // ...otherwise remove failed tween from Sequence and continue TweenManager.Despawn(t, false); s._sequencedObjs.RemoveAt(i); s.sequencedTweens.Remove(t); --i; --len; continue; } // Fixes nested callbacks not being called correctly if main sequence has loops and nested ones don't if (multiCycleStep && t.tweenType == TweenType.Sequence) { if (s.position <= 0 && s.completedLoops == 0) { t.position = 0; } else { bool toZero = s.completedLoops == 0 || !s.isBackwards && (s.completedLoops < s.loops || s.loops == -1); if (t.isBackwards) { toZero = !toZero; } if (useInverse) { toZero = !toZero; } if (s.isBackwards && !useInverse && !prevPosIsInverse) { toZero = !toZero; } t.position = toZero ? 0 : t.duration; } } } } } return(false); }
// =================================================================================== // METHODS --------------------------------------------------------------------------- // Returns TRUE if the tween needs to be killed static bool ApplyInternalCycle(Sequence s, float fromPos, float toPos, UpdateMode updateMode, bool useInverse, bool prevPosIsInverse, bool multiCycleStep = false) { bool isBackwardsUpdate = toPos < fromPos; // Debug.Log(Time.frameCount + " " + s.id + " " + (multiCycleStep ? "<color=#FFEC03>Multicycle</color> > " : "Cycle > ") + s.position + "/" + s.duration + " - s.isBackwards: " + s.isBackwards + ", useInverse/prevInverse: " + useInverse + "/" + prevPosIsInverse + " - " + fromPos + " > " + toPos + " - UpdateMode: " + updateMode + ", isPlaying: " + s.isPlaying + ", completedLoops: " + s.completedLoops); if (isBackwardsUpdate) { int len = s._sequencedObjs.Count - 1; for (int i = len; i > -1; --i) { if (!s.active) { return(true); // Killed by some internal callback } ABSSequentiable sequentiable = s._sequencedObjs[i]; if (sequentiable.sequencedEndPosition < toPos || sequentiable.sequencedPosition > fromPos) { continue; } if (sequentiable.tweenType == TweenType.Callback) { if (updateMode == UpdateMode.Update && prevPosIsInverse) { // Debug.Log("<color=#FFEC03>BACKWARDS Callback > " + s.id + " - s.isBackwards: " + s.isBackwards + ", useInverse/prevInverse: " + useInverse + "/" + prevPosIsInverse + " - " + fromPos + " > " + toPos + "</color>"); OnTweenCallback(sequentiable.onStart); } } else { // Nested Tweener/Sequence float gotoPos = toPos - sequentiable.sequencedPosition; // float gotoPos = (float)((decimal)toPos - (decimal)sequentiable.sequencedPosition); if (gotoPos < 0) { gotoPos = 0; } Tween t = (Tween)sequentiable; if (!t.startupDone) { continue; // since we're going backwards and this tween never started just ignore it } t.isBackwards = true; if (TweenManager.Goto(t, gotoPos, false, updateMode)) { return(true); } // Fixes nested callbacks not being called correctly if main sequence has loops and nested ones don't if (multiCycleStep && t.tweenType == TweenType.Sequence) { if (s.position <= 0 && s.completedLoops == 0) { t.position = 0; } else { bool toZero = s.completedLoops == 0 || s.isBackwards && (s.completedLoops < s.loops || s.loops == -1); if (t.isBackwards) { toZero = !toZero; } if (useInverse) { toZero = !toZero; } if (s.isBackwards && !useInverse && !prevPosIsInverse) { toZero = !toZero; } t.position = toZero ? 0 : t.duration; } } } } } else { int len = s._sequencedObjs.Count; for (int i = 0; i < len; ++i) { if (!s.active) { return(true); // Killed by some internal callback } ABSSequentiable sequentiable = s._sequencedObjs[i]; if (sequentiable.sequencedPosition > toPos || sequentiable.sequencedEndPosition < fromPos) { continue; } if (sequentiable.tweenType == TweenType.Callback) { if (updateMode == UpdateMode.Update) { // Debug.Log("<color=#FFEC03>FORWARD Callback > " + s.id + " - s.isBackwards: " + s.isBackwards + ", useInverse/prevInverse: " + useInverse + "/" + prevPosIsInverse + " - " + fromPos + " > " + toPos + "</color>"); bool fire = !s.isBackwards && !useInverse && !prevPosIsInverse || s.isBackwards && useInverse && !prevPosIsInverse; if (fire) { OnTweenCallback(sequentiable.onStart); } } } else { // Nested Tweener/Sequence float gotoPos = toPos - sequentiable.sequencedPosition; // float gotoPos = (float)((decimal)toPos - (decimal)sequentiable.sequencedPosition); if (gotoPos < 0) { gotoPos = 0; } Tween t = (Tween)sequentiable; // Fix for final nested tween not calling OnComplete in some cases if (toPos >= sequentiable.sequencedEndPosition) { if (!t.startupDone) { TweenManager.ForceInit(t, true); } if (gotoPos < t.fullDuration) { gotoPos = t.fullDuration; } } // t.isBackwards = false; if (TweenManager.Goto(t, gotoPos, false, updateMode)) { return(true); } // Fixes nested callbacks not being called correctly if main sequence has loops and nested ones don't if (multiCycleStep && t.tweenType == TweenType.Sequence) { if (s.position <= 0 && s.completedLoops == 0) { t.position = 0; } else { bool toZero = s.completedLoops == 0 || !s.isBackwards && (s.completedLoops < s.loops || s.loops == -1); if (t.isBackwards) { toZero = !toZero; } if (useInverse) { toZero = !toZero; } if (s.isBackwards && !useInverse && !prevPosIsInverse) { toZero = !toZero; } t.position = toZero ? 0 : t.duration; } } } } } return(false); }