// =================================================================================== // 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, s); } } 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, s); } } } 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); }