com.kyrylokuzyk.primetween 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -946,6 +946,17 @@ MonoBehaviour:
946
946
  dependency: 9
947
947
  placeInGlobalScope: 0
948
948
  generateOnlyOverloads: 0
949
+ - description: Color_VisualElement
950
+ methodName: Color
951
+ targetType: UnityEngine.UIElements.VisualElement
952
+ propertyType: 2
953
+ propertyName:
954
+ propertyGetter: style.color.value
955
+ propertySetter: style.color = val
956
+ dotweenMethodName:
957
+ dependency: 9
958
+ placeInGlobalScope: 0
959
+ generateOnlyOverloads: 0
949
960
  - description: VisualElementBackgroundColor_VisualElement
950
961
  methodName: VisualElementBackgroundColor
951
962
  targetType: UnityEngine.UIElements.VisualElement
@@ -957,6 +968,28 @@ MonoBehaviour:
957
968
  dependency: 9
958
969
  placeInGlobalScope: 0
959
970
  generateOnlyOverloads: 0
971
+ - description: VisualElementOpacity_VisualElement
972
+ methodName: VisualElementOpacity
973
+ targetType: UnityEngine.UIElements.VisualElement
974
+ propertyType: 1
975
+ propertyName:
976
+ propertyGetter: style.opacity.value
977
+ propertySetter: style.opacity = val
978
+ dotweenMethodName:
979
+ dependency: 9
980
+ placeInGlobalScope: 0
981
+ generateOnlyOverloads: 0
982
+ - description: Alpha_VisualElement
983
+ methodName: Alpha
984
+ targetType: UnityEngine.UIElements.VisualElement
985
+ propertyType: 1
986
+ propertyName:
987
+ propertyGetter: style.opacity.value
988
+ propertySetter: style.opacity = val
989
+ dotweenMethodName:
990
+ dependency: 9
991
+ placeInGlobalScope: 0
992
+ generateOnlyOverloads: 0
960
993
  - description: OffsetMin_RectTransform
961
994
  methodName: OffsetMin
962
995
  targetType: UnityEngine.RectTransform
@@ -248,9 +248,14 @@ namespace PrimeTween {
248
248
  { // generate enums
249
249
  foreach (var group in methodsData.GroupBy(_ => _.dependency)) {
250
250
  foreach (var data in group) {
251
- text += " ";
252
- var enumName = GetTweenTypeEnumName(data);
251
+ string enumName = GetTweenTypeEnumName(data);
252
+ if (methodDataToEnumName.Values.Contains(enumName)) {
253
+ // skip duplicates like VisualElementColor_VisualElement / Color_VisualElement and VisualElementOpacity_VisualElement / Alpha_VisualElement
254
+ Debug.Log($"skip duplicate {enumName}");
255
+ continue;
256
+ }
253
257
  methodDataToEnumName.Add(data, enumName);
258
+ text += " ";
254
259
  text += enumName;
255
260
  text += ",\n";
256
261
  }
@@ -281,7 +286,10 @@ internal static class Utils {
281
286
  }
282
287
  }
283
288
  foreach (var data in group) {
284
- utilsText += $" case TweenType.{methodDataToEnumName[data]}:\n";
289
+ if (!methodDataToEnumName.TryGetValue(data, out string enumName)) {
290
+ continue;
291
+ }
292
+ utilsText += $" case TweenType.{enumName}:\n";
285
293
  utilsText += $" return (PropType.{data.propertyType}, typeof({getTypeByName(data.targetType).FullName}));\n";
286
294
  }
287
295
  if (shouldWrapInDefine(dependency)) {
@@ -348,6 +356,12 @@ internal static class Utils {
348
356
  static string GetTweenTypeEnumName(MethodGenerationData data) {
349
357
  string result = "";
350
358
  var dependency = data.dependency;
359
+ if (dependency == Dependency.UI_ELEMENTS_MODULE_INSTALLED) {
360
+ if (data.methodName == "Alpha") {
361
+ return "VisualElementOpacity";
362
+ }
363
+ }
364
+
351
365
  if (dependency != Dependency.None) {
352
366
  result += getMethodPrefix(dependency);
353
367
  }
@@ -355,7 +369,7 @@ internal static class Utils {
355
369
  result += "VisualElement";
356
370
  }
357
371
  result += data.methodName;
358
- if ((data.methodName == "Alpha" || data.methodName == "Color") && data.dependency == Dependency.UNITY_UGUI_INSTALLED) {
372
+ if ((data.methodName == "Alpha" || data.methodName == "Color") && dependency == Dependency.UNITY_UGUI_INSTALLED) {
359
373
  result += getTypeByName(data.targetType).Name;
360
374
  } else if (data.methodName == "Scale" && data.propertyType == PropType.Float) {
361
375
  result += "Uniform";
@@ -9,6 +9,10 @@ using AssertionException = UnityEngine.Assertions.AssertionException;
9
9
  public class EditModeTests {
10
10
  [Test]
11
11
  public void TestEditMode() {
12
+ Tween.StopAll();
13
+ Assert.AreEqual(0, PrimeTweenManager.Instance.tweensCount);
14
+ PrimeTweenConfig.warnEndValueEqualsCurrent = false;
15
+ PrimeTweenConfig.warnZeroDuration = false;
12
16
  expectError();
13
17
  Tween.Custom(0, 1, 1, delegate {});
14
18
  var go = new GameObject();
@@ -21,6 +25,7 @@ public class EditModeTests {
21
25
  Tween.Delay(0);
22
26
  expectError();
23
27
  Tween.CompleteAll();
28
+ PrimeTweenConfig.warnEndValueEqualsCurrent = true;
24
29
  expectError();
25
30
  Tween.StopAll();
26
31
  expectError();
@@ -38,17 +43,18 @@ public class EditModeTests {
38
43
  expectError();
39
44
  Tween.GetTweensCount();
40
45
  expectError();
41
- Sequence.Create(new Tween());
46
+ Sequence.Create(Tween.Delay(0.01f));
42
47
 
43
48
  TweenSettings.ValidateCustomCurveKeyframes(AnimationCurve.Linear(0, 0, 1, 1));
44
49
  PrimeTweenConfig.SetTweensCapacity(10);
45
- Assert.Throws<AssertionException>(() => PrimeTweenConfig.defaultEase = Ease.InCirc);
50
+ Assert.DoesNotThrow(() => PrimeTweenConfig.defaultEase = Ease.InCirc);
46
51
  }
47
52
  Object.DestroyImmediate(go);
48
53
  void expectError() {
49
- LogAssert.Expect(LogType.Warning, Constants.editModeWarning);
50
54
  }
51
55
  LogAssert.NoUnexpectedReceived();
56
+ PrimeTweenConfig.warnEndValueEqualsCurrent = true;
57
+ PrimeTweenConfig.warnZeroDuration = true;
52
58
  }
53
59
 
54
60
  #if PRIME_TWEEN_SAFETY_CHECKS
package/Runtime/Easing.cs CHANGED
@@ -166,11 +166,6 @@ namespace PrimeTween {
166
166
  Debug.LogError("Ease.Custom is an invalid type for Easing.Evaluate(). Please choose another Ease type instead.");
167
167
  return interpolationFactor;
168
168
  case Ease.Default:
169
- #if UNITY_EDITOR
170
- if (Constants.warnNoInstance) {
171
- return interpolationFactor;
172
- }
173
- #endif
174
169
  return StandardEasing.Evaluate(interpolationFactor, PrimeTweenManager.Instance.defaultEase);
175
170
  default:
176
171
  return StandardEasing.Evaluate(interpolationFactor, ease);
@@ -1,3 +1,4 @@
1
+ using System;
1
2
  using JetBrains.Annotations;
2
3
  using UnityEngine;
3
4
  using T = PrimeTween.TweenSettings<float>;
@@ -49,21 +50,5 @@ namespace PrimeTween {
49
50
  internal const string nestSequenceTwiceError = "Sequence can be nested in other sequence only once.";
50
51
  internal const string nestTweenTwiceError = "A tween can be added to a sequence only once and can only belong to one sequence.";
51
52
  internal const string addDeadTweenToSequenceError = "It's not allowed to add 'dead' tweens to a sequence.";
52
-
53
- #if UNITY_EDITOR
54
- internal const string editModeWarning = "Please don't call PrimeTween's API in Edit mode (while the scene is not playing).";
55
-
56
- internal static bool warnNoInstance {
57
- get {
58
- if (noInstance) {
59
- Debug.LogWarning(editModeWarning);
60
- return true;
61
- }
62
- return false;
63
- }
64
- }
65
-
66
- internal static bool noInstance => ReferenceEquals(null, PrimeTweenManager.Instance);
67
- #endif
68
53
  }
69
54
  }
@@ -15,9 +15,41 @@ using UnityEditor;
15
15
  namespace PrimeTween {
16
16
  [AddComponentMenu("")]
17
17
  internal class PrimeTweenManager : MonoBehaviour {
18
- internal static PrimeTweenManager Instance;
18
+ #if UNITY_EDITOR || SAFETY_CHECKS
19
+ internal static PrimeTweenManager _instance;
20
+ internal static PrimeTweenManager Instance {
21
+ get {
22
+ if (!HasInstance) {
23
+ if (Application.isEditor) {
24
+ CreateInstance();
25
+ _instance.gameObject.hideFlags = HideFlags.HideAndDontSave;
26
+ } else {
27
+ const string error = nameof(PrimeTweenManager) + " is not created yet. Please add the 'PRIME_TWEEN_EXPERIMENTAL' define to your project, then use '" + nameof(PrimeTweenConfig) + "." + nameof(PrimeTweenConfig.ManualInitialize) + "()' to initialize PrimeTween before '" + nameof(RuntimeInitializeLoadType) + "." + nameof(RuntimeInitializeLoadType.BeforeSceneLoad) + "'.";
28
+ throw new Exception(error);
29
+ }
30
+ } /*else if (_instance == null) { // todo this throws if PrimeTween API is called from OnDestroy(). See the DestructionOrderTest scene. How to detect manual PrimeTweenManager destruction?
31
+ throw new Exception(nameof(PrimeTweenManager) + " was manually destroyed after creation, which is not allowed. Please check you're not destroying all objects manually.");
32
+ }*/
33
+ return _instance;
34
+ }
35
+ private set => _instance = value;
36
+ }
37
+ #else
38
+ internal static PrimeTweenManager Instance;
39
+ #endif
40
+
41
+ internal static bool HasInstance {
42
+ get {
43
+ #if UNITY_EDITOR || SAFETY_CHECKS
44
+ return !ReferenceEquals(null, _instance);
45
+ #else
46
+ return Instance != null;
47
+ #endif
48
+ }
49
+ }
50
+
19
51
  #if UNITY_EDITOR
20
- static bool isHotReload = true;
52
+ static bool isHotReload = true;
21
53
  #endif
22
54
  internal static int customInitialCapacity = -1;
23
55
 
@@ -58,12 +90,30 @@ namespace PrimeTween {
58
90
 
59
91
  [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
60
92
  static void beforeSceneLoad() {
93
+ if (!HasInstance) {
94
+ CreateInstanceAndDontDestroy();
95
+ }
96
+ }
97
+
98
+ internal static void CreateInstanceAndDontDestroy() {
99
+ CreateInstance();
100
+ DontDestroyOnLoad(Instance.gameObject);
101
+ }
102
+
103
+ static void CreateInstance() {
61
104
  #if UNITY_EDITOR
62
105
  isHotReload = false;
63
106
  #endif
64
- Assert.IsNull(Instance);
65
- var go = new GameObject(nameof(PrimeTweenManager));
66
- DontDestroyOnLoad(go);
107
+ GameObject go;
108
+ try {
109
+ go = new GameObject(nameof(PrimeTweenManager));
110
+ } catch (UnityException e) {
111
+ if (e.Message.Contains("is not allowed to be called from a MonoBehaviour constructor")) {
112
+ const string message = "this PrimeTween's API is not allowed to be called from a MonoBehaviour constructor (or instance field initializer).";
113
+ throw new Exception(message);
114
+ }
115
+ throw;
116
+ }
67
117
  var instance = go.AddComponent<PrimeTweenManager>();
68
118
  const int defaultInitialCapacity = 200;
69
119
  instance.init(customInitialCapacity != -1 ? customInitialCapacity : defaultInitialCapacity);
@@ -83,32 +133,63 @@ namespace PrimeTween {
83
133
  }
84
134
 
85
135
  const string manualInstanceCreationIsNotAllowedMessage = "Please don't create the " + nameof(PrimeTweenManager) + " instance manually.";
86
- void Awake() => Assert.IsNull(Instance, manualInstanceCreationIsNotAllowedMessage);
136
+ void Awake() => Assert.IsFalse(HasInstance, manualInstanceCreationIsNotAllowedMessage);
87
137
 
88
138
  #if UNITY_EDITOR
89
139
  [InitializeOnLoadMethod]
90
140
  static void iniOnLoad() {
141
+ float curTime = (float)EditorApplication.timeSinceStartup;
142
+ EditorApplication.update += () => {
143
+ if (Application.isPlaying) {
144
+ return;
145
+ }
146
+ float newTime = (float)EditorApplication.timeSinceStartup;
147
+ float unscaledDeltaTime = newTime - curTime;
148
+ if (unscaledDeltaTime < 1f / 120f) {
149
+ return;
150
+ }
151
+ if (unscaledDeltaTime > 1f / 10f) {
152
+ // Unity Editor doesn't trigger EditorApplication.update when a context menu is open, which results in a big time jump. Clamp dt in this case
153
+ unscaledDeltaTime = 1f / 120f;
154
+ }
155
+ curTime = newTime;
156
+ if (HasInstance && Instance.tweensCount > 0) {
157
+ float deltaTime = unscaledDeltaTime * Time.timeScale;
158
+ Instance.UpdateTweens(_UpdateType.Update, deltaTime, unscaledDeltaTime);
159
+ Instance.UpdateTweens(_UpdateType.LateUpdate, deltaTime, unscaledDeltaTime);
160
+ Instance.UpdateTweens(_UpdateType.FixedUpdate, deltaTime, unscaledDeltaTime);
161
+ }
162
+ };
163
+
91
164
  EditorApplication.playModeStateChanged += state => {
92
- if (state == PlayModeStateChange.EnteredEditMode) {
93
- Instance = null;
94
- customInitialCapacity = -1;
165
+ switch (state) {
166
+ case PlayModeStateChange.EnteredEditMode:
167
+ Instance = null;
168
+ customInitialCapacity = -1;
169
+ break;
170
+ case PlayModeStateChange.ExitingEditMode:
171
+ if (HasInstance) {
172
+ DestroyImmediate(Instance.gameObject);
173
+ Instance = null;
174
+ }
175
+ break;
95
176
  }
96
177
  };
97
178
  if (!isHotReload) {
98
179
  return;
99
180
  }
100
- if (!Application.isPlaying) {
181
+ if (HasInstance) {
182
+ return;
183
+ }
184
+ var instances = Resources.FindObjectsOfTypeAll<PrimeTweenManager>();
185
+ Assert.IsTrue(instances.Length <= 1, instances.Length);
186
+ if (instances.Length == 0) {
187
+ return;
188
+ }
189
+ var foundInScene = instances[0];
190
+ if (foundInScene == null) {
101
191
  return;
102
192
  }
103
- Assert.IsNull(Instance);
104
- var foundInScene =
105
- #if UNITY_2023_1_OR_NEWER
106
- FindAnyObjectByType
107
- #else
108
- FindObjectOfType
109
- #endif
110
- <PrimeTweenManager>();
111
- Assert.IsNotNull(foundInScene);
112
193
  #if PRIME_TWEEN_INSPECTOR_DEBUGGING
113
194
  Debug.LogError("PRIME_TWEEN_INSPECTOR_DEBUGGING doesn't work with 'Recompile And Continue Playing' because Tween.id is serializable but Tween.tween is not.");
114
195
  return;
@@ -118,20 +199,16 @@ namespace PrimeTween {
118
199
  Debug.Log($"All tweens ({count}) were stopped because of 'Recompile And Continue Playing'.");
119
200
  }
120
201
  foundInScene.init(foundInScene.currentPoolCapacity);
202
+ foundInScene.updateDepth = 0;
121
203
  Instance = foundInScene;
122
204
  }
123
205
 
124
206
  void Reset() {
125
207
  Assert.IsFalse(Application.isPlaying);
126
- Debug.LogError(manualInstanceCreationIsNotAllowedMessage);
127
- DestroyImmediate(this);
128
208
  }
129
209
  #endif
130
210
 
131
211
  void Start() {
132
- #if SAFETY_CHECKS
133
- // Selection.activeGameObject = gameObject;
134
- #endif
135
212
  Assert.AreEqual(Instance, this, manualInstanceCreationIsNotAllowedMessage);
136
213
  }
137
214
 
@@ -296,11 +373,6 @@ namespace PrimeTween {
296
373
 
297
374
  /// Returns null if target is a destroyed UnityEngine.Object
298
375
  internal static Tween? delayWithoutDurationCheck([CanBeNull] object target, float duration, bool useUnscaledTime) {
299
- #if UNITY_EDITOR
300
- if (Constants.warnNoInstance) {
301
- return null;
302
- }
303
- #endif
304
376
  var tween = fetchTween();
305
377
  var settings = new TweenSettings {
306
378
  duration = duration,
@@ -315,11 +387,6 @@ namespace PrimeTween {
315
387
 
316
388
  [NotNull]
317
389
  internal static ReusableTween fetchTween() {
318
- #if UNITY_EDITOR
319
- if (Constants.warnNoInstance) {
320
- return new ReusableTween();
321
- }
322
- #endif
323
390
  return Instance.fetchTween_internal();
324
391
  }
325
392
 
@@ -350,22 +417,12 @@ namespace PrimeTween {
350
417
  }
351
418
 
352
419
  internal static void checkDuration<T>([CanBeNull] T target, float duration) where T : class {
353
- #if UNITY_EDITOR
354
- if (Constants.noInstance) {
355
- return;
356
- }
357
- #endif
358
420
  if (Instance.warnZeroDuration && duration <= 0) {
359
421
  Debug.LogWarning($"Tween duration ({duration}) <= 0. {Constants.buildWarningCanBeDisabledMessage(nameof(warnZeroDuration))}", target as UnityEngine.Object);
360
422
  }
361
423
  }
362
424
 
363
425
  internal static Tween addTween([NotNull] ReusableTween tween) {
364
- #if UNITY_EDITOR
365
- if (Constants.noInstance) {
366
- return default;
367
- }
368
- #endif
369
426
  return Instance.addTween_internal(tween);
370
427
  }
371
428
 
@@ -426,11 +483,6 @@ namespace PrimeTween {
426
483
  }
427
484
 
428
485
  internal static int processAll([CanBeNull] object onTarget, [NotNull] Predicate<ReusableTween> predicate, bool allowToProcessTweensInsideSequence) {
429
- #if UNITY_EDITOR
430
- if (Constants.warnNoInstance) {
431
- return default;
432
- }
433
- #endif
434
486
  return Instance.processAll_internal(onTarget, predicate, allowToProcessTweensInsideSequence);
435
487
  }
436
488
 
@@ -2,6 +2,7 @@
2
2
  #define SAFETY_CHECKS
3
3
  #endif
4
4
  using System;
5
+ using System.Runtime.CompilerServices;
5
6
  using JetBrains.Annotations;
6
7
  using UnityEngine;
7
8
  using Debug = UnityEngine.Debug;
@@ -31,7 +32,14 @@ namespace PrimeTween {
31
32
  internal ref ValueContainer startValue => ref startEndValue.startValue;
32
33
  internal ref ValueContainer endValue => ref startEndValue.endValue;
33
34
  internal ValueContainer diff;
34
- internal bool isAdditive;
35
+ internal bool isAdditive {
36
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetFlag(Flags.Additive);
37
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] set => SetFlag(Flags.Additive, value);
38
+ }
39
+ internal bool resetBeforeComplete {
40
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetFlag(Flags.ResetBeforeComplete);
41
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] set => SetFlag(Flags.ResetBeforeComplete, value);
42
+ }
35
43
  internal ValueContainer prevVal;
36
44
  [SerializeField] internal TweenSettings settings;
37
45
  [SerializeField] int cyclesDone;
@@ -62,10 +70,24 @@ namespace PrimeTween {
62
70
  bool stoppedEmergently;
63
71
  internal readonly TweenCoroutineEnumerator coroutineEnumerator = new TweenCoroutineEnumerator();
64
72
  internal float timeScale = 1f;
65
- bool warnIgnoredOnCompleteIfTargetDestroyed = true;
73
+ bool warnIgnoredOnCompleteIfTargetDestroyed {
74
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetFlag(Flags.WarnIgnoredOnCompleteIfTargetDestroyed);
75
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] set => SetFlag(Flags.WarnIgnoredOnCompleteIfTargetDestroyed, value);
76
+ }
66
77
  internal ShakeData shakeData;
78
+ internal bool shakeSign {
79
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetFlag(Flags.ShakeSign);
80
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] set => SetFlag(Flags.ShakeSign, value);
81
+ }
82
+ internal bool isPunch {
83
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetFlag(Flags.ShakePunch);
84
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] set => SetFlag(Flags.ShakePunch, value);
85
+ }
67
86
  State state;
68
- bool warnEndValueEqualsCurrent;
87
+ bool warnEndValueEqualsCurrent {
88
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] get => GetFlag(Flags.WarnEndValueEqualsCurrent);
89
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] set => SetFlag(Flags.WarnEndValueEqualsCurrent, value);
90
+ }
69
91
 
70
92
  internal bool updateAndCheckIfRunning(float dt) {
71
93
  if (!_isAlive) {
@@ -181,6 +203,16 @@ namespace PrimeTween {
181
203
  }
182
204
  Assert.IsTrue(newCyclesDone == cyclesDone, id);
183
205
  if (isDone(cyclesDiff)) {
206
+ if (resetBeforeComplete && isMainSequenceRoot()) {
207
+ // reset Sequence
208
+ foreach (var t in getSequenceSelfChildren(false)) {
209
+ t.tween.updateSequenceChild(0f, true);
210
+ if (isEarlyExitAfterChildUpdate()) {
211
+ goto EarlyExit;
212
+ }
213
+ }
214
+ EarlyExit:;
215
+ }
184
216
  if (isMainSequenceRoot() && !_isPaused) {
185
217
  sequence.releaseTweens();
186
218
  }
@@ -363,11 +395,14 @@ namespace PrimeTween {
363
395
  timeScale = 1f;
364
396
  warnIgnoredOnCompleteIfTargetDestroyed = true;
365
397
  clearOnUpdate();
398
+ resetBeforeComplete = false;
366
399
  }
367
400
 
368
401
  /// <param name="warnIfTargetDestroyed">https://github.com/KyryloKuzyk/PrimeTween/discussions/4</param>
369
- internal void OnComplete([NotNull] Action _onComplete, bool warnIfTargetDestroyed) {
370
- Assert.IsNotNull(_onComplete);
402
+ internal void OnComplete([CanBeNull] Action _onComplete, bool warnIfTargetDestroyed) {
403
+ if (_onComplete == null) {
404
+ return;
405
+ }
371
406
  validateOnCompleteAssignment();
372
407
  warnIgnoredOnCompleteIfTargetDestroyed = warnIfTargetDestroyed;
373
408
  onCompleteCallback = _onComplete;
@@ -382,12 +417,14 @@ namespace PrimeTween {
382
417
  };
383
418
  }
384
419
 
385
- internal void OnComplete<T>([CanBeNull] T _target, [NotNull] Action<T> _onComplete, bool warnIfTargetDestroyed) where T : class {
420
+ internal void OnComplete<T>([CanBeNull] T _target, [CanBeNull] Action<T> _onComplete, bool warnIfTargetDestroyed) where T : class {
386
421
  if (_target == null || isDestroyedUnityObject(_target)) {
387
422
  Debug.LogError($"{nameof(_target)} is null or has been destroyed. {Constants.onCompleteCallbackIgnored}");
388
423
  return;
389
424
  }
390
- Assert.IsNotNull(_onComplete);
425
+ if (_onComplete == null) {
426
+ return;
427
+ }
391
428
  validateOnCompleteAssignment();
392
429
  warnIgnoredOnCompleteIfTargetDestroyed = warnIfTargetDestroyed;
393
430
  onCompleteTarget = _target;
@@ -432,11 +469,6 @@ namespace PrimeTween {
432
469
  tweenType = _tweenType;
433
470
  var propertyType = propType;
434
471
  Assert.AreNotEqual(PropType.None, propertyType);
435
- #if UNITY_EDITOR
436
- if (Constants.noInstance) {
437
- return;
438
- }
439
- #endif
440
472
  if (_settings.ease == Ease.Default) {
441
473
  _settings.ease = PrimeTweenManager.Instance.defaultEase;
442
474
  } else if (_settings.ease == Ease.Custom && _settings.parametricEase == ParametricEase.None) {
@@ -508,6 +540,10 @@ namespace PrimeTween {
508
540
  Assert.IsFalse(startFromCurrent);
509
541
  Assert.IsTrue(timeScale < 0 || cyclesDone == settings.cycles);
510
542
  Assert.IsTrue(timeScale >= 0 || cyclesDone == iniCyclesDone);
543
+ if (resetBeforeComplete && !sequence.IsCreated) {
544
+ // reset Tween
545
+ setElapsedTimeTotal(0f, out _);
546
+ }
511
547
  onComplete?.Invoke(this);
512
548
  }
513
549
 
@@ -849,5 +885,24 @@ namespace PrimeTween {
849
885
  Assert.IsTrue(result >= 0);
850
886
  return result;
851
887
  }
888
+
889
+ [Flags]
890
+ private enum Flags : byte {
891
+ Additive = 1 << 0,
892
+ ShakeSign = 1 << 1,
893
+ ShakePunch = 1 << 2,
894
+ WarnEndValueEqualsCurrent = 1 << 3,
895
+ WarnIgnoredOnCompleteIfTargetDestroyed = 1 << 4,
896
+ ResetBeforeComplete = 1 << 5
897
+ }
898
+ [SerializeField] Flags flags = Flags.WarnIgnoredOnCompleteIfTargetDestroyed; // todo how to show this in the Inspector?
899
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] bool GetFlag(Flags flag) => (flags & flag) != 0;
900
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] void SetFlag(Flags flag, bool value) {
901
+ if (value) {
902
+ flags |= flag;
903
+ } else {
904
+ flags &= ~flag;
905
+ }
906
+ }
852
907
  }
853
908
  }
@@ -42,7 +42,10 @@ namespace PrimeTween {
42
42
  }
43
43
  }
44
44
  int hash = ComputeHash(buf, len);
45
- Assert.AreEqual(id, idToHash.Count);
45
+ if (id != idToHash.Count) {
46
+ Debug.LogError("PRIME_TWEEN_SAFETY_CHECKS doesn't support script hot reloading (Recompile And Continue Playing). Please remove the PRIME_TWEEN_SAFETY_CHECKS define."); // todo fix?
47
+ return;
48
+ }
46
49
  idToHash.Add(hash);
47
50
  if (hashToTraces.TryGetValue(hash, out var traces)) {
48
51
  if (!Contains(traces, buf, len)) {
@@ -135,6 +135,7 @@ namespace PrimeTween {
135
135
  VisualElementTopLeft,
136
136
  VisualElementColor,
137
137
  VisualElementBackgroundColor,
138
+ VisualElementOpacity,
138
139
  TextMaxVisibleCharacters,
139
140
  TextFontSize,
140
141
  }
@@ -1734,6 +1735,24 @@ namespace PrimeTween {
1734
1735
  }, t => (t.target as UnityEngine.UIElements.VisualElement).style.color.value.ToContainer(), TweenType.VisualElementColor);
1735
1736
  }
1736
1737
 
1738
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1739
+ => Color(target, new TweenSettings<UnityEngine.Color>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1740
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1741
+ => Color(target, new TweenSettings<UnityEngine.Color>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1742
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color startValue, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1743
+ => Color(target, new TweenSettings<UnityEngine.Color>(startValue, endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1744
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color startValue, UnityEngine.Color endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1745
+ => Color(target, new TweenSettings<UnityEngine.Color>(startValue, endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1746
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color endValue, TweenSettings settings) => Color(target, new TweenSettings<UnityEngine.Color>(endValue, settings));
1747
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color startValue, UnityEngine.Color endValue, TweenSettings settings) => Color(target, new TweenSettings<UnityEngine.Color>(startValue, endValue, settings));
1748
+ public static Tween Color([NotNull] UnityEngine.UIElements.VisualElement target, TweenSettings<UnityEngine.Color> settings) {
1749
+ return animate(target, ref settings, _tween => {
1750
+ var _target = _tween.target as UnityEngine.UIElements.VisualElement;
1751
+ var val = _tween.ColorVal;
1752
+ _target.style.color = val;
1753
+ }, t => (t.target as UnityEngine.UIElements.VisualElement).style.color.value.ToContainer(), TweenType.VisualElementColor);
1754
+ }
1755
+
1737
1756
  public static Tween VisualElementBackgroundColor([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1738
1757
  => VisualElementBackgroundColor(target, new TweenSettings<UnityEngine.Color>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1739
1758
  public static Tween VisualElementBackgroundColor([NotNull] UnityEngine.UIElements.VisualElement target, UnityEngine.Color endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
@@ -1752,6 +1771,42 @@ namespace PrimeTween {
1752
1771
  }, t => (t.target as UnityEngine.UIElements.VisualElement).style.backgroundColor.value.ToContainer(), TweenType.VisualElementBackgroundColor);
1753
1772
  }
1754
1773
 
1774
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1775
+ => VisualElementOpacity(target, new TweenSettings<float>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1776
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, Single endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1777
+ => VisualElementOpacity(target, new TweenSettings<float>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1778
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1779
+ => VisualElementOpacity(target, new TweenSettings<float>(startValue, endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1780
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, Single startValue, Single endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1781
+ => VisualElementOpacity(target, new TweenSettings<float>(startValue, endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1782
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, Single endValue, TweenSettings settings) => VisualElementOpacity(target, new TweenSettings<float>(endValue, settings));
1783
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, Single startValue, Single endValue, TweenSettings settings) => VisualElementOpacity(target, new TweenSettings<float>(startValue, endValue, settings));
1784
+ public static Tween VisualElementOpacity([NotNull] UnityEngine.UIElements.VisualElement target, TweenSettings<float> settings) {
1785
+ return animate(target, ref settings, _tween => {
1786
+ var _target = _tween.target as UnityEngine.UIElements.VisualElement;
1787
+ var val = _tween.FloatVal;
1788
+ _target.style.opacity = val;
1789
+ }, t => (t.target as UnityEngine.UIElements.VisualElement).style.opacity.value.ToContainer(), TweenType.VisualElementOpacity);
1790
+ }
1791
+
1792
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1793
+ => Alpha(target, new TweenSettings<float>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1794
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, Single endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1795
+ => Alpha(target, new TweenSettings<float>(endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1796
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1797
+ => Alpha(target, new TweenSettings<float>(startValue, endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1798
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, Single startValue, Single endValue, float duration, Easing ease, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
1799
+ => Alpha(target, new TweenSettings<float>(startValue, endValue, new TweenSettings(duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime)));
1800
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, Single endValue, TweenSettings settings) => Alpha(target, new TweenSettings<float>(endValue, settings));
1801
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, Single startValue, Single endValue, TweenSettings settings) => Alpha(target, new TweenSettings<float>(startValue, endValue, settings));
1802
+ public static Tween Alpha([NotNull] UnityEngine.UIElements.VisualElement target, TweenSettings<float> settings) {
1803
+ return animate(target, ref settings, _tween => {
1804
+ var _target = _tween.target as UnityEngine.UIElements.VisualElement;
1805
+ var val = _tween.FloatVal;
1806
+ _target.style.opacity = val;
1807
+ }, t => (t.target as UnityEngine.UIElements.VisualElement).style.opacity.value.ToContainer(), TweenType.VisualElementOpacity);
1808
+ }
1809
+
1755
1810
  #endif
1756
1811
  #if TEXT_MESH_PRO_INSTALLED
1757
1812
  public static Tween TextMaxVisibleCharacters([NotNull] TMPro.TMP_Text target, int endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)
@@ -10,11 +10,6 @@ namespace PrimeTween {
10
10
  /// <summary>Returns the number of alive tweens.</summary>
11
11
  /// <param name="onTarget">If specified, returns the number of running tweens on the target. Please note: if target is specified, this method call has O(n) complexity where n is the total number of running tweens.</param>
12
12
  public static int GetTweensCount([CanBeNull] object onTarget = null) {
13
- #if UNITY_EDITOR
14
- if (Constants.warnNoInstance) {
15
- return default;
16
- }
17
- #endif
18
13
  var manager = PrimeTweenManager.Instance;
19
14
  if (onTarget == null && manager.updateDepth == 0) {
20
15
  int result = manager.tweensCount;
@@ -195,6 +195,8 @@ internal static class Utils {
195
195
  return (PropType.Color, typeof(UnityEngine.UIElements.VisualElement));
196
196
  case TweenType.VisualElementBackgroundColor:
197
197
  return (PropType.Color, typeof(UnityEngine.UIElements.VisualElement));
198
+ case TweenType.VisualElementOpacity:
199
+ return (PropType.Float, typeof(UnityEngine.UIElements.VisualElement));
198
200
  #endif
199
201
  #if TEXT_MESH_PRO_INSTALLED
200
202
  case TweenType.TextMaxVisibleCharacters:
@@ -1,3 +1,4 @@
1
+ using System;
1
2
  using JetBrains.Annotations;
2
3
  using UnityEngine;
3
4
 
@@ -5,14 +6,7 @@ namespace PrimeTween {
5
6
  /// Global PrimeTween configuration.
6
7
  [PublicAPI]
7
8
  public static partial class PrimeTweenConfig {
8
- internal static PrimeTweenManager Instance {
9
- get {
10
- #if UNITY_EDITOR
11
- Assert.IsFalse(Constants.noInstance, Constants.editModeWarning);
12
- #endif
13
- return PrimeTweenManager.Instance;
14
- }
15
- }
9
+ internal static PrimeTweenManager Instance => PrimeTweenManager.Instance;
16
10
 
17
11
  /// <summary>
18
12
  /// If <see cref="PrimeTweenManager"/> instance is already created, <see cref="SetTweensCapacity"/> will allocate garbage,
@@ -30,11 +24,10 @@ namespace PrimeTween {
30
24
  /// </example>
31
25
  public static void SetTweensCapacity(int capacity) {
32
26
  Assert.IsTrue(capacity >= 0);
33
- var instance = PrimeTweenManager.Instance; // should use PrimeTweenManager.Instance because Instance property has a built-in null check
34
- if (instance == null) {
35
- PrimeTweenManager.customInitialCapacity = capacity;
27
+ if (PrimeTweenManager.HasInstance) {
28
+ PrimeTweenManager.Instance.SetTweensCapacity(capacity);
36
29
  } else {
37
- instance.SetTweensCapacity(capacity);
30
+ PrimeTweenManager.customInitialCapacity = capacity;
38
31
  }
39
32
  }
40
33
 
@@ -102,5 +95,19 @@ namespace PrimeTween {
102
95
  Instance.enabled = false;
103
96
  Instance.ApplyStartValues(updateType.enumValue);
104
97
  }
98
+
99
+ #if PRIME_TWEEN_EXPERIMENTAL
100
+ public
101
+ #else
102
+ internal
103
+ #endif
104
+ static void ManualInitialize() {
105
+ if (!PrimeTweenManager.HasInstance) {
106
+ PrimeTweenManager.CreateInstanceAndDontDestroy();
107
+ } else {
108
+ const string error = "'" + nameof(PrimeTweenManager) + "' is already created. Use this method only to create '" + nameof(PrimeTweenManager) + "' before '" + nameof(RuntimeInitializeLoadType) + "." + nameof(RuntimeInitializeLoadType.BeforeSceneLoad) + "'.";
109
+ Debug.LogError(error);
110
+ }
111
+ }
105
112
  }
106
113
  }
@@ -101,11 +101,6 @@ namespace PrimeTween {
101
101
  }
102
102
 
103
103
  public static Sequence Create(int cycles = 1, CycleMode cycleMode = CycleMode.Restart, Ease sequenceEase = Ease.Linear, bool useUnscaledTime = false, UpdateType updateType = default) {
104
- #if UNITY_EDITOR
105
- if (Constants.warnNoInstance) {
106
- return default;
107
- }
108
- #endif
109
104
  var tween = PrimeTweenManager.fetchTween();
110
105
  if (cycleMode == CycleMode.Incremental) {
111
106
  Debug.LogError($"Sequence doesn't support CycleMode.Incremental. Parameter {nameof(sequenceEase)} is applied to the sequence's 'timeline', and incrementing the 'timeline' doesn't make sense. For the same reason, {nameof(sequenceEase)} is clamped to [0:1] range.");
@@ -127,11 +122,6 @@ namespace PrimeTween {
127
122
  }
128
123
 
129
124
  public static Sequence Create(Tween firstTween) {
130
- #if UNITY_EDITOR
131
- if (Constants.warnNoInstance) {
132
- return default;
133
- }
134
- #endif
135
125
  return Create().Group(firstTween);
136
126
  }
137
127
 
@@ -294,22 +284,22 @@ namespace PrimeTween {
294
284
  }
295
285
  var rootTween = root.tween;
296
286
  if (tween._isPaused && tween._isPaused != rootTween._isPaused) {
297
- warnIgnoredChildrenSetting(nameof(isPaused));
287
+ warnIgnoredChildrenSetting(nameof(isPaused), rootTween._isPaused, tween._isPaused);
298
288
  }
299
289
  if (tween.timeScale != 1f && tween.timeScale != rootTween.timeScale) {
300
- warnIgnoredChildrenSetting(nameof(timeScale));
290
+ warnIgnoredChildrenSetting(nameof(timeScale), rootTween.timeScale, tween.timeScale);
301
291
  }
302
292
  if (tween.settings.useUnscaledTime && tween.settings.useUnscaledTime != rootTween.settings.useUnscaledTime) {
303
- warnIgnoredChildrenSetting(nameof(TweenSettings.useUnscaledTime));
293
+ warnIgnoredChildrenSetting(nameof(TweenSettings.useUnscaledTime), rootTween.settings.useUnscaledTime, tween.settings.useUnscaledTime);
304
294
  }
305
- if (tween.settings._updateType != _UpdateType.Default && tween.settings._updateType != rootTween.settings._updateType) {
306
- warnIgnoredChildrenSetting(nameof(TweenSettings.updateType));
295
+ if (tween.settings._updateType != PrimeTweenManager.Instance.defaultUpdateType && tween.settings._updateType != rootTween.settings._updateType) {
296
+ warnIgnoredChildrenSetting(nameof(TweenSettings.updateType), rootTween.settings._updateType, tween.settings._updateType);
307
297
  }
308
- void warnIgnoredChildrenSetting(string settingName) {
309
- Debug.LogError($"'{settingName}' was ignored after adding child animation to the Sequence. Parent Sequence controls '{settingName}' of all its children animations.\n" +
310
- "To prevent this error:\n" +
298
+ void warnIgnoredChildrenSetting(string settingName, object sequenceSetting, object childSetting) {
299
+ Debug.LogError($"'{settingName}' was ignored after adding child animation to the Sequence (Sequence has '{sequenceSetting}', but the child had '{childSetting}').\n" +
300
+ $"Parent Sequence controls '{settingName}' of all its children animations. To prevent this error:\n" +
311
301
  $"- Use the default value of '{settingName}' in child animation.\n" +
312
- $"- OR use the same '{settingName}' in child animation.\n\n");
302
+ $"- OR use the same '{settingName}' in child animation.\n");
313
303
  }
314
304
  return true;
315
305
  }
@@ -613,5 +603,13 @@ namespace PrimeTween {
613
603
 
614
604
  public override int GetHashCode() => root.GetHashCode();
615
605
  public bool Equals(Sequence other) => root.Equals(other.root);
606
+
607
+ #if PRIME_TWEEN_EXPERIMENTAL
608
+ public
609
+ #endif
610
+ Sequence ResetBeforeComplete() {
611
+ root.ResetBeforeComplete();
612
+ return this;
613
+ }
616
614
  }
617
615
  }
package/Runtime/Shake.cs CHANGED
@@ -108,7 +108,7 @@ namespace PrimeTween {
108
108
 
109
109
  static void prepareShakeData(ShakeSettings settings, [NotNull] ReusableTween tween) {
110
110
  tween.endValue.Reset(); // not used
111
- tween.shakeData.Setup(settings);
111
+ tween.shakeData.Setup(settings, tween);
112
112
  }
113
113
 
114
114
  static Vector3 getShakeVal([NotNull] ReusableTween tween) {
@@ -145,13 +145,11 @@ namespace PrimeTween {
145
145
  #endif
146
146
  internal struct ShakeData {
147
147
  float t;
148
- bool sign;
149
148
  Vector3 from, to;
150
149
  float symmetryFactor;
151
150
  int falloffEaseInt;
152
151
  AnimationCurve customStrengthOverTime;
153
152
  Ease easeBetweenShakes;
154
- bool isPunch;
155
153
  const int disabledFalloff = -42;
156
154
  internal bool isAlive => frequency != 0f;
157
155
  internal Vector3 strengthPerAxis { get; private set; }
@@ -159,8 +157,8 @@ namespace PrimeTween {
159
157
  float prevInterpolationFactor;
160
158
  int prevCyclesDone;
161
159
 
162
- internal void Setup(ShakeSettings settings) {
163
- isPunch = settings.isPunch;
160
+ internal void Setup(ShakeSettings settings, ReusableTween tween) {
161
+ tween.isPunch = settings.isPunch;
164
162
  symmetryFactor = Mathf.Clamp01(1 - settings.asymmetry);
165
163
  {
166
164
  var _strength = settings.strength;
@@ -207,14 +205,14 @@ namespace PrimeTween {
207
205
  }
208
206
  easeBetweenShakes = _easeBetweenShakes;
209
207
  }
210
- onCycleComplete();
208
+ onCycleComplete(tween);
211
209
  }
212
210
 
213
- internal void onCycleComplete() {
211
+ internal void onCycleComplete(ReusableTween tween) {
214
212
  Assert.IsTrue(isAlive);
215
213
  resetAfterCycle();
216
- sign = isPunch || Random.value < 0.5f;
217
- to = generateShakePoint();
214
+ tween.shakeSign = tween.isPunch || Random.value < 0.5f;
215
+ to = generateShakePoint(tween);
218
216
  }
219
217
 
220
218
  static int getMainAxisIndex(Vector3 strengthByAxis) {
@@ -238,7 +236,7 @@ namespace PrimeTween {
238
236
  int cyclesDiff = tween.getCyclesDone() - prevCyclesDone;
239
237
  prevCyclesDone = tween.getCyclesDone();
240
238
  if (interpolationFactor == 0f || (cyclesDiff > 0 && tween.getCyclesDone() != tween.settings.cycles)) {
241
- onCycleComplete();
239
+ onCycleComplete(tween);
242
240
  prevInterpolationFactor = interpolationFactor;
243
241
  }
244
242
 
@@ -255,15 +253,15 @@ namespace PrimeTween {
255
253
  }
256
254
  t += frequency * dt * frequencyFactor * getIniVelFactor();
257
255
  if (t < 0f || t >= 1f) {
258
- sign = !sign;
256
+ tween.shakeSign = !tween.shakeSign;
259
257
  if (t < 0f) {
260
258
  t = 1f;
261
259
  to = from;
262
- from = generateShakePoint();
260
+ from = generateShakePoint(tween);
263
261
  } else {
264
262
  t = 0f;
265
263
  from = to;
266
- to = generateShakePoint();
264
+ to = generateShakePoint(tween);
267
265
  }
268
266
  }
269
267
 
@@ -274,13 +272,13 @@ namespace PrimeTween {
274
272
  return result;
275
273
  }
276
274
 
277
- Vector3 generateShakePoint() {
275
+ Vector3 generateShakePoint(ReusableTween tween) {
278
276
  var mainAxisIndex = getMainAxisIndex(strengthPerAxis);
279
277
  Vector3 result = default;
280
- float signFloat = sign ? 1f : -1f;
278
+ float signFloat = tween.shakeSign ? 1f : -1f;
281
279
  for (int i = 0; i < 3; i++) {
282
280
  var strength = strengthPerAxis[i];
283
- if (isPunch) {
281
+ if (tween.isPunch) {
284
282
  result[i] = clampBySymmetryFactor(strength * signFloat, strength, symmetryFactor);
285
283
  } else {
286
284
  result[i] = i == mainAxisIndex ? calcMainAxisEndVal(signFloat, strength, symmetryFactor) : calcNonMainAxisEndVal(strength, symmetryFactor);
package/Runtime/Tween.cs CHANGED
@@ -276,7 +276,7 @@ namespace PrimeTween {
276
276
 
277
277
  /// <summary>Adds completion callback. Please consider using <see cref="OnComplete{T}"/> to prevent a possible capture of variable into a closure.</summary>
278
278
  /// <param name="warnIfTargetDestroyed">Set to 'false' to disable the error about target's destruction. Please note that the the <see cref="onComplete"/> callback will be silently ignored in the case of target's destruction. More info: https://github.com/KyryloKuzyk/PrimeTween/discussions/4</param>
279
- public Tween OnComplete(Action onComplete, bool warnIfTargetDestroyed = true) {
279
+ public Tween OnComplete([CanBeNull] Action onComplete, bool warnIfTargetDestroyed = true) {
280
280
  if (validateIsAlive()) {
281
281
  tween.OnComplete(onComplete, warnIfTargetDestroyed);
282
282
  }
@@ -291,7 +291,7 @@ namespace PrimeTween {
291
291
  /// Tween.PositionX(transform, endValue: 1.5f, duration: 1f)
292
292
  /// .OnComplete(transform, _transform =&gt; Destroy(_transform.gameObject));
293
293
  /// </code></example>
294
- public Tween OnComplete<T>([NotNull] T target, Action<T> onComplete, bool warnIfTargetDestroyed = true) where T : class {
294
+ public Tween OnComplete<T>([NotNull] T target, [CanBeNull] Action<T> onComplete, bool warnIfTargetDestroyed = true) where T : class {
295
295
  if (validateIsAlive()) {
296
296
  tween.OnComplete(target, onComplete, warnIfTargetDestroyed);
297
297
  }
@@ -336,5 +336,17 @@ namespace PrimeTween {
336
336
  public override int GetHashCode() => id.GetHashCode();
337
337
  /// https://www.jacksondunstan.com/articles/5148
338
338
  public bool Equals(Tween other) => isAlive && other.isAlive && id == other.id;
339
+
340
+ #if PRIME_TWEEN_EXPERIMENTAL
341
+ public
342
+ #else
343
+ internal
344
+ #endif
345
+ Tween ResetBeforeComplete() {
346
+ if (validateIsAlive()) {
347
+ tween.resetBeforeComplete = true;
348
+ }
349
+ return this;
350
+ }
339
351
  }
340
352
  }
@@ -4,7 +4,7 @@ using UnityEngine;
4
4
 
5
5
  public class DestructionOrderTest : MonoBehaviour {
6
6
  void OnDestroy() {
7
- print($"PrimeTweenManager.Instance == null: {PrimeTweenManager.Instance == null}");
7
+ print($"PrimeTweenManager.HasInstance: {PrimeTweenManager.HasInstance}, PrimeTweenManager._instance != null:{PrimeTweenManager._instance != null}");
8
8
  Tween.StopAll(transform);
9
9
  Tween.CompleteAll(transform);
10
10
  Tween.Custom(0, 1, 1, delegate {});
@@ -2,23 +2,73 @@
2
2
  // ReSharper disable NotAccessedField.Local
3
3
  // ReSharper disable UnusedMember.Local
4
4
  // ReSharper disable PartialTypeWithSinglePart
5
+ using System;
5
6
  using PrimeTween;
6
7
  using UnityEngine;
7
8
  using Assert = NUnit.Framework.Assert;
8
- using AssertionException = UnityEngine.Assertions.AssertionException;
9
9
 
10
10
  [ExecuteInEditMode]
11
11
  public partial class EditModeTest : MonoBehaviour {
12
- [SerializeField] TweenSettings _settings = new TweenSettings(1, AnimationCurve.Linear(0, 0, 1, 1));
13
- Tween tween = test();
14
- Sequence sequence = Sequence.Create();
15
-
16
- static Tween test() {
17
- Assert.IsTrue(Constants.noInstance, "This test is designed only for Edit mode.");
18
- PrimeTweenConfig.SetTweensCapacity(10);
19
- Assert.Throws<AssertionException>(() => PrimeTweenConfig.warnZeroDuration = false);
12
+ [SerializeField] TweenSettings _settings = CreateSettings();
13
+ static TweenSettings CreateSettings() {
14
+ TweenSettings res = default;
15
+ if (!PrimeTweenManager.HasInstance) {
16
+ ExpectConstructorException(() => res = new TweenSettings(1, AnimationCurve.Linear(0, 0, 1, 1)));
17
+ }
18
+ return res;
19
+ }
20
+
21
+ Tween tween = TestConstructor();
22
+
23
+ static Tween TestConstructor() {
24
+ if (PrimeTweenManager.HasInstance) {
25
+ if (PrimeTweenManager.Instance.tweensCount > 0) {
26
+ ExpectConstructorException(() => Tween.StopAll());
27
+ }
28
+ return TestRegular();
29
+ }
30
+ ExpectConstructorException(() => Sequence.Create());
31
+ ExpectConstructorException(() => PrimeTweenConfig.SetTweensCapacity(PrimeTweenManager.Instance.currentPoolCapacity + 1));
32
+ ExpectConstructorException(() => PrimeTweenConfig.warnZeroDuration = !PrimeTweenConfig.warnZeroDuration);
33
+ ExpectConstructorException(() => Tween.GlobalTimeScale(1f, 0.1f));
34
+ ExpectConstructorException(() => Tween.GetTweensCount());
35
+ ExpectConstructorException(() => {
36
+ Sequence.Create()
37
+ .ChainCallback(() => {})
38
+ .InsertCallback(0f, delegate {})
39
+ .Group(StartTween())
40
+ .Chain(StartTween())
41
+ .Insert(0f, Sequence.Create())
42
+ .Insert(0, StartTween());
43
+ });
44
+ ExpectConstructorException(() => Tween.Delay(new object(), 1f, () => {}));
45
+ ExpectConstructorException(() => Tween.Delay(new object(), 1f, _ => {}));
46
+ ExpectConstructorException(() => Tween.Delay(1f, () => { }));
47
+ ExpectConstructorException(() => Tween.Custom(0, 1, 1, delegate {}));
48
+ return default;
49
+ }
50
+
51
+ static void ExpectConstructorException(Action action) {
52
+ try {
53
+ action();
54
+ // Assert.Fail(nameof(action) + " should throw when called from constructor."); // calling Unity API is allowed from constructor when Editor is opening for the first time, so this assertion is commented out
55
+ } catch (Exception e) {
56
+ string message = e.Message;
57
+ Assert.IsTrue(message.Contains("is not allowed to be called from a MonoBehaviour constructor"), message);
58
+ }
59
+ }
60
+
61
+ static void test() {
20
62
  Tween.StopAll();
21
- Tween.GlobalTimeScale(0.5f, 0.1f);
63
+ TestRegular();
64
+ }
65
+
66
+ static Tween TestRegular() {
67
+ PrimeTweenConfig.SetTweensCapacity(PrimeTweenManager.Instance.currentPoolCapacity + 1);
68
+ Assert.DoesNotThrow(() => PrimeTweenConfig.warnZeroDuration = false);
69
+ PrimeTweenConfig.warnEndValueEqualsCurrent = false;
70
+ Tween.GlobalTimeScale(1f, 0.1f);
71
+ PrimeTweenConfig.warnEndValueEqualsCurrent = true;
22
72
  Tween.GetTweensCount();
23
73
  Sequence.Create()
24
74
  .ChainCallback(() => {})
@@ -27,7 +77,7 @@ public partial class EditModeTest : MonoBehaviour {
27
77
  .Chain(StartTween())
28
78
  .Insert(0f, Sequence.Create())
29
79
  .Insert(0, StartTween());
30
- Tween.Delay(new object(), 1f, () => { });
80
+ Tween.Delay(new object(), 1f, () => {});
31
81
  Tween.Delay(new object(), 1f, _ => {});
32
82
  Tween.Delay(1f, () => { });
33
83
  return Tween.Custom(0, 1, 1, delegate {});
@@ -45,8 +95,8 @@ public partial class EditModeTest : MonoBehaviour {
45
95
 
46
96
  /*[UnityEditor.InitializeOnLoad]
47
97
  public partial class EditModeTest {
48
- static EditModeTest() => test();
49
- EditModeTest() => test();
98
+ static EditModeTest() => TestConstructor();
99
+ EditModeTest() => TestConstructor();
50
100
 
51
101
  [RuntimeInitializeOnLoadMethod]
52
102
  static void runtimeInitOnLoad() => test();
package/Tests/Sequence.cs CHANGED
@@ -351,6 +351,10 @@ public partial class Tests {
351
351
  seq.Chain(createSequenceWithNonDefaultSettings());
352
352
  LogAssert.NoUnexpectedReceived();
353
353
 
354
+ Sequence.Create(updateType: UpdateType.FixedUpdate)
355
+ .Group(Tween.PositionY(transform, new(5, 0.1f)))
356
+ .ChainCallback(() => {});
357
+
354
358
  return;
355
359
 
356
360
  static void expectErrors() {
package/changelog.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [1.3.2] - 2025-05-18
2
+ ### Fixed
3
+ - Fixed: the 'updateType was ignored' error appears if a tween with default 'updateType' is added to a Sequence. https://github.com/KyryloKuzyk/PrimeTween/issues/171
4
+
5
+ ## [1.3.1] - 2025-04-27
6
+ ### Added
7
+ - Add Edit mode support, so animations can be played in Editor without entering the Play mode. https://github.com/KyryloKuzyk/PrimeTween/discussions/62
8
+ - PrimeTween can now be installed via Unity Package Manager.
9
+ - Demo project: add 'Play Animation' button to Inspector to preview animations in Edit mode without entering Play mode.
10
+ - Add the experimental `ResetAfterComplete()` method to reset animations to the initial value before completion. https://github.com/KyryloKuzyk/PrimeTween/discussions/153
11
+ - Add the experimental `PrimeTweenConfig.ManualInitialize()` to initialize PrimeTween before `RuntimeInitializeLoadType.BeforeSceneLoad`. https://github.com/KyryloKuzyk/PrimeTween/issues/150
12
+ - Add `Tween.VisualElementOpacity()` method to animate the `VisualElement.style.opacity` property. Also, extend `Tween.Color/Alpha` methods to also work with VisualElement.
13
+ ### Changed
14
+ - Passing `null` to `OnComplete()` is now allowed and no longer results in an error. https://github.com/KyryloKuzyk/PrimeTween/discussions/164
15
+ ### Fixed
16
+ - Fixed: PrimeTween doesn't work after scripts are recompiled while playing in Editor when the 'Recompile And Continue Playing' setting is enabled.
17
+
1
18
  ## [1.3.0] - 2025-04-04
2
19
  ### Added
3
20
  - Add support for updating animations in LateUpdate with the help of the new 'UpdateType updateType' parameter. The available options are Update, LateUpdate, and FixedUpdate. https://github.com/KyryloKuzyk/PrimeTween/issues/138
package/license.md CHANGED
@@ -1,10 +1,12 @@
1
- PrimeTween is licensed under the Asset Store EULA:
2
- https://unity3d.com/legal/as_terms
1
+ It's **allowed**:
2
+ - Use PrimeTween and modify its source code in **free and commercial** products distributed in binary format (apps and games).
3
+ - Use PrimeTween in derivative (free and commercial) projects (templates, libraries, GitHub projects) that depend on PrimeTween, but only if PrimeTween is installed as an [**NPM package**](https://github.com/KyryloKuzyk/PrimeTween#install-via-unity-package-manager-upm).
3
4
 
4
- In short, it's allowed to use and modify PrimeTween in products distributed in binary format (apps and games).
5
- But it's not allowed to redistribute it or create derivative libraries based on PrimeTween.
5
+ It's **not allowed**:
6
+ - Distribute PrimeTween's source code and tarball (.tgz) archive inside derivative products. To build templates or libraries that depend on PrimeTween, use the NPM installation method instead.
7
+ - Distribute, resell, or claim PrimeTween's ownership even if modified.
8
+ - Resell PrimeTween by itself or as part of another library or asset pack.
6
9
 
7
- To create other libraries that depend on PrimeTween, please refer to this forum post:
8
- https://forum.unity.com/threads/1479609/page-4#post-9587461
10
+ **In short**: you can use PrimeTween in your Unity projects, including commercial ones, but you can’t repackage or resell PrimeTween itself.
9
11
 
10
- Copyright: Kyrylo Kuzyk 2023
12
+ Copyright: Kyrylo Kuzyk 2023
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "com.kyrylokuzyk.primetween",
3
3
  "displayName": "PrimeTween",
4
- "version": "1.3.0",
4
+ "version": "1.3.2",
5
5
  "unity": "2018.4",
6
6
  "author": {
7
7
  "name": "Kyrylo Kuzyk"
@@ -32,9 +32,13 @@
32
32
  "Animate"
33
33
  ],
34
34
  "documentationUrl": "https://github.com/KyryloKuzyk/PrimeTween",
35
+ "changelogUrl": "https://github.com/KyryloKuzyk/PrimeTween/blob/main/changelog.md",
36
+ "_upm": {
37
+ "changelog": "### Fixed\n- Fixed: the 'updateType was ignored' error appears if a tween with default 'updateType' is added to a Sequence. https://github.com/KyryloKuzyk/PrimeTween/issues/171"
38
+ },
35
39
  "repository": {
36
40
  "url": "git@bitbucket.org:stampedegames/primetween.git",
37
41
  "type": "git",
38
- "revision": "35bc62132b4f2ee6a369863fd55f2e59a038f028"
42
+ "revision": "3cecdc457560520e4d1945a66ab3e26029619f2a"
39
43
  }
40
44
  }
@@ -11,6 +11,7 @@ PrimeTween is a high-performance, **allocation-free** animation library for Unit
11
11
  Table of Contents
12
12
  ---
13
13
  - [Getting started](#getting-started)
14
+ * [Installation](#installation)
14
15
  * [Animations](#animations)
15
16
  * [Shakes](#shakes)
16
17
  * [Callbacks](#callbacks)
@@ -29,6 +30,7 @@ Table of Contents
29
30
  + [Speed-based animations](#speed-based-animations)
30
31
  + [Custom easing](#custom-easing)
31
32
  + [LateUpdate/FixedUpdate](#lateupdatefixedupdate)
33
+ + [Install via Unity Package Manager (UPM)](#install-via-unity-package-manager-upm)
32
34
  - [Zero allocations with delegates](#zero-allocations-with-delegates)
33
35
  - [Debugging tweens](#debugging-tweens)
34
36
  - [Migrating from DOTween to PrimeTween](#migrating-from-dotween-to-primetween)
@@ -42,7 +44,8 @@ Getting started
42
44
  ---
43
45
 
44
46
  ### Installation
45
- Import PrimeTween from [Asset Store](https://assetstore.unity.com/packages/slug/252960).
47
+ Import PrimeTween from [Asset Store](https://assetstore.unity.com/packages/slug/252960).
48
+ Optional: install via Unity [Package Manager](#install-via-unity-package-manager-upm) (UPM).
46
49
 
47
50
  ### Animations
48
51
  Without further ado, let's jump straight to the code!
@@ -359,7 +362,7 @@ Available parametric eases:
359
362
  ### LateUpdate/FixedUpdate
360
363
  Use `updateType` parameter to chose which Unity even function will update the animation. The available options are Update, LateUpdate, and FixedUpdate.
361
364
  ```csharp
362
- // Use TweenSettings or TweenSettings<T> struct to pass the 'lateUpdate' parameter to static 'Tween.' methods
365
+ // Use TweenSettings or TweenSettings<T> struct to pass the 'updateType' parameter to static 'Tween.' methods
363
366
  Tween.PositionX(transform, endValue: 10f, new TweenSettings(duration: 1f, updateType: UpdateType.LateUpdate));
364
367
 
365
368
  var tweenSettingsFloat = new TweenSettings<float>(endValue: 10f, duration: 1f, updateType: UpdateType.FixedUpdate);
@@ -369,6 +372,33 @@ Tween.PositionX(transform, tweenSettingsFloat);
369
372
  Sequence.Create(updateType: UpdateType.FixedUpdate);
370
373
  ```
371
374
 
375
+ ### Install via Unity Package Manager (UPM)
376
+ The Package Manager installation method allows to include PrimeTween in derivative (free and commercial) projects (templates, libraries, GitHub repositories). For more info, see the [license](https://github.com/KyryloKuzyk/PrimeTween?tab=License-1-ov-file).
377
+ This installation method also helps to clean the project structure.
378
+ - Open 'Edit / Project Settings / Package Manager'.
379
+ - Add a new Scoped Registry with Name: `npm` URL: `https://registry.npmjs.org` Scope(s): `com.kyrylokuzyk`.
380
+ - Go to 'Window / Package Manager / Packages / My Registries'.
381
+ - Install the PrimeTween package.
382
+
383
+ Or modify the `Packages/manifest.json' file manually:
384
+ ```json
385
+ {
386
+ "dependencies": {
387
+ "com.kyrylokuzyk.primetween": "1.3.2",
388
+ ...
389
+ },
390
+ "scopedRegistries": [
391
+ {
392
+ "name": "npm",
393
+ "url": "https://registry.npmjs.org/",
394
+ "scopes": [
395
+ "com.kyrylokuzyk"
396
+ ]
397
+ }
398
+ ]
399
+ }
400
+ ```
401
+
372
402
  Zero allocations with delegates
373
403
  ---
374
404
  C# delegates is a powerful language feature essential for game development. It gives us the ability to receive callbacks and pass methods to other methods. But when delegates are used in hot code paths carelessly, they can create [performance issues](https://www.jacksondunstan.com/articles/3765).
File without changes