2025-01-23 10:16:47 +08:00
#if TEST_FRAMEWORK_INSTALLED
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text.RegularExpressions ;
using System.Threading.Tasks ;
using JetBrains.Annotations ;
using NUnit.Framework ;
using PrimeTween ;
using UnityEngine ;
using UnityEngine.SceneManagement ;
using UnityEngine.TestTools ;
using Assert = NUnit . Framework . Assert ;
using AssertionException = UnityEngine . Assertions . AssertionException ;
using Object = UnityEngine . Object ;
using Random = UnityEngine . Random ;
using SuppressMessage = System . Diagnostics . CodeAnalysis . SuppressMessageAttribute ;
public partial class Tests {
[Test]
public void TweenTimeScaleWhileInSequence ( ) {
var t = Tween . Delay ( 0.01f ) ;
Sequence . Create ( t ) ;
expectCantManipulateTweenInsideSequence ( ) ;
t . timeScale = 2f ;
LogAssert . NoUnexpectedReceived ( ) ;
Tween . StopAll ( ) ;
}
[Test]
public async Task TweenTimeScaleOutlive ( ) {
{
var tween = Tween . Delay ( getDt ( ) / 2 ) ;
var timeScaleTween = Tween . TweenTimeScale ( tween , Random . value + 0.01f , float . MaxValue ) ;
await tween ;
Assert . IsFalse ( timeScaleTween . isAlive ) ;
}
{
var seq = Sequence . Create ( Tween . Delay ( getDt ( ) / 2 ) ) ;
var timeScaleTween = Tween . TweenTimeScale ( seq , Random . value + 0.01f , float . MaxValue ) ;
await seq ;
Assert . IsFalse ( timeScaleTween . isAlive ) ;
}
}
[Test]
public async Task TweenTimeScale ( ) {
var t = Tween . PositionZ ( transform , 10 , 1 ) ;
const float iniTimeScale = 0.9f ;
t . timeScale = iniTimeScale ;
Assert . AreEqual ( iniTimeScale , t . timeScale ) ;
const float targetTimeScale = 0.5f ;
await Tween . TweenTimeScale ( t , targetTimeScale , 0.001f ) ;
Assert . AreEqual ( targetTimeScale , t . timeScale ) ;
t . Complete ( ) ;
}
[UnityTest]
public IEnumerator QuaternionDefaultValue ( ) {
{
var q = Quaternion . Euler ( 0 , 0 , 45 ) ;
var def = new Quaternion ( ) ;
Assert . AreEqual ( Quaternion . identity . normalized , def . normalized ) ;
Assert . AreNotEqual ( Quaternion . Angle ( Quaternion . identity , q ) , Quaternion . Angle ( def , q ) ) ;
Assert . AreEqual ( Quaternion . Angle ( Quaternion . identity , q ) , Quaternion . Angle ( def . normalized , q ) ) ;
}
{
Tween t = default ;
var def = new Quaternion ( ) ;
int numCallback = 0 ;
t = Tween . Custom ( def , def , 0.01f , delegate {
numCallback + + ;
var startVal = t . tween . startValue . QuaternionVal ;
var endVal = t . tween . endValue . QuaternionVal ;
// Debug.Log($"{startVal}, {endVal}");
Assert . AreNotEqual ( def , startVal ) ;
Assert . AreNotEqual ( def , endVal ) ;
t . Stop ( ) ;
} ) ;
yield return t . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numCallback ) ;
}
}
/// This test can fail if Game window is set to 'Play Unfocused'
[UnityTest]
public IEnumerator StartValueIsAppliedOnFirstFrame ( ) {
const int iniVal = - 1 ;
float val = iniVal ;
const int startValue = 0 ;
Tween . Custom ( startValue , 1 , 0.01f , newVal = > val = newVal ) ;
Assert . AreEqual ( iniVal , val ) ;
yield return new WaitForEndOfFrame ( ) ;
Assert . AreEqual ( startValue , val ) ;
yield return new WaitForEndOfFrame ( ) ;
Assert . AreNotEqual ( startValue , val ) ;
}
[Test]
public void SafetyChecksEnabled ( ) {
#if ! PRIME_TWEEN_SAFETY_CHECKS
Assert . Inconclusive ( ) ;
#endif
}
[UnityTest]
public IEnumerator TweenIsDeadInOnComplete ( ) {
Tween t = default ;
t = Tween . Delay ( 0.01f , ( ) = > {
Assert . IsFalse ( t . isAlive ) ;
for ( int i = 0 ; i < 6 ; i + + ) {
expectIsDeadError ( ) ;
}
Assert . AreEqual ( 0 , t . elapsedTime ) ;
Assert . AreEqual ( 0 , t . elapsedTimeTotal ) ;
Assert . AreEqual ( 0 , t . progress ) ;
Assert . AreEqual ( 0 , t . progressTotal ) ;
Assert . AreEqual ( 0 , t . duration ) ;
Assert . AreEqual ( 0 , t . durationTotal ) ;
} ) ;
yield return t . ToYieldInstruction ( ) ;
}
static void expectIsDeadError ( bool isCreated = true ) = > LogAssert . Expect ( LogType . Error , new Regex ( isCreated ? Constants . isDeadMessage : "Tween or Sequence is not created properly." ) ) ;
[Test]
public void ShakeDuplication1 ( ) {
var s1 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f , startDelay : 0.1f ) ;
var s2 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f ) ;
Assert . IsTrue ( s1 . isAlive ) ;
Assert . IsTrue ( s2 . isAlive ) ;
}
[UnityTest]
public IEnumerator ShakeDuplication2 ( ) {
var s1 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f ) ;
Assert . IsTrue ( s1 . isAlive ) ;
var s2 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f ) ;
Assert . IsTrue ( s1 . isAlive ) ;
yield return null ;
// because two shakes are started the same frame, the first one completes the second one
Assert . IsTrue ( s1 . isAlive ) ;
Assert . IsTrue ( s2 . isAlive ) ;
}
[UnityTest]
public IEnumerator ShakeDuplication3 ( ) {
var s1 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f ) ;
yield return null ;
var s2 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f ) ;
yield return null ;
Assert . IsTrue ( s1 . isAlive ) ;
Assert . IsTrue ( s2 . isAlive ) ;
}
[UnityTest]
public IEnumerator ShakeDuplication4 ( ) {
const float startDelay = 0.05f ;
var s1 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f , startDelay : startDelay ) ;
var s2 = Tween . ShakeLocalPosition ( transform , Vector3 . one , 0.1f , startDelay : 0.1f ) ;
yield return Tween . Delay ( startDelay + Time . deltaTime ) . ToYieldInstruction ( ) ;
Assert . IsTrue ( s1 . isAlive ) ;
Assert . IsTrue ( s2 . isAlive ) ;
}
[UnityTest]
public IEnumerator ShakeDuplication5 ( ) {
var target = new GameObject ( nameof ( ShakeDuplication5 ) ) . transform ;
target . localPosition = new Vector3 ( Random . value , Random . value , Random . value ) ;
var iniPos = target . localPosition ;
var s1 = Tween . ShakeLocalPosition ( target , Vector3 . one , 0.1f ) ;
var seq = Sequence . Create ( s1 ) ;
Assert . IsTrue ( s1 . isAlive ) ;
var s2 = Tween . ShakeLocalPosition ( target , Vector3 . one , 0.1f ) ;
Assert . IsTrue ( s1 . isAlive ) ;
Assert . IsTrue ( seq . isAlive ) ;
Assert . IsTrue ( s2 . isAlive ) ;
Assert . IsTrue ( s1 . tween . startFromCurrent ) ;
Assert . IsTrue ( s2 . tween . startFromCurrent ) ;
yield return null ;
Assert . IsTrue ( s1 . isAlive ) ;
Assert . IsTrue ( seq . isAlive ) ;
Assert . IsTrue ( s2 . isAlive ) ;
Assert . IsFalse ( s1 . tween . startFromCurrent ) ;
Assert . IsFalse ( s2 . tween . startFromCurrent ) ;
Assert . AreEqual ( iniPos , s1 . tween . startValue . Vector3Val ) ;
Assert . AreEqual ( iniPos , s2 . tween . startValue . Vector3Val ) ;
}
[Test]
public void ShakeDuplicationDestroyedTarget ( ) {
var target = new GameObject ( nameof ( ShakeDuplicationDestroyedTarget ) ) . transform ;
Tween . ShakeLocalPosition ( target , Vector3 . one , 0.1f ) ;
Object . DestroyImmediate ( target . gameObject ) ;
Tween . ShakeLocalPosition ( target , Vector3 . one , 0.1f ) ;
expectTargetIsNull ( ) ;
}
static void expectTargetIsNull ( ) = > LogAssert . Expect ( LogType . Error , new Regex ( "Tween's target is null" ) ) ;
[UnityTest]
public IEnumerator FramePacing ( ) {
Tween . StopAll ( ) ;
2025-05-15 10:40:15 +08:00
const int fps = 120 ;
2025-01-23 10:16:47 +08:00
Application . targetFrameRate = fps ;
QualitySettings . vSyncCount = 0 ;
Assert . AreEqual ( fps , Application . targetFrameRate ) ;
yield return null ;
{
var go = new GameObject ( ) ;
go . AddComponent < FramePacingTest > ( ) ;
while ( go ! = null ) {
yield return null ;
}
}
Application . targetFrameRate = targetFrameRate ;
yield return null ;
}
#if UNITY_EDITOR
[Test]
public void GenerateCode ( ) {
const string path = "Packages/com.kyrylokuzyk.primetween/Editor/CodeGenerator.asset" ;
var cg = UnityEditor . AssetDatabase . LoadAssetAtPath < CodeGenerator > ( path ) ;
cg . generateAllMethods ( ) ;
}
#endif
[Test]
public void TweenCompleteInvokeOnCompleteParameter ( ) {
{
int numCompleted = 0 ;
var t = Tween . Scale ( transform , 1.5f , 0.01f ) . OnComplete ( ( ) = > numCompleted + + ) ;
t . Complete ( ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
t . Complete ( ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
}
/ * {
int numCompleted = 0 ;
var t = Tween . Scale ( transform , 1.5f , 0.01f ) . OnComplete ( ( ) = > numCompleted + + ) ;
t . Complete ( false ) ;
Assert . AreEqual ( 0 , numCompleted ) ;
t . Complete ( false ) ;
Assert . AreEqual ( 0 , numCompleted ) ;
t . Complete ( ) ;
Assert . AreEqual ( 0 , numCompleted ) ;
} * /
}
[Test]
public void IgnoreFromInScale ( ) {
var t = Tween . Scale ( transform , 1.5f , 0.01f ) ;
Assert . IsTrue ( t . tween . startFromCurrent ) ;
}
[UnityTest]
public IEnumerator FromToValues ( ) {
{
var duration = getDt ( ) * Random . Range ( 0.5f , 1.5f ) ;
var t = Tween . Custom ( 0 , 0 , duration , ease : Ease . Linear , onValueChange : delegate { } ) ;
while ( t . isAlive ) {
Assert . AreEqual ( t . elapsedTime , t . progress * duration , 0.001f ) ;
Assert . AreEqual ( t . interpolationFactor , t . progress ) ;
Assert . AreEqual ( t . interpolationFactor , t . progressTotal ) ;
yield return null ;
}
}
var from = Random . value ;
var to = Random . value ;
var data = new TweenSettings < float > ( from , to , 0.01f ) ;
{
var t = Tween . LocalPositionX ( transform , data ) ;
Assert . AreEqual ( from , t . tween . startValue . FloatVal ) ;
Assert . AreEqual ( to , t . tween . endValue . FloatVal ) ;
}
{
var t = Tween . Custom ( this , data , delegate { } ) ;
Assert . AreEqual ( from , t . tween . startValue . FloatVal ) ;
Assert . AreEqual ( to , t . tween . endValue . FloatVal ) ;
}
}
[UnityTest]
public IEnumerator TweenCompleteWhenInterpolationCompleted ( ) {
float curVal = 0f ;
var t = Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 2 , endDelay : 1f , cycleMode : CycleMode . Yoyo ) ;
while ( t . interpolationFactor < 1f ) {
yield return null ;
}
Assert . AreEqual ( 0 , t . cyclesDone ) ;
Assert . AreEqual ( 1f , curVal ) ;
t . Complete ( ) ;
Assert . AreEqual ( 0f , curVal ) ;
}
[Test]
public async Task CycleModeIncremental ( ) {
{
float curVal = 0f ;
await Tween . Custom ( this , 0f , 1f , 0.01f , ( _ , val ) = > curVal = val , cycles : 2 , cycleMode : CycleMode . Incremental ) ;
Assert . AreEqual ( 2f , curVal ) ;
}
{
float curVal = 0f ;
await Tween . Custom ( this , 0f , 1f , 0.01f , ( _ , val ) = > curVal = val , cycles : 4 , cycleMode : CycleMode . Incremental ) ;
Assert . AreEqual ( 4f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.01f , ( _ , val ) = > curVal = val , cycles : 2 , cycleMode : CycleMode . Incremental )
. Complete ( ) ;
Assert . AreEqual ( 2f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.01f , ( _ , val ) = > curVal = val , cycles : 4 , cycleMode : CycleMode . Incremental )
. Complete ( ) ;
Assert . AreEqual ( 4f , curVal ) ;
}
}
[Test]
public void TweenCompleteWithEvenCycles ( ) {
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 2 , cycleMode : CycleMode . Restart )
. Complete ( ) ;
Assert . AreEqual ( 1f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 4 , cycleMode : CycleMode . Restart )
. Complete ( ) ;
Assert . AreEqual ( 1f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 2 , cycleMode : CycleMode . Yoyo )
. Complete ( ) ;
Assert . AreEqual ( 0f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 4 , cycleMode : CycleMode . Yoyo )
. Complete ( ) ;
Assert . AreEqual ( 0f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 2 , cycleMode : CycleMode . Rewind )
. Complete ( ) ;
Assert . AreEqual ( 0f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 4 , cycleMode : CycleMode . Rewind )
. Complete ( ) ;
Assert . AreEqual ( 0f , curVal ) ;
}
}
[Test]
public void TweenCompleteWithOddCycles ( ) {
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 1 , cycleMode : CycleMode . Yoyo )
. Complete ( ) ;
Assert . AreEqual ( 1f , curVal ) ;
}
{
float curVal = 0f ;
Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 3 , cycleMode : CycleMode . Yoyo )
. Complete ( ) ;
Assert . AreEqual ( 1f , curVal ) ;
}
}
[UnityTest]
public IEnumerator TweenOnCompleteIsCalledOnceForTweenInSequence ( ) {
for ( int i = 0 ; i < 1 ; i + + ) {
loopBegin :
float curVal = 0f ;
int numCompleted = 0 ;
float duration = Mathf . Max ( minDuration , getDt ( ) ) * 10f ;
var t = Tween . Custom ( this , 0f , 1f , duration , ( _ , val ) = > curVal = val , cycles : 1 , cycleMode : CycleMode . Yoyo )
. OnComplete ( ( ) = > numCompleted + + ) ;
var s = t . Chain ( Tween . Delay ( duration ) ) ;
while ( true ) {
if ( ! t . isAlive ) {
goto loopBegin ;
}
if ( t . cyclesDone = = 1 ) {
break ;
}
yield return null ;
}
Assert . IsTrue ( t . isAlive ) ;
Assert . AreEqual ( 1 , t . tween . getCyclesDone ( ) ) ;
Assert . IsTrue ( t . tween . sequence . IsCreated ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
Assert . IsTrue ( s . isAlive ) ;
Assert . AreEqual ( 1f , curVal ) ;
s . Complete ( ) ;
Assert . AreEqual ( 1f , curVal ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
}
}
[Test]
public void TweenCompleteInSequence ( ) {
float curVal = 0f ;
var t = Tween . Custom ( this , 0f , 1f , 0.05f , ( _ , val ) = > curVal = val , cycles : 1 , cycleMode : CycleMode . Yoyo ) ;
var s = t . Chain ( Tween . Delay ( 0.05f ) ) ;
Assert . IsTrue ( t . isAlive ) ;
Assert . AreEqual ( 0 , t . tween . getCyclesDone ( ) ) ;
Assert . IsTrue ( t . tween . sequence . IsCreated ) ;
Assert . IsTrue ( s . isAlive ) ;
Assert . AreNotEqual ( 1f , curVal ) ;
s . Complete ( ) ;
Assert . AreEqual ( 1f , curVal ) ;
}
[Test]
public async Task AwaitExceptions ( ) {
2025-05-15 10:40:15 +08:00
expectTweenWasStoppedBecauseException ( ) ;
2025-01-23 10:16:47 +08:00
await Tween . Custom ( this , 0f , 1f , 1f , delegate {
throw new Exception ( ) ;
} ) ;
}
[UnityTest]
public IEnumerator CoroutineEnumeratorNotEnumeratedToTheEnd ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
var t = Tween . Delay ( TweenSettings . minDuration * 100 ) ;
var e = t . ToYieldInstruction ( ) ;
Assert . IsTrue ( e . MoveNext ( ) ) ;
yield return e . Current ;
Assert . IsTrue ( t . isAlive ) ;
while ( t . isAlive ) {
yield return null ;
}
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
testCompletedCorEnumerator ( e ) ;
}
[UnityTest]
public IEnumerator CoroutineEnumeratorInfiniteTween ( ) {
{
var t = Tween . Position ( transform , Vector3 . one , getDt ( ) , cycles : - 1 ) ;
Tween . Delay ( getDt ( ) * 5f ) . OnComplete ( ( ) = > t . Stop ( ) ) ;
yield return t . ToYieldInstruction ( ) ;
}
{
var t = Tween . Position ( transform , Vector3 . one , getDt ( ) , cycles : - 1 ) ;
Tween . Delay ( getDt ( ) * 5f ) . OnComplete ( ( ) = > t . Complete ( ) ) ;
yield return t . ToYieldInstruction ( ) ;
}
}
[UnityTest]
public IEnumerator CoroutineEnumeratorMultipleToYieldInstruction ( ) {
var t = Tween . Delay ( 0.01f ) ;
var e = t . ToYieldInstruction ( ) ;
Assert . Throws < AssertionException > ( ( ) = > t . ToYieldInstruction ( ) ) ;
t . Complete ( ) ;
yield return e ;
Assert . IsFalse ( t . isAlive ) ;
testCompletedCorEnumerator ( e ) ;
}
[UnityTest]
public IEnumerator CoroutineEnumeratorUsingDead ( ) {
var t = Tween . Delay ( 0.01f ) ;
var e = t . ToYieldInstruction ( ) ;
yield return e ;
Assert . IsFalse ( t . isAlive ) ;
testCompletedCorEnumerator ( e ) ;
}
static void testCompletedCorEnumerator ( IEnumerator e ) {
Assert . IsFalse ( e . MoveNext ( ) ) ;
Assert . Throws < AssertionException > ( ( ) = > {
_ = e . Current ;
} ) ;
Assert . Throws < NotSupportedException > ( ( ) = > e . Reset ( ) ) ;
}
[UnityTest]
public IEnumerator YieldInstructionsClash2 ( ) {
var test = new GameObject ( ) . AddComponent < YieldInstructionsClash > ( ) ;
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while ( test ! = null ) {
yield return null ;
}
}
[UnityTest]
public IEnumerator YieldInstructionsClash ( ) {
Application . targetFrameRate = 100 ;
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
for ( int i = 0 ; i < 1 ; i + + ) {
{
var t1 = Tween . Delay ( minDuration ) ;
int frameStart = Time . frameCount ;
yield return t1 . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , Time . frameCount - frameStart ) ;
Assert . IsFalse ( t1 . isAlive ) ;
var t2 = Tween . Delay ( minDuration ) ;
t2 . ToYieldInstruction ( ) ;
t2 . Complete ( ) ;
}
{
var t1 = Tween . Delay ( minDuration ) ;
t1 . ToYieldInstruction ( ) ;
yield return null ;
yield return null ;
Assert . IsFalse ( t1 . isAlive ) ;
var t2 = Tween . Delay ( minDuration ) ;
t2 . ToYieldInstruction ( ) ;
t2 . Complete ( ) ;
}
}
Application . targetFrameRate = targetFrameRate ;
}
[Test]
public void TweenDuplicateInSequence ( ) {
var t1 = Tween . Delay ( 0.1f ) ;
var t2 = Tween . Delay ( 0.1f ) ;
var s = t1 . Chain ( t2 ) ;
expectNestTweenTwiceError ( ) ;
s . Chain ( t1 ) ;
}
/ * [ UnityTest ]
public IEnumerator WaitStopFromValueChange2 ( ) {
Tween t = default ;
t = Tween . WaitWhile ( this , _ = > {
Assert . IsTrue ( t . isAlive ) ;
t . Stop ( ) ;
return true ;
} ) ;
yield return t . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator WaitCompleteFromValueChange2 ( ) {
Tween t = default ;
int numValueChanged = 0 ;
t = Tween . WaitWhile ( this , _ = > {
numValueChanged + + ;
switch ( numValueChanged ) {
case 1 :
Assert . IsTrue ( t . isAlive ) ;
t . Complete ( ) ;
break ;
case 2 :
Assert . IsFalse ( t . isAlive ) ;
break ;
default : throw new Exception ( ) ;
}
return true ;
} ) ;
yield return t . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator WaitCompleteFromValueChange ( ) {
var target = new GameObject ( ) ;
int numValueChanged = 0 ;
yield return Tween . WaitWhile ( target , _ = > {
numValueChanged + + ;
switch ( numValueChanged ) {
case 1 :
Assert . AreEqual ( 1 , Tween . CompleteAll ( target , 1 , 1 ) ) ;
break ;
case 2 :
Assert . AreEqual ( 0 , Tween . CompleteAll ( target , 0 , 0 ) ) ;
break ;
default : throw new Exception ( ) ;
}
return true ;
} ) . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator WaitStopFromValueChange ( ) {
var target = new GameObject ( ) ;
yield return Tween . WaitWhile ( target , _ = > {
Assert . AreEqual ( 1 , Tween . StopAll ( target , 1 , 1 ) ) ;
return true ;
} ) . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator TweenWait ( ) {
var timeStart = Time . time ;
int numOnCompleteDone = 0 ;
const float duration = 0.3f ;
var t = Tween . WaitWhile ( this , _ = > Time . time - timeStart < duration )
. OnComplete ( ( ) = > numOnCompleteDone + + ) ;
yield return null ;
Assert . IsTrue ( t . isAlive ) ;
yield return new WaitForSeconds ( duration + 0.01f ) ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnCompleteDone ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[Test]
public void TweenWaitInstantComplete ( ) {
int numOnCompleteDone = 0 ;
var t = Tween . WaitWhile ( this , _ = > true ) . OnComplete ( ( ) = > numOnCompleteDone + + ) ;
Assert . IsTrue ( t . isAlive ) ;
t . Complete ( ) ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnCompleteDone ) ;
}
[Test]
public void TweenWaitInstantStop ( ) {
int numOnCompleteDone = 0 ;
var t = Tween . WaitWhile ( this , _ = > true ) . OnComplete ( ( ) = > numOnCompleteDone + + ) ;
Assert . IsTrue ( t . isAlive ) ;
t . Stop ( ) ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 0 , numOnCompleteDone ) ;
}
[Test]
public void TweenWaitException ( ) {
var t = Tween . WaitWhile ( this , _ = > throw new Exception ( ) ) . OnComplete ( Assert . Fail ) ;
Assert . IsTrue ( t . isAlive ) ;
LogAssert . Expect ( LogType . Error , new Regex ( "Tween was stopped because of exception" ) ) ;
LogAssert . Expect ( LogType . Error , new Regex ( Constants . onCompleteCallbackIgnored ) ) ;
t . Complete ( ) ;
Assert . IsFalse ( t . isAlive ) ;
}
[UnityTest]
public IEnumerator TweenWaitDuration ( ) {
// Application.targetFrameRate = 60;
var t = Tween . WaitWhile ( this , _ = > true ) ;
validate ( ) ;
Assert . AreEqual ( 0 , t . elapsedTime ) ;
Assert . AreEqual ( 0 , t . elapsedTimeTotal ) ;
yield return null ;
Assert . AreNotEqual ( 0 , t . elapsedTime ) ;
Assert . AreNotEqual ( 0 , t . elapsedTimeTotal ) ;
// for (int i = 0; i < 60; i++) {
// yield return null;
// Debug.Log($"{t.elapsedTime}, {t.elapsedTimeTotal}");
// }
validate ( ) ;
t . Complete ( ) ;
void validate ( ) {
Assert . AreEqual ( - 1 , t . cyclesTotal ) ;
Assert . AreEqual ( 0 , t . cyclesDone ) ;
Assert . IsTrue ( float . IsPositiveInfinity ( t . duration ) ) ;
Assert . IsTrue ( float . IsPositiveInfinity ( t . durationTotal ) ) ;
Assert . AreEqual ( 0 , t . progress ) ;
Assert . AreEqual ( 0 , t . progressTotal ) ;
Assert . AreEqual ( 0 , t . interpolationFactor ) ;
}
} * /
[Test]
public void ZeroDurationWarning ( ) {
var oldSetting = PrimeTweenConfig . warnZeroDuration ;
try {
PrimeTweenConfig . warnZeroDuration = true ;
LogAssert . Expect ( LogType . Warning , new Regex ( nameof ( PrimeTweenManager . warnZeroDuration ) ) ) ;
Tween . Custom ( this , 0 , 1 , 0 , delegate { } ) ;
PrimeTweenConfig . warnZeroDuration = false ;
Tween . Custom ( this , 0 , 1 , 0 , delegate { } ) ;
LogAssert . NoUnexpectedReceived ( ) ;
} finally {
PrimeTweenConfig . warnZeroDuration = oldSetting ;
}
}
[Test]
public void CompleteTweenTwice ( ) {
int numCompleted = 0 ;
var t = createCustomTween ( 1 )
. OnComplete ( ( ) = > numCompleted + + ) ;
t . Complete ( ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
t . Complete ( ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
}
[UnityTest]
public IEnumerator FromValueShouldNotChangeBetweenCycles ( ) {
var cube = GameObject . CreatePrimitive ( PrimitiveType . Cube ) ;
var origPos = new Vector3 ( 10 , 10 , 10 ) ;
cube . transform . position = origPos ;
var tween = Tween . Position ( cube . transform , new Vector3 ( 20 , 10 , 10 ) , 0.01f , cycles : 5 ) ;
Assert . IsTrue ( tween . isAlive ) ;
Assert . IsNotNull ( tween . tween . getter ) ;
while ( tween . isAlive ) {
yield return null ;
Assert . AreEqual ( origPos , tween . tween . startValue . Vector3Val , "'From' should not change after a cycle. This can happen if tween resets startFromCurrent after a cycle." ) ;
}
Object . Destroy ( cube ) ;
}
[Test]
public void SettingIsPausedOnTweenInSequenceDisplayError ( ) {
var target = new object ( ) ;
var t = Tween . Delay ( target , 0.01f ) ;
Sequence . Create ( t ) ;
expectError ( ) ;
t . isPaused = true ;
expectError ( ) ;
Tween . SetPausedAll ( true , target ) ;
expectError ( ) ;
Tween . SetPausedAll ( false , target ) ;
void expectError ( ) {
expectCantManipulateTweenInsideSequence ( ) ;
}
}
[Test]
public void SettingCyclesOnDeadTweenDisplaysError ( ) {
var t = createTween ( ) ;
Assert . IsTrue ( t . isAlive ) ;
t . Complete ( ) ;
Assert . IsFalse ( t . isAlive ) ;
expectIsDeadError ( ) ;
t . SetRemainingCycles ( 5 ) ;
}
[Test]
public void TestDeadTween ( ) {
var t = createDeadTween ( ) ;
expectError ( ) ;
t . isPaused = true ;
t . Stop ( ) ;
t . Complete ( ) ;
// t.Revert();
expectError ( ) ;
t . SetRemainingCycles ( 10 ) ;
expectError ( ) ;
t . OnComplete ( delegate { } ) ;
expectError ( ) ;
t . OnComplete ( this , delegate { } ) ;
expectError ( ) ;
t . timeScale = 0 ;
void expectError ( ) {
expectIsDeadError ( ) ;
}
}
static Tween createDeadTween ( ) {
var t = createCustomTween ( 0.1f ) ;
t . Complete ( ) ;
Assert . IsFalse ( t . isAlive ) ;
return t ;
}
[UnityTest]
public IEnumerator TweenIsPaused ( ) {
var val = 0f ;
var t = Tween . Custom ( this , 0 , 1 , 1 , ( _ , newVal ) = > {
val = newVal ;
} ) ;
t . isPaused = true ;
yield return null ;
Assert . AreEqual ( 0 , val ) ;
yield return null ;
Assert . AreEqual ( 0 , val ) ;
yield return null ;
Assert . AreEqual ( 0 , val ) ;
t . isPaused = false ;
yield return null ;
Assert . AreNotEqual ( 0 , val ) ;
}
[UnityTest]
public IEnumerator SequenceIsPaused ( ) {
var val = 0f ;
var t = Tween . Custom ( this , 0 , 1 , 1 , ( _ , newVal ) = > {
val = newVal ;
} ) ;
var s = Sequence . Create ( t ) ;
s . isPaused = true ;
yield return null ;
Assert . AreEqual ( 0 , val ) ;
yield return null ;
Assert . AreEqual ( 0 , val ) ;
yield return null ;
Assert . AreEqual ( 0 , val ) ;
s . isPaused = false ;
yield return null ;
Assert . AreNotEqual ( 0 , val ) ;
}
const int capacityForTest = 800 ;
[UnityTest]
public IEnumerator TweensCapacity ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
PrimeTweenConfig . SetTweensCapacity ( capacityForTest ) ;
Assert . AreEqual ( capacityForTest , tweensCapacity ) ;
PrimeTweenConfig . SetTweensCapacity ( 0 ) ;
Assert . AreEqual ( 0 , tweensCapacity ) ;
LogAssert . Expect ( LogType . Warning , new Regex ( "Please increase the capacity" ) ) ;
Tween . Delay ( 0.0001f ) ;
Tween . Delay ( 0.0001f ) ; // created before set capacity
PrimeTweenConfig . SetTweensCapacity ( capacityForTest ) ;
Assert . AreEqual ( capacityForTest , tweensCapacity ) ;
var delay = Tween . Delay ( 0.0001f ) ;
yield return delay . ToYieldInstruction ( ) ; // should not display warning
Assert . IsFalse ( delay . isAlive ) ;
yield return null ; // the yielded tween is not yet released when the coroutine completes. The release will happen only in a frame
Assert . AreEqual ( 0 , tweensCount ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
static int tweensCapacity = > PrimeTweenManager . Instance . currentPoolCapacity ;
[Test]
public void ListResize ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
var list = new List < ReusableTween > ( ) ;
test ( 2 , 2 ) ;
Assert . AreNotEqual ( list [ 0 ] , list [ 1 ] ) ;
test ( 0 , 2 ) ;
test ( 10 , 10 ) ;
test ( 2 , 5 ) ;
test ( 10 , 20 ) ;
test ( 5 , 30 ) ;
test ( 6 , 29 ) ;
test ( 4 , 31 ) ;
test ( 5 , 32 ) ;
test ( 5 , 31 ) ;
test ( 4 , 31 ) ;
test ( 3 , 31 ) ;
test ( 0 , 31 ) ;
test ( 31 , 31 ) ;
Assert . Throws < AssertionException > ( ( ) = > test ( 32 , 31 ) ) ;
test ( 0 , 0 ) ;
test ( 10 , 10 ) ;
void test ( int newCount , int newCapacity ) {
PrimeTweenManager . resizeAndSetCapacity ( list , newCount , newCapacity ) ;
Assert . AreEqual ( newCount , list . Count ) ;
Assert . AreEqual ( newCapacity , list . Capacity ) ;
PrimeTweenConfig . SetTweensCapacity ( newCapacity ) ;
Assert . AreEqual ( newCapacity , tweensCapacity ) ;
}
PrimeTweenConfig . SetTweensCapacity ( capacityForTest ) ;
}
static ShakeSettings shakeSettings {
get {
if ( Random . value < 0.5f ) {
return new ShakeSettings ( Vector3 . one , 1f , 10f , false ) ;
}
return new ShakeSettings ( Vector3 . one , 1f , 10f , false , Ease . Linear ) ;
}
}
[UnityTest]
public IEnumerator ShakeCompleteWhenStartDelayIsNotElapsed ( ) {
var target = new GameObject ( nameof ( ShakeCompleteWhenStartDelayIsNotElapsed ) ) . transform ;
var iniPos = Random . value * Vector3 . one ;
target . localPosition = iniPos ;
var t = Tween . ShakeLocalPosition ( target , Vector3 . one , 0.1f , startDelay : 0.1f ) ;
yield return null ;
Assert . AreEqual ( 0f , t . interpolationFactor ) ;
Assert . AreEqual ( iniPos , target . localPosition ) ;
t . Complete ( ) ;
Assert . AreEqual ( iniPos , target . localPosition ) ;
}
[UnityTest]
public IEnumerator ShakeScale ( ) {
var shakeTransform = new GameObject ( "shake target" ) . transform ;
shakeTransform . position = Vector3 . one ;
Assert . AreEqual ( shakeTransform . localScale , Vector3 . one ) ;
var t = Tween . ShakeScale ( shakeTransform , shakeSettings ) ;
yield return null ;
Assert . AreNotEqual ( shakeTransform . localScale , Vector3 . one ) ;
t . Complete ( ) ;
Assert . IsTrue ( shakeTransform . localScale = = Vector3 . one ) ;
Object . DestroyImmediate ( shakeTransform . gameObject ) ;
}
[UnityTest]
public IEnumerator ShakeLocalRotation ( ) {
var shakeTransform = new GameObject ( "shake target" ) . transform ;
shakeTransform . position = Vector3 . one ;
Assert . AreEqual ( shakeTransform . localRotation , Quaternion . identity ) ;
var t = Tween . ShakeLocalRotation ( shakeTransform , shakeSettings ) ;
yield return null ;
Assert . AreNotEqual ( shakeTransform . localRotation , Quaternion . identity ) ;
t . Complete ( ) ;
Assert . IsTrue ( shakeTransform . localRotation = = Quaternion . identity ) ;
Object . DestroyImmediate ( shakeTransform . gameObject ) ;
}
[UnityTest]
public IEnumerator ShakeLocalPosition ( ) {
var shakeTransform = new GameObject ( "shake target" ) . transform ;
shakeTransform . position = Vector3 . one ;
Assert . AreEqual ( shakeTransform . position , Vector3 . one ) ;
var t = Tween . ShakeLocalPosition ( shakeTransform , shakeSettings ) ;
yield return null ;
Assert . AreNotEqual ( shakeTransform . position , Vector3 . one ) ;
t . Complete ( ) ;
Assert . IsTrue ( shakeTransform . position = = Vector3 . one , shakeTransform . position . ToString ( ) ) ;
Object . DestroyImmediate ( shakeTransform . gameObject ) ;
}
[UnityTest]
public IEnumerator ShakeCustom ( ) {
var shakeTransform = new GameObject ( "shake target" ) . transform ;
var iniPos = Vector3 . one ;
shakeTransform . position = iniPos ;
Assert . AreEqual ( iniPos , shakeTransform . position ) ;
var t = Tween . ShakeCustom ( shakeTransform , iniPos , shakeSettings , ( target , val ) = > target . localPosition = val ) ;
yield return null ;
Assert . AreNotEqual ( iniPos , shakeTransform . position ) ;
t . Complete ( ) ;
Assert . IsTrue ( iniPos = = shakeTransform . position , iniPos . ToString ( ) ) ;
}
[UnityTest]
public IEnumerator CreateShakeWhenTweenListHasNull ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
Tween . Delay ( 0.0001f ) ;
LogAssert . Expect ( LogType . Error , "Shake's strength is (0, 0, 0)." ) ;
LogAssert . Expect ( LogType . Error , new Regex ( "Shake's frequency should be > 0f" ) ) ;
Tween . Delay ( 0.0001f )
. OnComplete ( ( ) = > {
Assert . AreEqual ( 1 , getNullTweensCount ( ) ) ;
Tween . ShakeLocalPosition ( transform , default ) . Complete ( ) ;
} ) ;
yield return null ;
yield return null ;
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
}
static int getNullTweensCount ( ) = > PrimeTweenManager . Instance . tweensCount - Tween . GetTweensCount ( ) ;
[UnityTest]
public IEnumerator DelayNoTarget ( ) {
int numCallbackCalled = 0 ;
var t = Tween . Delay ( getDt ( ) * 2f , ( ) = > numCallbackCalled + + ) ;
Assert . AreEqual ( 0 , numCallbackCalled ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . AreEqual ( 1 , numCallbackCalled ) ;
}
[UnityTest]
public IEnumerator DelayFirstOverload ( ) {
int numCallbackCalled = 0 ;
var t = Tween . Delay ( this , getDt ( ) * 3 , ( ) = > numCallbackCalled + + ) ;
Assert . AreEqual ( 0 , numCallbackCalled ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . AreEqual ( 1 , numCallbackCalled ) ;
}
[UnityTest]
public IEnumerator DelaySecondOverload ( ) {
int numCallbackCalled = 0 ;
var t = Tween . Delay ( this , getDt ( ) * 3 , _ = > numCallbackCalled + + ) ;
Assert . AreEqual ( 0 , numCallbackCalled ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . AreEqual ( 1 , numCallbackCalled ) ;
}
[UnityTest]
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
public IEnumerator NewTweenCreatedFromManualOnComplete ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
var t1 = createTween ( ) . OnComplete ( ( ) = > createTween ( ) ) ;
createTween ( ) ;
t1 . Complete ( ) ;
Assert . AreEqual ( 3 , tweensCount ) ;
checkTweensAreOrdered ( ) ;
yield return null ;
Assert . AreEqual ( 2 , tweensCount ) ;
checkTweensAreOrdered ( ) ;
Tween . StopAll ( ) ;
}
static void checkTweensAreOrdered ( ) {
checkOrder ( PrimeTweenManager . Instance . tweens ) ;
2025-05-15 10:40:15 +08:00
checkOrder ( PrimeTweenManager . Instance . lateUpdateTweens ) ;
2025-01-23 10:16:47 +08:00
checkOrder ( PrimeTweenManager . Instance . fixedUpdateTweens ) ;
void checkOrder ( List < ReusableTween > tweens ) {
Assert . IsTrue ( tweens . OrderBy ( _ = > _ . id ) . SequenceEqual ( tweens ) ) ;
}
}
[UnityTest]
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
public IEnumerator NewTweenCreatedFromNormalOnComplete ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
int numOnCompleteCalled = 0 ;
var t1 = createCustomTween ( 0.01f ) . OnComplete ( ( ) = > {
numOnCompleteCalled + + ;
createCustomTween ( 0.01f ) ;
createCustomTween ( 0.01f ) ;
createCustomTween ( 0.01f ) ;
} ) ;
Assert . AreEqual ( 1 , tweensCount ) ;
checkTweensAreOrdered ( ) ;
while ( t1 . isAlive ) {
yield return null ;
}
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
Assert . AreEqual ( 3 , tweensCount ) ;
checkTweensAreOrdered ( ) ;
}
[UnityTest]
public IEnumerator SetAllPaused ( ) {
if ( tweensCount ! = 0 ) {
var aliveCount = Tween . GetTweensCount ( ) ;
Assert . AreEqual ( Tween . StopAll ( null ) , aliveCount ) ;
}
Assert . AreEqual ( 0 , tweensCount ) ;
const int count = 10 ;
var tweens = new List < Tween > ( ) ;
for ( int i = 0 ; i < count ; i + + ) {
tweens . Add ( createCustomTween ( 1 ) ) ;
}
Assert . IsTrue ( tweens . All ( _ = > ! _ . isPaused ) ) ;
Assert . AreEqual ( Tween . SetPausedAll ( true , null ) , count ) ;
Assert . IsTrue ( tweens . All ( _ = > _ . isPaused ) ) ;
Assert . AreEqual ( Tween . SetPausedAll ( false , null ) , count ) ;
Assert . IsTrue ( tweens . All ( _ = > ! _ . isPaused ) ) ;
Assert . IsTrue ( tweens . All ( _ = > _ . isAlive ) ) ;
yield return null ;
Assert . IsTrue ( tweens . All ( _ = > _ . isAlive ) ) ;
foreach ( var _ in tweens ) {
_ . Complete ( ) ;
}
Assert . IsFalse ( tweens . All ( _ = > _ . isAlive ) ) ;
}
[UnityTest]
public IEnumerator StopAllCalledFromOnValueChange ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
int numOnValueChangeCalled = 0 ;
var t = Tween . Custom ( this , 0 , 1 , 1f , delegate {
Assert . AreEqual ( 0 , numOnValueChangeCalled ) ;
numOnValueChangeCalled + + ;
var numStopped = Tween . StopAll ( this ) ;
Assert . AreEqual ( 1 , numStopped ) ;
} ) ;
Assert . IsTrue ( t . isAlive ) ;
yield return null ;
yield return null ;
Assert . IsFalse ( t . isAlive ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator RecursiveCompleteCallFromOnValueChange ( ) {
int numOnValueChangeCalled = 0 ;
int numOnCompleteCalled = 0 ;
Tween t = default ;
t = Tween . Custom ( this , 0 , 1 , 1f , delegate {
// Debug.Log(val);
numOnValueChangeCalled + + ;
Assert . IsTrue ( numOnValueChangeCalled < = 2 ) ;
t . Complete ( ) ;
} ) . OnComplete ( ( ) = > numOnCompleteCalled + + ) ;
Assert . IsTrue ( t . isAlive ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator RecursiveCompleteAllCallFromOnValueChange ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
int numOnValueChangeCalled = 0 ;
int numOnCompleteCalled = 0 ;
var t = Tween . Custom ( this , 0 , 1 , 1f , delegate {
// Debug.Log(val);
numOnValueChangeCalled + + ;
switch ( numOnValueChangeCalled ) {
case 1 : {
var numCompleted = Tween . CompleteAll ( this ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
break ;
}
case 2 : {
var numCompleted = Tween . CompleteAll ( this ) ;
Assert . AreEqual ( 0 , numCompleted ) ;
break ;
}
default :
throw new Exception ( ) ;
}
} ) . OnComplete ( ( ) = > numOnCompleteCalled + + ) ;
Assert . IsTrue ( t . isAlive ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
Assert . AreEqual ( 2 , numOnValueChangeCalled ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator RecursiveCompleteCallFromOnComplete ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
int numOnCompleteCalled = 0 ;
Tween t = default ;
t = Tween . Custom ( this , 0 , 1 , minDuration , delegate {
} ) . OnComplete ( ( ) = > {
numOnCompleteCalled + + ;
t . Complete ( ) ;
} ) ;
Assert . IsTrue ( t . isAlive ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
}
[UnityTest]
public IEnumerator RecursiveCompleteAllCallFromOnComplete ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
int numOnCompleteCalled = 0 ;
var t = Tween . Custom ( this , 0 , 1 , minDuration , delegate {
} ) . OnComplete ( ( ) = > {
numOnCompleteCalled + + ;
var numCompleted = Tween . CompleteAll ( this ) ;
Assert . AreEqual ( 0 , numCompleted ) ;
} ) ;
Assert . IsTrue ( t . isAlive ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
}
[UnityTest]
public IEnumerator StopAllCalledFromOnValueChange2 ( ) {
int numOnValChangedCalled = 0 ;
var t = Tween . Custom ( this , 0 , 1 , 0.0001f , ( _ , val ) = > {
// Debug.Log(val);
Assert . AreEqual ( 0 , val ) ;
Assert . AreEqual ( 0 , numOnValChangedCalled ) ;
numOnValChangedCalled + + ;
var numStopped = Tween . StopAll ( this ) ;
Assert . AreEqual ( 1 , numStopped ) ;
} ) ;
Assert . IsTrue ( t . isAlive ) ;
yield return null ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnValChangedCalled ) ;
}
[UnityTest]
public IEnumerator TweenCanBeNullInProcessAllMethod ( ) {
Assert . AreEqual ( 0 , tweensCount ) ;
Tween . Custom ( this , 0 , 1 , 0.0001f , delegate {
// Debug.Log($"t1 val {val}");
} ) ;
Tween . Custom ( this , 0 , 1 , 0.0001f , delegate {
// Debug.Log($"t2 val {val}");
Assert . AreEqual ( 0 , getNullTweensCount ( ) ) ;
Assert . AreEqual ( Tween . StopAll ( this ) , 2 ) ;
} ) ;
yield return null ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator TweenCanBeNullInOnComplete ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
int numOnCompleteCalled = 0 ;
Tween . Custom ( this , 0 , 1 , 0.0001f , delegate { } ) ;
Tween . Custom ( this , 0 , 1 , 0.0001f , delegate {
} ) . OnComplete ( ( ) = > {
numOnCompleteCalled + + ;
Assert . AreEqual ( 1 , getNullTweensCount ( ) ) ;
var numStopped = Tween . StopAll ( this ) ;
Assert . AreEqual ( 0 , numStopped ) ;
} ) ;
yield return null ;
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator TweenShouldBeDeadInOnValueChangeAfterCallingComplete ( ) {
// Debug.Log(nameof(TweenShouldBeDeadInOnValueChangeAfterCallingComplete));
var target = new GameObject ( nameof ( TweenShouldBeDeadInOnValueChangeAfterCallingComplete ) ) ;
int numOnValueChangeCalled = 0 ;
Tween t = default ;
t = Tween . Custom ( target , 0 , 1 , minDuration , ( _ , val ) = > {
// Debug.Log(val);
Assert . IsTrue ( val = = 0 | | val = = 1 ) ;
numOnValueChangeCalled + + ;
switch ( numOnValueChangeCalled ) {
case 1 :
Assert . IsTrue ( t . isAlive ) ;
if ( Random . value < 0.5f ) {
t . Complete ( ) ;
} else {
Assert . AreEqual ( Tween . CompleteAll ( target ) , 1 ) ;
}
break ;
case 2 :
// when Complete() is called, it's expected that onValueChange will be reported once again
break ;
default : throw new Exception ( ) ;
}
} ) ;
Assert . AreEqual ( 1 , Tween . SetPausedAll ( true , target ) ) ;
Assert . AreEqual ( 1 , Tween . SetPausedAll ( false , target ) ) ;
yield return null ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 2 , numOnValueChangeCalled ) ;
}
[Test]
public void NumProcessed ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
var target1 = new object ( ) ;
var target2 = new object ( ) ;
createWithTarget1 ( ) ; // 1
createWithTarget1 ( ) ; // 2
createWithTarget1 ( ) ; // 3
createWithTarget2 ( ) ; // 1
createWithTarget2 ( ) ; // 2
createWithTarget1 ( ) ; // 4
createWithTarget2 ( ) ; // 3
Assert . AreEqual ( 4 , Tween . SetPausedAll ( true , target1 ) ) ;
Assert . AreEqual ( 4 , Tween . SetPausedAll ( false , target1 ) ) ;
Assert . AreEqual ( 4 , Tween . StopAll ( target1 ) ) ;
Assert . AreEqual ( 0 , Tween . StopAll ( target1 ) ) ;
Assert . AreEqual ( 0 , Tween . CompleteAll ( target1 ) ) ;
Assert . AreEqual ( 0 , Tween . SetPausedAll ( true , target1 ) ) ;
Assert . AreEqual ( 3 , Tween . SetPausedAll ( true , target2 ) ) ;
Assert . AreEqual ( 3 , Tween . SetPausedAll ( false , target2 ) ) ;
Assert . AreEqual ( 3 , Tween . CompleteAll ( target2 ) ) ;
Assert . AreEqual ( 0 , Tween . CompleteAll ( target2 ) ) ;
Assert . AreEqual ( 0 , Tween . StopAll ( target2 ) ) ;
void createWithTarget1 ( ) = > Tween . Custom ( target1 , 0 , 1 , 0.0001f , delegate { } ) ;
void createWithTarget2 ( ) = > Tween . Custom ( target2 , 0 , 1 , 0.0001f , delegate { } ) ;
}
[UnityTest]
public IEnumerator TweenIsAliveForWholeDuration ( ) {
int numOnValueChangedCalled = 0 ;
int numOnValueChangedCalledAfterComplete = 0 ;
Tween t = default ;
var target = new object ( ) ;
bool isCompleteCalled = false ;
const float duration = 0.3f ;
t = Tween . Custom ( target , 0 , 1 , duration , ( _ , val ) = > {
// Debug.Log(val);
numOnValueChangedCalled + + ;
if ( isCompleteCalled ) {
numOnValueChangedCalledAfterComplete + + ;
}
Assert . AreEqual ( ! isCompleteCalled , t . isAlive ) ;
if ( val > duration / 2 ) {
isCompleteCalled = true ;
t . Complete ( ) ;
}
} ) . OnComplete ( ( ) = > {
Assert . IsTrue ( t . IsCreated ) ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 0 , Tween . StopAll ( target ) ) ;
} ) ;
while ( t . isAlive ) {
yield return null ;
}
Assert . IsTrue ( numOnValueChangedCalled > 1 ) ;
Assert . AreEqual ( 1 , numOnValueChangedCalledAfterComplete ) ;
}
[Test]
public void SetPauseAll ( ) {
var target = new object ( ) ;
var t = Tween . Custom ( target , 0 , 1 , 1 , delegate { } ) ;
Assert . AreEqual ( 0 , Tween . SetPausedAll ( false , target ) ) ;
Assert . AreEqual ( 1 , Tween . SetPausedAll ( true , target ) ) ;
Assert . AreEqual ( 0 , Tween . SetPausedAll ( true , target ) ) ;
Assert . AreEqual ( 1 , Tween . SetPausedAll ( false , target ) ) ;
Assert . AreEqual ( 0 , Tween . SetPausedAll ( false , target ) ) ;
t . Stop ( ) ;
Assert . AreEqual ( 0 , Tween . SetPausedAll ( true , target ) ) ;
}
[UnityTest]
public IEnumerator StopByTargetFromOnValueChange ( ) {
var target = new GameObject ( ) ;
int numOnValueChangeCalled = 0 ;
var t = Tween . Custom ( target , 0 , 1 , 1 , delegate {
numOnValueChangeCalled + + ;
var numStopped = Tween . StopAll ( target ) ;
Assert . AreEqual ( 1 , numStopped ) ;
} ) ;
Assert . AreEqual ( 0 , numOnValueChangeCalled ) ;
Assert . IsTrue ( t . isAlive ) ;
yield return null ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnValueChangeCalled ) ;
}
[UnityTest]
public IEnumerator TweenPropertiesDefault ( ) {
if ( tweensCount ! = 0 ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
}
{
yield return Tween . Delay ( 0.001f ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , tweensCount ) ;
yield return null ;
Assert . AreEqual ( 0 , tweensCount ) ;
}
{
var t = Tween . Delay ( 0f ) ;
Assert . IsTrue ( t . isAlive ) ;
validate ( t , true ) ;
}
{
var t = new Tween ( ) ;
Assert . IsFalse ( t . isAlive ) ;
expectError ( false ) ;
Assert . AreEqual ( 0 , t . cyclesTotal ) ;
validate ( t , false , false ) ;
}
{
var t = Tween . Delay ( 1 ) ;
t . Complete ( ) ;
Assert . IsFalse ( t . isAlive ) ;
expectError ( ) ;
Assert . AreEqual ( 0 , t . cyclesTotal ) ;
validate ( t , false ) ;
}
{
var t = Tween . Delay ( 1 ) ;
t . Stop ( ) ;
Assert . IsFalse ( t . isAlive ) ;
expectError ( ) ;
Assert . AreEqual ( 0 , t . cyclesTotal ) ;
validate ( t , false ) ;
}
void validate ( Tween t , bool isAlive , bool isCreated = true ) {
if ( ! isAlive ) {
for ( int i = 0 ; i < 8 ; i + + ) {
expectError ( isCreated ) ;
}
}
Assert . AreEqual ( 0 , t . elapsedTime ) ;
Assert . AreEqual ( 0 , t . elapsedTimeTotal ) ;
Assert . AreEqual ( 0 , t . cyclesDone ) ;
Assert . AreEqual ( 0 , t . duration ) ;
Assert . AreEqual ( 0 , t . durationTotal ) ;
Assert . AreEqual ( 0 , t . progress ) ;
Assert . AreEqual ( 0 , t . progressTotal ) ;
Assert . AreEqual ( 0 , t . interpolationFactor ) ;
if ( ! isAlive ) {
expectError ( isCreated ) ;
}
Assert . AreEqual ( 1 , t . timeScale ) ;
}
{
const float duration = 0.123f ;
var t = Tween . PositionY ( transform , 0 , duration , Ease . Linear , - 1 ) ;
Assert . AreEqual ( duration , t . duration ) ;
Assert . IsTrue ( float . IsPositiveInfinity ( t . durationTotal ) ) ;
Assert . AreEqual ( 0 , t . progress ) ;
Assert . AreEqual ( 0 , t . progressTotal ) ;
t . Stop ( ) ;
validate ( t , false ) ;
}
void expectError ( bool isCreated = true ) {
expectIsDeadError ( isCreated ) ;
}
}
[UnityTest]
public IEnumerator TweenProperties ( ) {
float duration = Mathf . Max ( minDuration , getDt ( ) * Random . Range ( 0.5f , 5f ) ) ;
int numCyclesExpected = Random . Range ( 1 , 3 ) ;
Tween t = default ;
float startDelay = getDt ( ) * Random . Range ( 0.1f , 1.2f ) ;
float endDelay = getDt ( ) * Random . Range ( 0.1f , 1.2f ) ;
float durationExpected = startDelay + duration + endDelay ;
float totalDurationExpected = durationExpected * numCyclesExpected ;
float timeStart = Time . time ;
t = Tween . Custom ( this , 1f , 2f , duration , ease : Ease . Linear , cycles : numCyclesExpected , startDelay : startDelay , endDelay : endDelay , onValueChange : ( _ , val ) = > {
val - = 1f ;
var elapsedTimeTotalExpected = Time . time - timeStart ;
var elapsedTimeExpected = elapsedTimeTotalExpected - durationExpected * t . cyclesDone ;
// Debug.Log($"val: {val}, progress: {t.progress}, elapsedTimeExpected: {elapsedTimeExpected}, elapsedTimeTotalExpected: {elapsedTimeTotalExpected}");
const float tolerance = 0.001f ;
if ( val < 1 ) {
Assert . AreEqual ( elapsedTimeExpected , t . elapsedTime , tolerance ) ;
Assert . AreEqual ( elapsedTimeTotalExpected , t . elapsedTimeTotal , tolerance , $"val: {val},duration: {duration}, numCyclesExpected: {numCyclesExpected}" ) ;
Assert . AreEqual ( Mathf . Min ( elapsedTimeTotalExpected / totalDurationExpected , 1f ) , t . progressTotal , tolerance ) ;
Assert . AreEqual ( elapsedTimeExpected / durationExpected , t . progress , tolerance ) ;
}
Assert . AreEqual ( numCyclesExpected , t . cyclesTotal ) ;
Assert . AreEqual ( durationExpected , t . duration ) ;
Assert . AreEqual ( totalDurationExpected , t . durationTotal ) ;
Assert . AreEqual ( t . interpolationFactor , val , tolerance ) ;
} ) ;
yield return t . ToYieldInstruction ( ) ;
Assert . IsFalse ( t . isAlive ) ;
for ( int i = 0 ; i < 2 ; i + + ) {
expectIsDeadError ( ) ;
}
Assert . AreEqual ( 0 , t . progress ) ;
Assert . AreEqual ( 0 , t . progressTotal ) ;
var infT = Tween . Position ( transform , Vector3 . one , minDuration , cycles : - 1 ) ;
Assert . IsTrue ( infT . isAlive ) ;
Assert . AreEqual ( - 1 , infT . cyclesTotal ) ;
infT . Complete ( ) ;
}
[UnityTest]
public IEnumerator ZeroDurationOnTweenShouldReportValueAtLeastOnce ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
Assert . AreEqual ( capacityForTest , tweensCapacity ) ;
const float p1 = 0.345f ;
Tween . PositionZ ( transform , 0 , p1 , 0f ) . Complete ( ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( p1 , transform . position . z ) ;
const float p2 = 0.123f ;
Tween . PositionZ ( transform , p2 , 0 ) . Complete ( ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( p2 , transform . position . z ) ;
const float p3 = 0.456f ;
Tween . PositionZ ( transform , p3 , 0 ) ;
yield return null ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( p3 , transform . position . z ) ;
yield return Tween . PositionZ ( transform , p1 , 0 ) . OnComplete ( ( ) = > { } ) . ToYieldInstruction ( ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( p1 , transform . position . z ) ;
}
[UnityTest]
public IEnumerator OneShouldBeReportedExactlyOnce ( ) {
int numOneReported = 0 ;
const int cycles = 1 ;
for ( int i = 0 ; i < 1 ; i + + ) {
numOneReported = 0 ;
yield return Tween . Custom ( this , 0 , 1 , getDt ( ) * Random . Range ( 0.5f , 1.5f ) , startDelay : getDt ( ) * Random . Range ( 0.1f , 1.1f ) , endDelay : getDt ( ) * Random . Range ( 0.5f , 3f ) , cycles : cycles , onValueChange : ( _ , val ) = > {
// print($"val: {val}");
if ( val = = 1f ) {
numOneReported + + ;
}
} ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( cycles , numOneReported ) ;
}
numOneReported = 0 ;
yield return Tween . Custom ( this , 0 , 1 , 0f , startDelay : getDt ( ) * Random . Range ( 0.1f , 1.1f ) , endDelay : getDt ( ) * Random . Range ( 0.1f , 1.1f ) , cycles : cycles , onValueChange : ( _ , val ) = > {
if ( val = = 1 ) {
numOneReported + + ;
}
} ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( cycles , numOneReported ) ;
numOneReported = 0 ;
yield return Tween . Custom ( this , 0 , 1 , 0f , cycles : cycles , onValueChange : ( _ , val ) = > {
if ( val = = 1 ) {
numOneReported + + ;
}
} ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( cycles , numOneReported ) ;
numOneReported = 0 ;
yield return Tween . Custom ( this , 0 , 1 , 0f , ( _ , val ) = > {
if ( val = = 1 ) {
numOneReported + + ;
}
} ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numOneReported ) ;
yield return Tween . PositionY ( transform , 3.14f , Mathf . Max ( minDuration , getDt ( ) * Random . Range ( 0.1f , 1.1f ) ) ) . ToYieldInstruction ( ) ;
yield return Tween . PositionY ( transform , 3.14f , 0f ) . ToYieldInstruction ( ) ;
yield return Tween . PositionY ( transform , 0 , 3.14f , 0f ) . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator SingleFrameTween ( ) {
Application . targetFrameRate = 200 ;
for ( int i = 0 ; i < 1 ; i + + ) {
int numOnValueChangeCalled = 0 ;
yield return Tween . Custom ( this , 0 , 1 , 0.0001f , ( _ , val ) = > {
numOnValueChangeCalled + + ;
Assert . IsTrue ( val = = 0 | | val = = 1 ) ;
} ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( 2 , numOnValueChangeCalled ) ;
}
Application . targetFrameRate = targetFrameRate ;
}
[UnityTest]
public IEnumerator TweensWithDurationOfDeltaTime ( ) {
for ( int i = 0 ; i < 1 ; i + + ) {
var go = new GameObject ( ) ;
go . AddComponent < TweensWithDurationOfDeltaTime > ( ) ;
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while ( go ! = null ) {
yield return null ;
}
}
}
[UnityTest]
public IEnumerator TweenWithExactDurationOfDeltaTime1 ( ) {
yield return Tween . Delay ( this , Time . deltaTime ) . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator TweenWithExactDurationOfDeltaTime2 ( ) {
int numOnCompleteCalled = 0 ;
yield return Tween . Delay ( this , Time . deltaTime , ( ) = > numOnCompleteCalled + + ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numOnCompleteCalled ) ;
}
[Test]
public void TotalDurationWithCycles ( ) {
var duration = Random . value ;
var startDelay = Random . value ;
var endDelay = Random . value ;
var cycles = Random . Range ( 1 , 10 ) ;
var t = Tween . LocalPositionY ( transform , new TweenSettings < float > ( 0 , 1 , duration , cycles : cycles , startDelay : startDelay , endDelay : endDelay ) ) ;
var durationTotalExpected = duration + startDelay + endDelay ;
const float tolerance = 0.0001f ;
Assert . AreEqual ( durationTotalExpected , t . duration , tolerance ) ;
Assert . AreEqual ( durationTotalExpected * cycles , t . durationTotal , tolerance ) ;
Assert . AreEqual ( durationTotalExpected * cycles , t . durationTotal , tolerance ) ;
t . Complete ( ) ;
}
[Test]
public void DurationWithWaitDependencies ( ) {
var t1Dur = Random . value ;
var t1Cycles = Random . Range ( 1 , 20 ) ;
var t2Dur = Random . value ;
var t2Cycles = Random . Range ( 1 , 20 ) ;
// const int t1Dur = 1;
// const int t1Cycles = 2;
// const int t2Dur = 2;
// const int t2Cycles = 2;
var t1 = Tween . LocalPositionX ( transform , 1 , t1Dur , cycles : t1Cycles ) ;
var t2 = Tween . LocalPositionX ( transform , 1 , t2Dur , cycles : t2Cycles ) ;
var s = t1 . Chain ( t2 ) ;
Assert . IsTrue ( t1 . isAlive ) ;
Assert . IsTrue ( t2 . isAlive ) ;
Assert . AreEqual ( t1Dur * t1Cycles , t1 . durationTotal ) ;
Assert . AreEqual ( t2Dur * t2Cycles , t2 . durationTotal ) ;
Assert . AreEqual ( t1Dur * t1Cycles , t1 . durationWithWaitDelay ) ;
Assert . AreEqual ( t1Dur * t1Cycles + t2Dur * t2Cycles , t2 . durationWithWaitDelay , 0.001f ) ;
s . Complete ( ) ;
}
[Test]
public void AwaitingDeadCompletesImmediately ( ) {
bool isCompleted = false ;
AwaitingDeadCompletesImmediatelyAsync ( ( ) = > isCompleted = true ) ;
Assert . IsTrue ( isCompleted ) ;
}
static async void AwaitingDeadCompletesImmediatelyAsync ( [ NotNull ] Action callback ) {
var frame = Time . frameCount ;
await new Tween ( ) ;
await new Sequence ( ) ;
Assert . AreEqual ( frame , Time . frameCount ) ;
callback ( ) ;
}
[UnityTest]
public IEnumerator TestAwaitByCallback ( ) {
bool isCompleted = false ;
var t = Tween . Delay ( getDt ( ) * 5f ) ;
waitForTweenAsync ( t , ( ) = > isCompleted = true ) ;
Assert . IsFalse ( isCompleted ) ;
yield return null ;
Assert . IsFalse ( isCompleted ) ;
yield return t . ToYieldInstruction ( ) ;
Assert . IsTrue ( isCompleted ) ;
}
static async void waitForTweenAsync ( Tween tween , [ NotNull ] Action callback ) {
await tween ;
callback ( ) ;
}
[Test]
public async Task AwaitTweenWithCallback ( ) {
bool isCompleted = false ;
var t = Tween . Delay ( getDt ( ) * 2f , ( ) = > isCompleted = true ) ;
Assert . IsTrue ( t . isAlive ) ;
Assert . IsTrue ( t . tween . HasOnComplete ) ;
await t ;
Assert . IsFalse ( t . isAlive ) ;
Assert . IsTrue ( isCompleted ) ;
}
const float minDuration = TweenSettings . minDuration ;
[Test]
public async Task AwaitTweenWithCallbackDoesntPostpone ( ) {
bool isCompleted = false ;
var t = Tween . Delay ( minDuration , ( ) = > isCompleted = true ) ;
Assert . IsTrue ( t . isAlive ) ;
Assert . IsTrue ( t . tween . HasOnComplete ) ;
var frameStart = Time . frameCount ;
await t ;
Assert . AreEqual ( 1 , Time . frameCount - frameStart ) ;
Assert . IsFalse ( t . isAlive ) ;
Assert . IsTrue ( isCompleted ) ;
}
[Test]
public async Task AwaitSequence ( ) {
bool isCompleted1 = false ;
bool isCompleted2 = false ;
await Sequence . Create ( Tween . Delay ( 0.01f , ( ) = > isCompleted1 = true ) )
. Chain ( Tween . Delay ( 0.02f , ( ) = > isCompleted2 = true ) ) ;
Assert . IsTrue ( isCompleted1 ) ;
Assert . IsTrue ( isCompleted2 ) ;
}
[Test]
public async Task AwaitSequence2 ( ) {
var t1 = Tween . Delay ( getDt ( ) ) ;
var t2 = Tween . Delay ( getDt ( ) ) ;
await t1 . Chain ( t2 ) ;
Assert . IsFalse ( t1 . isAlive ) ;
Assert . IsFalse ( t2 . isAlive ) ;
}
[UnityTest]
public IEnumerator ToYieldInstruction ( ) {
var t = Tween . Delay ( 0.1f ) ;
var e = t . ToYieldInstruction ( ) ;
var frameStart = Time . frameCount ;
while ( e . MoveNext ( ) ) {
yield return e . Current ;
t . Complete ( ) ;
}
Assert . AreEqual ( 1 , Time . frameCount - frameStart ) ;
Assert . IsFalse ( t . isAlive ) ;
yield return t . ToYieldInstruction ( ) ;
Tween defaultTween = default ;
defaultTween . ToYieldInstruction ( ) ;
Sequence defaultSequence = default ;
defaultSequence . ToYieldInstruction ( ) ;
t . Complete ( ) ;
}
[UnityTest]
public IEnumerator ImplicitConversionToIterator ( ) {
PrimeTweenConfig . warnStructBoxingAllocationInCoroutine = true ;
{
var t2 = Tween . Delay ( 0.0001f ) ;
var frameStart = Time . frameCount ;
expectCoroutineBoxingWarning ( ) ;
yield return t2 ;
Assert . AreEqual ( 1 , Time . frameCount - frameStart ) ;
Assert . IsFalse ( t2 . isAlive ) ;
}
{
var s = Sequence . Create ( Tween . Delay ( 0.0001f ) ) ;
var frameStart = Time . frameCount ;
// iterator boxing warning is shown only once
yield return s ;
Assert . AreEqual ( 1 , Time . frameCount - frameStart ) ;
Assert . IsFalse ( s . isAlive ) ;
}
LogAssert . NoUnexpectedReceived ( ) ;
}
[Test]
public async Task AwaitInfiniteTweenComplete ( ) {
Tween t = default ;
int numCompleted = 0 ;
t = Tween . Custom ( this , 0 , 1 , 1 , cycles : - 1 , onValueChange : delegate { t . Complete ( ) ; } )
. OnComplete ( ( ) = > numCompleted + + ) ;
await t ;
Assert . AreEqual ( 1 , numCompleted ) ;
}
[Test]
public async Task AwaitInfiniteTweenStop ( ) {
Tween t = default ;
int numOnValueChanged = 0 ;
t = Tween . Custom ( this , 0 , 1 , 1f , cycles : - 1 , onValueChange : delegate {
// Debug.Log(numOnValueChanged);
numOnValueChanged + + ;
Assert . AreEqual ( 1 , numOnValueChanged ) ;
Assert . IsTrue ( t . isAlive ) ;
t . Stop ( ) ;
} ) ;
Assert . IsTrue ( t . isAlive ) ;
await t ;
Assert . IsFalse ( t . isAlive ) ;
Assert . AreEqual ( 1 , numOnValueChanged ) ;
}
[Test]
public async Task TweenStoppedTweenWhileAwaiting ( ) {
var t = Tween . Delay ( 0.05f ) ;
#pragma warning disable CS4014
Tween . Delay ( 0.01f ) . OnComplete ( ( ) = > t . Stop ( ) ) ;
#pragma warning restore CS4014
Assert . IsTrue ( t . isAlive ) ;
await t ;
Assert . IsFalse ( t . isAlive ) ;
}
[Test]
public void InvalidDurations ( ) {
Assert . Throws < AssertionException > ( ( ) = > Tween . Delay ( float . NaN ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . Delay ( float . PositiveInfinity ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . Delay ( float . NegativeInfinity ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . PositionZ ( transform , new TweenSettings < float > ( 0 , 1 , new TweenSettings ( 1 , startDelay : float . NaN ) ) ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . PositionZ ( transform , new TweenSettings < float > ( 0 , 1 , new TweenSettings ( 1 , startDelay : float . PositiveInfinity ) ) ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . PositionZ ( transform , new TweenSettings < float > ( 0 , 1 , new TweenSettings ( 1 , startDelay : float . NegativeInfinity ) ) ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . PositionZ ( transform , new TweenSettings < float > ( 0 , 1 , new TweenSettings ( 1 , endDelay : float . NaN ) ) ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . PositionZ ( transform , new TweenSettings < float > ( 0 , 1 , new TweenSettings ( 1 , endDelay : float . PositiveInfinity ) ) ) , Constants . durationInvalidError ) ;
Assert . Throws < AssertionException > ( ( ) = > Tween . PositionZ ( transform , new TweenSettings < float > ( 0 , 1 , new TweenSettings ( 1 , endDelay : float . NegativeInfinity ) ) ) , Constants . durationInvalidError ) ;
}
[Test]
public void MaterialTweens ( ) {
{
var s = Shader . Find ( "Standard" ) ;
if ( s = = null ) {
Assert . Ignore ( ) ;
return ;
}
var m = new Material ( s ) ;
{
const string propName = "_EmissionColor" ;
#if UNITY_2021_1_OR_NEWER
Assert . IsTrue ( m . HasColor ( propName ) ) ;
#endif
var to = Color . red ;
Tween . MaterialColor ( m , Shader . PropertyToID ( propName ) , to , 1f ) . Complete ( ) ;
Assert . AreEqual ( to , m . GetColor ( propName ) ) ;
}
{
const string propName = "_EmissionColor" ;
#if UNITY_2021_1_OR_NEWER
Assert . IsTrue ( m . HasColor ( propName ) ) ;
#endif
var iniColor = new Color ( Random . value , Random . value , Random . value , Random . value ) ;
m . SetColor ( propName , iniColor ) ;
var toAlpha = Random . value ;
Tween . MaterialAlpha ( m , Shader . PropertyToID ( propName ) , toAlpha , 1f ) . Complete ( ) ;
var col = m . GetColor ( propName ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( col . r , iniColor . r ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( col . g , iniColor . g ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( col . b , iniColor . b ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( col . a , toAlpha ) ;
}
{
const string propName = "_Cutoff" ;
#if UNITY_2021_1_OR_NEWER
Assert . IsTrue ( m . HasFloat ( propName ) ) ;
#endif
var to = Random . value ;
Tween . MaterialProperty ( m , Shader . PropertyToID ( propName ) , to , 1f ) . Complete ( ) ;
UnityEngine . Assertions . Assert . AreApproximatelyEqual ( to , m . GetFloat ( propName ) ) ;
}
{
const string propName = "_MainTex" ;
#if UNITY_2021_1_OR_NEWER
Assert . IsTrue ( m . HasTexture ( propName ) ) ;
#endif
var to = Random . value * Vector2 . one ;
Tween . MaterialTextureOffset ( m , Shader . PropertyToID ( propName ) , to , 1f ) . Complete ( ) ;
Assert . AreEqual ( to , m . GetTextureOffset ( propName ) ) ;
}
{
const string propName = "_MainTex" ;
#if UNITY_2021_1_OR_NEWER
Assert . IsTrue ( m . HasTexture ( propName ) ) ;
#endif
var to = Random . value * Vector2 . one ;
Tween . MaterialTextureScale ( m , Shader . PropertyToID ( propName ) , to , 1f ) . Complete ( ) ;
Assert . IsTrue ( to = = m . GetTextureScale ( propName ) ) ;
}
}
{
var m = Resources . Load < Material > ( "Custom_TestShader" ) ;
Assert . IsNotNull ( m ) ;
const string propName = "_TestVectorProp" ;
var to = Random . value * Vector4 . one ;
Tween . MaterialProperty ( m , Shader . PropertyToID ( propName ) , to , 1f ) . Complete ( ) ;
Assert . IsTrue ( to = = m . GetVector ( propName ) ) ;
}
}
/// passing the serialized UnityEngine.Object reference that is not populated behaves like passing destroyed object
[Test]
public void PassingDestroyedUnityTarget ( ) {
LogAssert . NoUnexpectedReceived ( ) ;
var target = new GameObject ( ) . transform ;
Object . DestroyImmediate ( target . gameObject ) ;
var s = Sequence . Create ( ) ;
expectError ( ) ;
s . ChainCallback ( target , delegate { } ) ;
expectError ( ) ;
Assert . IsFalse ( Tween . Delay ( target , 0.1f , delegate { } ) . IsCreated ) ;
expectError ( ) ;
Assert . IsFalse ( Tween . Delay ( target , 0.1f ) . IsCreated ) ;
expectError ( ) ;
Assert . IsFalse ( Tween . Delay ( target , 0.1f , ( ) = > { } ) . IsCreated ) ;
expectError ( ) ;
Assert . IsFalse ( Tween . Position ( target , new TweenSettings < Vector3 > ( default , default , 0.1f ) ) . IsCreated ) ;
expectError ( ) ;
var deadTween = Tween . Custom ( target , 0f , 0 , 0.1f , delegate { } ) ;
Assert . IsFalse ( deadTween . isAlive ) ;
expectAddDeadToSequenceError ( ) ;
Sequence . Create ( deadTween ) ;
LogAssert . Expect ( LogType . Error , "Shake's strength is (0, 0, 0)." ) ;
LogAssert . Expect ( LogType . Error , new Regex ( "Shake's frequency should be > 0f" ) ) ;
expectError ( ) ;
Tween . ShakeLocalPosition ( target , default ) ;
void expectError ( ) {
expectTargetIsNull ( ) ;
}
}
[Test]
public void ShakeSettings ( ) {
{
var s = new ShakeSettings ( Vector3 . one , 1f , 1 ) ;
Assert . IsTrue ( s . enableFalloff ) ;
}
{
var s = new ShakeSettings ( Vector3 . one , 1f , 1 , true , Ease . InBack ) ;
Assert . IsTrue ( s . enableFalloff ) ;
}
{
var s = new ShakeSettings ( Vector3 . one , 1f , 1 , AnimationCurve . Linear ( 0 , 0 , 1 , 1 ) ) ;
Assert . IsTrue ( s . enableFalloff ) ;
}
}
[UnityTest]
public IEnumerator ForceCompleteWhenWaitingForEndDelay ( ) {
var t = Tween . ShakeLocalPosition ( transform , new ShakeSettings ( Vector3 . one , getDt ( ) * 2f , endDelay : 100f ) ) ;
while ( t . interpolationFactor < 1f ) {
yield return null ;
}
Assert . IsTrue ( t . isAlive ) ;
t . Complete ( ) ;
Assert . IsFalse ( t . isAlive ) ;
}
static void print ( object o ) = > Debug . Log ( $"[{Time.frameCount}] {o}" ) ;
[UnityTest]
public IEnumerator StopAtEvenOrOddCycle ( ) {
for ( int i = 0 ; i < 5 ; i + + ) {
var t = Tween . Rotation ( transform , Vector3 . one , getDt ( ) * 5f , cycles : 10 , cycleMode : CycleMode . Yoyo ) ;
while ( t . cyclesDone < Random . Range ( 2 , 4 ) ) {
yield return null ;
}
t . SetRemainingCycles ( true ) ;
Assert . AreEqual ( t . cyclesDone % 2 + 1 , t . cyclesTotal - t . cyclesDone ) ;
t . SetRemainingCycles ( false ) ;
Assert . AreEqual ( t . cyclesDone % 2 , ( t . cyclesTotal - t . cyclesDone ) % 2 ) ;
}
}
[UnityTest]
public IEnumerator SetCycles ( ) {
var t = Tween . Rotation ( transform , Vector3 . one , Mathf . Max ( minDuration , getDt ( ) ) * 10 , cycles : 10 ) ;
while ( t . cyclesDone ! = 2 ) {
yield return null ;
}
t . SetRemainingCycles ( 3 ) ;
Assert . AreEqual ( 2 , t . cyclesDone ) ;
Assert . AreEqual ( 5 , t . cyclesTotal ) ;
t . Complete ( ) ;
}
[Test]
public void DOTweenAdapterEnabled ( ) {
#if ! PRIME_TWEEN_DOTWEEN_ADAPTER
Assert . Inconclusive ( ) ;
#endif
}
[Test]
public void ExperimentalDefineSet ( ) {
#if PRIME_TWEEN_EXPERIMENTAL
Assert . Ignore ( "Please remove the PRIME_TWEEN_EXPERIMENTAL define and run all tests again." ) ;
#endif
}
[UnityTest]
public IEnumerator RecursiveKillAllCall ( ) {
// Calling Tween.StopAll/Complete() from onValueChange previously threw the 'Please don't call Tween.StopAll/CompleteAll() from the OnComplete() callback' exception before.
// But this no longer the case - current impl checks if Update/FixedUpdate() is safe to call
yield return Tween . Custom ( 0 , 1 , 1f , val = > {
if ( val ! = 0 ) {
Tween . StopAll ( ) ;
}
} ) . ToYieldInstruction ( ) ;
yield return Tween . Custom ( 0 , 1 , 0.01f , _ = > {
Tween . CompleteAll ( ) ;
} ) . ToYieldInstruction ( ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator KillAllIsImmediate ( ) {
Tween . Delay ( 0.01f ) ;
Tween . StopAll ( null ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
Tween . Delay ( 0.01f ) ;
Assert . AreEqual ( 1 , tweensCount ) ;
Assert . AreEqual ( Tween . CompleteAll ( null ) , 1 ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
yield return null ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[Test]
public void SetCapacityImmediatelyAfterStopAll ( ) {
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
PrimeTweenConfig . SetTweensCapacity ( 2 ) ;
Tween . Delay ( 0.01f ) ;
Tween . Delay ( 0.01f ) ;
Assert . AreEqual ( 2 , tweensCount ) ;
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , tweensCount ) ;
PrimeTweenConfig . SetTweensCapacity ( 1 ) ;
PrimeTweenConfig . SetTweensCapacity ( capacityForTest ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator RotationShakeEndVal ( ) {
var target = new GameObject ( nameof ( RotationShakeEndVal ) ) . transform ;
var iniRot = Random . rotation . normalized ;
var strength = Random . insideUnitSphere ;
var freq = Random . value * 10 ;
target . rotation = iniRot ;
var handle = Tween . ShakeLocalRotation ( target , strength , 1f , freq ) ;
// skip frame so cacheDiff() is called
yield return null ;
Assert . IsTrue ( handle . isAlive ) ;
var t = handle . tween ;
Assert . IsTrue ( iniRot = = t . startValue . QuaternionVal ) ;
Assert . IsTrue ( Quaternion . identity = = t . endValue . QuaternionVal ) ;
Assert . AreEqual ( strength , t . shakeData . strengthPerAxis ) ;
Assert . AreEqual ( freq , t . shakeData . frequency ) ;
Object . Destroy ( target . gameObject ) ;
handle . Stop ( ) ;
}
[UnityTest]
public IEnumerator AtSpeed ( ) {
var target = new GameObject ( nameof ( AtSpeed ) ) . transform ;
var speed = ( Random . value + 0.1f ) * 10f ;
const double tolerance = 0.001 ;
var endValue = new Vector3 ( 1 , 0 , 0 ) ;
{
Assert . AreEqual ( Vector3 . zero , target . position ) ;
var t = Tween . PositionAtSpeed ( target , endValue , speed ) ;
Assert . AreEqual ( speed , 1 / t . duration , tolerance ) ;
yield return null ;
Assert . AreEqual ( speed , 1 / t . duration , tolerance ) ;
t . Stop ( ) ;
}
{
target . position = Vector3 . zero ;
Tween . PositionAtSpeed ( target , endValue , speed ) . Complete ( ) ;
Assert . AreEqual ( endValue , target . position ) ;
}
{
target . position = Vector3 . zero ;
float startDelay = getDt ( ) ;
var t = Tween . PositionAtSpeed ( target , endValue , speed , startDelay : startDelay ) ;
var expectedDuration = 1 / speed + startDelay ;
while ( t . interpolationFactor = = 0 ) {
Assert . AreEqual ( expectedDuration , t . duration , tolerance ) ;
yield return null ;
}
Assert . AreEqual ( expectedDuration , t . duration , tolerance ) ;
yield return null ;
Assert . AreEqual ( expectedDuration , t . duration , tolerance ) ;
t . Stop ( ) ;
}
}
[UnityTest]
public IEnumerator DelayInterpolationFactor ( ) {
for ( int i = 0 ; i < 1 ; i + + ) {
float duration = Random . Range ( 0.001f , 0.1f ) ;
var d = Tween . Delay ( duration ) ;
float timeStart = Time . time ;
while ( d . isAlive ) {
Assert . AreEqual ( Mathf . Min ( 1f , ( Time . time - timeStart ) / duration ) , d . interpolationFactor , 0.001f ) ;
yield return null ;
}
}
}
[Test]
public void TweensCount ( ) {
Tween . StopAll ( ) ;
int count = Random . Range ( 1 , 10 ) ;
for ( int i = 0 ; i < count ; i + + ) {
Tween . PositionX ( transform , 10 , 0.01f ) ;
}
Assert . AreEqual ( count , Tween . GetTweensCount ( ) ) ;
Assert . AreEqual ( count , Tween . GetTweensCount ( transform ) ) ;
Tween . StopAll ( ) ;
Assert . AreEqual ( 0 , Tween . GetTweensCount ( ) ) ;
}
[UnityTest]
public IEnumerator StopCalledOnLastTweenFrame ( ) {
float dt = getDt ( ) ;
Tween tween = default ;
tween = Tween . Custom ( 0 , 1 , dt * 3 , val = > {
if ( val = = 1f ) {
tween . Stop ( ) ;
Assert . IsFalse ( tween . isAlive ) ;
}
} ) . OnComplete ( ( ) = > Assert . Fail ( ) ) ;
yield return tween . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator StopCalledOnLastTweenFrameFromOnUpdate ( ) {
Tween tween = default ;
float duration = getDt ( ) * 3f ;
tween = Tween . Custom ( 0 , 1 , duration , delegate { } )
. OnUpdate ( this , delegate {
if ( tween . interpolationFactor = = 1f ) {
tween . Stop ( ) ;
Assert . IsFalse ( tween . isAlive ) ;
}
} )
. OnComplete ( ( ) = > Assert . Fail ( ) ) ;
yield return tween . ToYieldInstruction ( ) ;
}
[UnityTest]
public IEnumerator OnUpdateDestroyedTarget ( ) {
var onUpdateTarget = new GameObject ( nameof ( OnUpdateDestroyedTarget ) ) ;
int numUpdated = 0 ;
expectOnUpdateRemoved ( ) ;
yield return Tween . Delay ( getDt ( ) * 5 )
. OnUpdate ( onUpdateTarget , ( target , _ ) = > {
Assert . AreEqual ( 0 , numUpdated ) ;
numUpdated + + ;
Object . Destroy ( target ) ;
} )
. ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numUpdated ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator OnUpdateException ( ) {
var onUpdateTarget = new GameObject ( nameof ( OnUpdateDestroyedTarget ) ) ;
expectOnUpdateRemoved ( ) ;
int numCompleted = 0 ;
yield return Tween . PositionZ ( transform , Random . value , 0.001f )
. OnUpdate ( onUpdateTarget , delegate { throw new Exception ( ) ; } )
. OnComplete ( ( ) = > numCompleted + + )
. ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numCompleted ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[Test]
public void OnUpdateInvalidUsage ( ) {
var t = Tween . Delay ( 0.001f ) ;
t . OnUpdate < object > ( null , delegate { } ) ; // ok
expectException < AssertionException > ( ( ) = > {
t . OnUpdate < object > ( null , delegate { } ) ; // duplicate is not allowed
} , "Only one OnUpdate() is allowed for one tween." ) ;
Assert . Throws < AssertionException > ( ( ) = > {
t . OnUpdate ( this , null ) ; // null onUpdate is not allowed
} ) ;
}
[UnityTest]
public IEnumerator OnUpdate ( ) {
{
// with delay
int numCalled = 0 ;
yield return Tween . Delay ( minDuration , ( ) = > numCalled + + ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numCalled ) ;
}
{
var t = Tween . Position ( transform , Vector3 . one , getDt ( ) , endDelay : getDt ( ) * 5 ) ;
int numInterpolationCompleted = 0 ;
yield return t . OnUpdate < object > ( null , delegate {
if ( t . interpolationFactor = = 1f ) {
numInterpolationCompleted + + ;
}
} ) . ToYieldInstruction ( ) ;
Assert . AreEqual ( 1 , numInterpolationCompleted ) ;
}
}
static void expectOnUpdateRemoved ( ) = > LogAssert . Expect ( LogType . Error , new Regex ( "will not be called again because" ) ) ;
[UnityTest]
public IEnumerator TimescaleTweenOutliveTheTarget ( ) {
var shortTween = Tween . Delay ( 0.001f ) ;
var timeScaleTween = Tween . TweenTimeScale ( shortTween , 0.5f , 1 )
. OnComplete ( Assert . Fail ) ;
expectOnCompleteIgnored ( ) ;
yield return shortTween . ToYieldInstruction ( ) ;
Assert . IsFalse ( timeScaleTween . isAlive ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator ConversionToEasing ( ) {
var curve = AnimationCurve . Linear ( 0 , 0 , 1 , 1 ) ;
new TweenSettings ( 1 , curve ) ;
new TweenSettings < float > ( 0 , 1 , curve ) ;
new TweenSettings < float > ( 0 , 1 , 1 , curve ) ;
Tween . Position ( transform , Vector3 . one , 1 , curve ) ;
Tween . Position ( transform , Vector3 . one , 1 , ( Easing ) Ease . InBack ) ;
Tween . Position ( transform , Vector3 . zero , Vector3 . one , 1 , curve ) ;
#if PRIME_TWEEN_EXPERIMENTAL
Tween . PositionAdditive ( transform , Vector3 . one , 1 , curve ) ;
#endif
Tween . PositionAtSpeed ( transform , Vector3 . one , 10 , curve ) ;
Tween . PositionAtSpeed ( transform , Vector3 . zero , Vector3 . one , 10 , curve ) ;
yield return null ;
Tween . StopAll ( ) ;
}
[UnityTest]
public IEnumerator Elastic ( ) {
for ( int i = 0 ; i < 5 ; i + + ) {
Assert . AreEqual ( 0 , Easing . Evaluate ( 0 , parametricSettings ( ParametricEase . Elastic , 1 , 0.3f ) ) ) ;
Assert . AreEqual ( 1 , Easing . Evaluate ( 1 , parametricSettings ( ParametricEase . Elastic , 1 , 0.3f ) ) ) ;
var strength = 1 + Random . value ;
var period = 0.1f + Random . value ;
var t = Tween . Position ( transform , Vector3 . one , 1 , Easing . Elastic ( strength , period ) ) ;
yield return null ;
Assert . IsTrue ( t . isAlive ) ;
Assert . AreEqual ( strength , t . tween . settings . parametricEaseStrength ) ;
Assert . AreEqual ( period , t . tween . settings . parametricEasePeriod ) ;
Assert . AreEqual ( Ease . Custom , t . tween . settings . ease ) ;
Assert . AreEqual ( ParametricEase . Elastic , t . tween . settings . parametricEase ) ;
t . Stop ( ) ;
}
}
[NotNull]
static ReusableTween parametricSettings ( ParametricEase ease , float strength , float period ) {
return new ReusableTween {
settings = new TweenSettings {
ease = Ease . Custom ,
duration = 1 ,
parametricEase = ease ,
parametricEaseStrength = strength ,
parametricEasePeriod = period
}
} ;
}
[UnityTest]
public IEnumerator Overshoot ( ) {
Assert . AreEqual ( 0 , Easing . Evaluate ( 0 , parametricSettings ( ParametricEase . Overshoot , 1 , float . NaN ) ) ) ;
Assert . AreEqual ( 1 , Easing . Evaluate ( 1 , parametricSettings ( ParametricEase . Overshoot , 1 , float . NaN ) ) ) ;
var strength = Random . value ;
var t = Tween . Position ( transform , Vector3 . one , 1 , Easing . Overshoot ( strength ) ) ;
yield return null ;
Assert . IsTrue ( t . isAlive ) ;
Assert . AreEqual ( strength * StandardEasing . backEaseConst , t . tween . settings . parametricEaseStrength ) ;
Assert . AreEqual ( ParametricEase . Overshoot , t . tween . settings . parametricEase ) ;
Assert . AreEqual ( Ease . Custom , t . tween . settings . ease ) ;
t . Stop ( ) ;
}
[UnityTest]
[SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
public IEnumerator NullTarget ( ) {
const float duration = 0.05f ;
Transform t = null ;
expectTargetIsNull ( ) ;
Tween . Position ( t , Vector3 . one , duration ) . ToYieldInstruction ( ) ;
expectTargetIsNull ( ) ;
Tween . Delay ( null , duration ) ;
expectTargetIsNull ( ) ;
Tween . Delay ( t , duration , delegate { } ) ;
expectTargetIsNull ( ) ;
Sequence . Create ( ) . ChainCallback ( t , delegate { } ) ;
Tween . Custom ( 0 , 1 , duration , delegate { } ) ;
Tween . Delay ( duration ) ;
Time . timeScale = 0.99f ;
Tween . GlobalTimeScale ( 1 , 0.05f ) ;
Sequence . Create ( ) . ChainCallback ( delegate { } ) ;
#if PRIME_TWEEN_DOTWEEN_ADAPTER
DOTween . Sequence ( ) . SetLoops ( 2 ) . AppendCallback ( delegate { } ) ;
DOTween . Sequence ( ) . PrependInterval ( 0.01f ) ;
#endif
yield return null ;
yield return null ;
Tween . StopAll ( ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator MoreThanOneCyclePerFrame ( ) {
yield return null ;
{
var zeroDurTween = Tween . ScaleY ( transform , 2f , 0 , cycles : int . MaxValue - 1 ) ;
yield return null ;
Assert . IsFalse ( zeroDurTween . isAlive , "0f duration completes all cycles immediately" ) ;
}
{
var infiniteZeroDurTween = Tween . ScaleY ( transform , 2f , 0 , cycles : - 1 ) ;
yield return null ;
Assert . AreEqual ( 1 , infiniteZeroDurTween . cyclesDone ) ;
Assert . IsTrue ( infiniteZeroDurTween . isAlive ) ;
}
{
float duration = 0.001f + getDt ( ) / 10f ;
Assert . IsTrue ( duration > = 0.001f ) ;
var t = Tween . ScaleY ( transform , 2f , duration , cycles : int . MaxValue - 1 ) ;
yield return null ;
Assert . AreEqual ( Mathf . FloorToInt ( Time . deltaTime / duration ) , t . cyclesDone ) ;
t . Complete ( ) ;
}
}
[UnityTest]
public IEnumerator ExecutionOrder ( ) {
yield return null ;
int i = 0 ;
void validate ( int order ) {
// Debug.Log($"-------------- validate {order}");
Assert . AreEqual ( i , order ) ;
i + + ;
}
{
for ( int k = 0 ; k < 1 ; k + + ) {
yield return Sequence . Create ( 2 )
. Chain ( Tween . Custom ( 0 , 1 , getDur ( ) , delegate { } , startDelay : getDur ( ) , endDelay : getDur ( ) ) . OnComplete ( ( ) = > validate ( 0 ) ) )
. ChainCallback ( ( ) = > validate ( 1 ) )
. Chain ( Tween . Delay ( getDur ( ) , ( ) = > validate ( 2 ) ) )
. Chain ( Tween . Custom ( 0 , 1 , getDur ( ) , delegate { } , startDelay : getDur ( ) , endDelay : getDur ( ) ) . OnComplete ( ( ) = > validate ( 3 ) ) )
. ChainCallback ( ( ) = > validate ( 4 ) )
. ChainCallback ( ( ) = > validate ( 5 ) )
. ChainCallback ( ( ) = > {
validate ( 6 ) ;
i = 0 ;
} )
. ToYieldInstruction ( ) ;
}
}
{
for ( int k = 0 ; k < 1 ; k + + ) {
i = 0 ;
var seq = Sequence . Create ( ) ;
const int iterations = 5 ;
for ( int j = 0 ; j < iterations ; j + + ) {
var expected = j ;
if ( Random . value > 0.5f ) {
seq . Chain ( Tween . Delay ( getDur ( ) , ( ) = > validate ( expected ) ) ) ;
} else {
seq . ChainCallback ( ( ) = > validate ( expected ) ) ;
}
}
seq . ChainCallback ( ( ) = > {
validate ( iterations ) ;
i = 0 ;
} ) ;
seq . SetRemainingCycles ( 2 ) ;
yield return seq . ToYieldInstruction ( ) ;
}
}
float getDur ( ) = > Mathf . Max ( minDuration , getDt ( ) * Mathf . Lerp ( 0.1f , 2f , Random . value ) ) ;
}
static float getDt ( ) = > Application . targetFrameRate ! = - 1 ? 1f / Application . targetFrameRate : Time . deltaTime ;
[Test]
public void ShakeIsDeadOnNewReusableTween ( ) {
var t = new ReusableTween ( ) ;
Assert . IsFalse ( t . shakeData . isAlive ) ;
}
[UnityTest]
public IEnumerator SmallDurationWithInfiniteCycles ( ) {
int numChanged = 0 ;
int numUpdated = 0 ;
const float duration = 0.001f ;
var t = Tween . Custom ( 0f , 1f , duration , cycles : - 1 , onValueChange : delegate {
numChanged + + ;
// print("onValueChange");
} )
. OnUpdate ( this , delegate {
numUpdated + + ;
Assert . AreEqual ( numChanged , numUpdated ) ;
// print("OnUpdate()");
} ) ;
float timeStart = Time . time ;
yield return null ;
yield return null ;
yield return null ;
Assert . AreEqual ( 4 , numChanged ) ;
Assert . AreEqual ( 4 , numUpdated ) ;
var cyclesDoneExpected = Mathf . FloorToInt ( ( Time . time - timeStart ) / duration ) ;
Assert . AreEqual ( cyclesDoneExpected , t . cyclesDone ) ;
t . Complete ( ) ;
}
[UnityTest]
public IEnumerator InvalidOperationExceptionInsideCompleteAllBug ( ) {
for ( int i = 0 ; i < 1 ; i + + ) {
const float upper = 1.5f ;
Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , upper ) , ( ) = > Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , 1.5f ) ) ) ;
Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , upper ) , ( ) = > Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , 1.5f ) ) ) ;
Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , upper ) , ( ) = > Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , 1.5f ) ) ) ;
Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , upper ) , ( ) = > Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , 1.5f ) ) ) ;
Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , upper ) , ( ) = > Tween . Delay ( getDt ( ) * Random . Range ( 0.5f , 1.5f ) ) ) ;
int delayFramesBeforeCompleteAll = Random . Range ( 0 , 0 ) ;
for ( int j = 0 ; j < delayFramesBeforeCompleteAll ; j + + ) {
yield return null ;
}
if ( Random . value > = 0.0f ) {
Tween . CompleteAll ( ) ;
}
}
yield return null ;
}
[UnityTest]
public IEnumerator TweenElapsedTimeTotal ( ) {
var duration = getDt ( ) * 2f ;
var t = Tween . Custom ( 0f , 1f , duration , delegate { } ) ;
var s = Sequence . Create ( 2 )
. ChainDelay ( duration )
. Chain ( t )
. ChainDelay ( duration ) ;
while ( s . isAlive ) {
Assert . IsTrue ( t . elapsedTimeTotal > = 0f ) ;
Assert . IsTrue ( t . elapsedTimeTotal < = t . durationTotal ) ;
yield return null ;
}
}
[Test]
public void SetCyclesWithDelay ( ) {
LogAssert . Expect ( LogType . Error , new Regex ( "Applying cycles to Delay will not repeat" ) ) ;
var delay = Tween . Delay ( this , duration : . 5f , delegate { } ) ;
delay . SetRemainingCycles ( 10 ) ;
delay . Stop ( ) ;
}
[Test]
public void ElapsedTimeTotalIsClamped ( ) {
for ( int i = 0 ; i < 1 ; i + + ) {
float duration = Random . value + 0.001f ;
int cycles = Random . Range ( 3 , 20 ) ;
var t = Tween . Delay ( duration ) ;
t . SetRemainingCycles ( cycles ) ;
t . isPaused = true ;
t . elapsedTime = float . MaxValue ;
Assert . AreEqual ( 1 , t . cyclesDone ) ;
Assert . AreEqual ( duration , t . tween . elapsedTimeTotal ) ;
Assert . AreEqual ( 0f , t . elapsedTime ) ; // new cycles has started, so should be 0f
Assert . AreEqual ( duration , t . elapsedTimeTotal ) ;
t . elapsedTimeTotal = 0f ;
Assert . AreEqual ( 0 , t . cyclesDone ) ;
Assert . AreEqual ( 0f , t . tween . elapsedTimeTotal ) ;
Assert . AreEqual ( 0f , t . elapsedTime ) ;
Assert . AreEqual ( 0f , t . elapsedTimeTotal ) ;
t . elapsedTimeTotal = float . MaxValue ;
Assert . AreEqual ( cycles , t . cyclesDone ) ;
Assert . AreEqual ( t . durationTotal , t . tween . elapsedTimeTotal ) ;
Assert . AreEqual ( t . duration , t . elapsedTime ) ;
Assert . AreEqual ( t . durationTotal , t . elapsedTimeTotal ) ;
Assert . IsTrue ( t . isAlive ) ;
t . Stop ( ) ;
}
}
[UnityTest]
public IEnumerator WarnEndValueEqualsCurrent ( ) {
Assert . AreEqual ( 0 , tweensCount ) ;
var iniPos = Vector3 . one * Random . value ;
{
transform . position = iniPos ;
var t = Tween . Position ( transform , iniPos , 1f ) ;
yield return null ;
LogAssert . Expect ( LogType . Warning , new Regex ( "Tween's 'endValue' equals to the current animated value" ) ) ;
t . Stop ( ) ;
}
{
PrimeTweenConfig . warnEndValueEqualsCurrent = false ;
transform . position = iniPos ;
var t = Tween . Position ( transform , iniPos , 1f ) ;
yield return null ;
t . Stop ( ) ;
PrimeTweenConfig . warnEndValueEqualsCurrent = true ;
}
LogAssert . NoUnexpectedReceived ( ) ;
}
[Test]
public void SetInfiniteTweenElapsedTime ( ) {
var t = Tween . Custom ( 0f , 1f , 0.01f , delegate { } , cycles : - 1 ) ;
for ( int i = 0 ; i < 8 ; i + + ) {
LogAssert . Expect ( LogType . Error , new Regex ( "Invalid elapsedTime" ) ) ;
}
t . elapsedTime = float . MaxValue ; // ok
t . elapsedTime = float . PositiveInfinity ; // ok
t . elapsedTime = - 1f ;
t . elapsedTime = float . NegativeInfinity ;
t . elapsedTime = float . NaN ;
t . elapsedTimeTotal = 0f ; // ok
t . elapsedTimeTotal = 10f ; // ok
t . elapsedTimeTotal = - 1f ;
t . elapsedTimeTotal = float . MaxValue ;
t . elapsedTimeTotal = float . PositiveInfinity ;
t . elapsedTimeTotal = float . NegativeInfinity ;
t . elapsedTimeTotal = float . NaN ;
t . Stop ( ) ;
}
[Test]
public void SetInfiniteTweenProgress ( ) {
var t = Tween . Custom ( 0f , 1f , 0.01f , delegate { } , cycles : - 1 ) ;
Assert . IsTrue ( float . IsPositiveInfinity ( t . durationTotal ) ) ;
// ok
t . progress = 0f ;
t . progress = 0.5f ;
t . progress = 1f ;
for ( int i = 0 ; i < 3 ; i + + ) {
LogAssert . Expect ( LogType . Error , new Regex ( "It's not allowed to set progressTotal on infinite tween" ) ) ;
}
t . progressTotal = 0f ;
t . progressTotal = 0.5f ;
t . progressTotal = 1f ;
Assert . IsTrue ( float . IsPositiveInfinity ( t . durationTotal ) ) ;
t . Stop ( ) ;
}
[UnityTest]
public IEnumerator ZZ_SceneLoadSetsUnityObjectBug1 ( ) {
var t = Tween . Delay ( 1f ) ;
LoadTestScene ( ) ;
yield return null ;
Assert . IsTrue ( t . isAlive ) ;
t . Stop ( ) ;
}
[UnityTest]
public IEnumerator ZZ_SceneLoadSetsUnityObjectBug2 ( ) {
var seq = Sequence . Create ( ) . ChainDelay ( 1f ) ;
LoadTestScene ( ) ;
yield return null ;
Assert . IsTrue ( seq . isAlive ) ;
seq . Stop ( ) ;
}
static void LoadTestScene ( ) {
const string testScenePath = "Packages/com.kyrylokuzyk.primetween/Tests/SceneLoadSetsUnityObjectBug.unity" ;
#if UNITY_EDITOR
if ( Application . isEditor ) {
UnityEditor . SceneManagement . EditorSceneManager . LoadSceneInPlayMode ( testScenePath , new LoadSceneParameters ( LoadSceneMode . Single ) ) ;
return ;
}
#endif
SceneManager . LoadScene ( testScenePath , LoadSceneMode . Single ) ;
}
[UnityTest]
public IEnumerator SetElapsedTimeRecursively ( ) {
Tween t = default ;
int i = 0 ;
t = Tween . Custom ( 0f , 1f , getDt ( ) / 5f , delegate {
// print("custom");
onUpdate ( ) ;
} )
. OnUpdate ( this , delegate {
// print("OnUpdate");
onUpdate ( ) ;
} ) ;
yield return t . ToYieldInstruction ( ) ;
void onUpdate ( ) {
i + + ;
Assert . IsTrue ( i < 100 ) ;
expectRecursiveCallError ( ) ;
t . progress + = 0.01f ;
expectRecursiveCallError ( ) ;
t . progressTotal + = 0.01f ;
expectRecursiveCallError ( ) ;
t . elapsedTime + = 0.01f ;
expectRecursiveCallError ( ) ;
t . elapsedTimeTotal + = 0.01f ;
}
}
[UnityTest]
public IEnumerator CompleteInfiniteTween ( ) {
int numCallbacks = 0 ;
var duration = Mathf . Max ( minDuration , Random . Range ( 0f , getDt ( ) ) ) ;
Assert . IsTrue ( duration > = minDuration ) ;
var t = Tween . Position ( transform , Vector3 . one , duration , cycles : - 1 )
. OnComplete ( ( ) = > numCallbacks + + ) ;
float timeStart = Time . time ;
yield return null ;
yield return null ;
var cyclesDoneExpected = Mathf . FloorToInt ( ( Time . time - timeStart ) / duration ) ;
Assert . AreEqual ( cyclesDoneExpected , t . cyclesDone ) ;
t . Complete ( ) ;
Assert . AreEqual ( 1 , numCallbacks ) ;
}
[Test]
public void CompleteInfiniteTween2 ( ) {
var target = new GameObject ( ) . transform ;
var iniValue = Vector3 . one * 0.5f ;
target . localScale = iniValue ;
var endValue = Vector3 . one * 2f ;
Tween . Scale ( target , endValue , 0.5f , cycles : - 1 , cycleMode : CycleMode . Yoyo ) . Complete ( ) ;
Assert . AreEqual ( endValue , target . localScale ) ;
{
var t = Tween . Scale ( target , iniValue , 0.5f , cycles : - 1 , cycleMode : CycleMode . Yoyo ) ;
t . SetRemainingCycles ( true ) ;
t . Complete ( ) ;
Assert . AreEqual ( iniValue , target . localScale ) ;
}
{
var t = Tween . Scale ( target , endValue , 0.5f , cycles : - 1 , cycleMode : CycleMode . Yoyo ) ;
t . SetRemainingCycles ( false ) ;
t . Complete ( ) ;
Assert . AreEqual ( iniValue , target . localScale ) ;
}
Object . DestroyImmediate ( target . gameObject ) ;
LogAssert . NoUnexpectedReceived ( ) ;
}
[UnityTest]
public IEnumerator WarnEndValueEqualsCurrent2 ( ) {
Tween . StopAll ( ) ;
yield return null ;
{
transform . position = Vector3 . one ;
expectWarning ( ) ;
var t = Tween . Position ( transform , Vector3 . one , 0.01f ) ;
yield return null ;
t . Stop ( ) ;
}
{
transform . position = Vector3 . one ;
PrimeTweenConfig . warnEndValueEqualsCurrent = false ;
var t = Tween . Position ( transform , Vector3 . one , 0.01f ) ;
PrimeTweenConfig . warnEndValueEqualsCurrent = true ;
yield return null ;
t . Stop ( ) ;
}
LogAssert . NoUnexpectedReceived ( ) ;
static void expectWarning ( ) = > LogAssert . Expect ( LogType . Warning , new Regex ( "Tween's 'endValue' equals to the current animated value" ) ) ;
}
[UnityTest]
public IEnumerator SetPropertiesOfInfiniteTween ( ) {
var t = Tween . Custom ( 0 , 1 , 1 , _ = > {
// print(_);
} , cycles : - 1 , cycleMode : CycleMode . Yoyo , ease : Ease . Linear ) ;
t . elapsedTime = 0.5f ;
yield return null ;
t . progress = 0.75f ;
yield return null ;
t . elapsedTimeTotal = 2.1f ;
yield return null ;
t . elapsedTime = 0.5f ;
yield return null ;
t . Stop ( ) ;
}
[Test]
public void NegativeIniCyclesBugReport ( ) {
// https://github.com/KyryloKuzyk/PrimeTween/issues/63
Tween . StopAll ( ) ;
var startValue = Vector3 . one * 10 ;
var endValue = Vector3 . one * 20 ;
transform . position = startValue ;
var posTween = Tween . Position ( transform , startValue , endValue , new TweenSettings ( 1f , cycles : 2 , cycleMode : CycleMode . Rewind ) ) ;
var seq = Sequence . Create ( )
. ChainDelay ( 1f )
. Chain ( posTween ) ;
seq . elapsedTime = 1.1f ;
Assert . AreNotEqual ( 0f , posTween . interpolationFactor ) ;
Assert . AreNotEqual ( startValue , transform . position ) ;
// Assert.AreEqual(-1, posTween.tween.cyclesDone);
seq . elapsedTime = 0.5f ;
Assert . AreEqual ( 0f , posTween . interpolationFactor ) ;
Assert . AreEqual ( startValue , transform . position ) ;
seq . Stop ( ) ;
}
2025-05-15 10:40:15 +08:00
[Test]
public void UpdateTypes ( ) {
var iniUpdateType = PrimeTweenConfig . defaultUpdateType ;
{
Tween . StopAll ( ) ;
var t = Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : default ) ) . tween ;
Assert . AreEqual ( _UpdateType . Update , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . tweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : UpdateType . Update ) ) . tween ;
Assert . AreEqual ( _UpdateType . Update , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . tweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : UpdateType . LateUpdate ) ) . tween ;
Assert . AreEqual ( _UpdateType . LateUpdate , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . lateUpdateTweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : UpdateType . FixedUpdate ) ) . tween ;
Assert . AreEqual ( _UpdateType . FixedUpdate , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . fixedUpdateTweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
UpdateType updateType = default ;
updateType . enumValue = ( _UpdateType ) 100 ;
Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : updateType ) ) ;
LogAssert . Expect ( LogType . Error , "Invalid update type: 100" ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . ShakeLocalPosition ( transform , new ShakeSettings ( Vector3 . one , updateType : default ) ) . tween ;
Assert . AreEqual ( _UpdateType . Update , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . tweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . ShakeLocalPosition ( transform , new ShakeSettings ( Vector3 . one , updateType : UpdateType . Update ) ) . tween ;
Assert . AreEqual ( _UpdateType . Update , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . tweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . ShakeLocalPosition ( transform , new ShakeSettings ( Vector3 . one , updateType : UpdateType . LateUpdate ) ) . tween ;
Assert . AreEqual ( _UpdateType . LateUpdate , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . lateUpdateTweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
var t = Tween . ShakeLocalPosition ( transform , new ShakeSettings ( Vector3 . one , updateType : UpdateType . FixedUpdate ) ) . tween ;
Assert . AreEqual ( _UpdateType . FixedUpdate , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . fixedUpdateTweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
PrimeTweenConfig . defaultUpdateType = UpdateType . FixedUpdate ;
var t = Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : default ) ) . tween ;
Assert . AreEqual ( _UpdateType . FixedUpdate , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . fixedUpdateTweens . Single ( ) ) ;
}
{
Tween . StopAll ( ) ;
PrimeTweenConfig . defaultUpdateType = UpdateType . LateUpdate ;
var t = Tween . Position ( transform , default , new TweenSettings ( 1f , updateType : default ) ) . tween ;
Assert . AreEqual ( _UpdateType . LateUpdate , t . settings . _updateType ) ;
Assert . AreEqual ( t , PrimeTweenManager . Instance . lateUpdateTweens . Single ( ) ) ;
}
Tween . StopAll ( ) ;
#pragma warning disable CS0618 // Type or member is obsolete
Assert . AreEqual ( false , new TweenSettings ( 1f , updateType : default ) . useFixedUpdate ) ;
Assert . AreEqual ( false , new TweenSettings ( 1f , updateType : UpdateType . Update ) . useFixedUpdate ) ;
Assert . AreEqual ( false , new TweenSettings ( 1f , updateType : UpdateType . LateUpdate ) . useFixedUpdate ) ;
Assert . AreEqual ( true , new TweenSettings ( 1f , updateType : UpdateType . FixedUpdate ) . useFixedUpdate ) ;
#pragma warning restore CS0618 // Type or member is obsolete
Assert . AreEqual ( UpdateType . Default , new TweenSettings ( 1f , updateType : default ) . updateType ) ;
PrimeTweenConfig . defaultUpdateType = UpdateType . Update ;
Assert . AreEqual ( UpdateType . Default , new TweenSettings ( 1f , updateType : default ) . updateType ) ;
PrimeTweenConfig . defaultUpdateType = UpdateType . LateUpdate ;
Assert . AreEqual ( UpdateType . Update , new TweenSettings ( 1f , updateType : UpdateType . Update ) . updateType ) ;
Assert . AreEqual ( UpdateType . FixedUpdate , new TweenSettings ( 1f , updateType : UpdateType . FixedUpdate ) . updateType ) ;
PrimeTweenConfig . defaultUpdateType = iniUpdateType ;
}
2025-01-23 10:16:47 +08:00
}
#endif