/// <summary> /// If speed based duration was not already set (meaning OnStart has not yet been called), /// calculates the duration and then resets the tween so that OnStart can be called from scratch. /// Used by Sequences when Appending/Prepending/Inserting speed based tweens. /// </summary> internal void ForceSetSpeedBasedDuration() { if (!_speedBased || plugins == null) { return; } int pluginsCount = plugins.Count; for (int i = 0; i < pluginsCount; ++i) { plugins[i].ForceSetSpeedBasedDuration(); } _duration = 0; for (int i = 0; i < pluginsCount; ++i) { ABSTweenPlugin plug = plugins[i]; if (plug.duration > _duration) { _duration = plug.duration; } } SetFullDuration(); }
/// <summary>Tweens a property or field to the given value using a custom plugin</summary> /// <param name="plugin">The plugin to use. Each custom plugin implements a static <code>Get()</code> method /// you'll need to call to assign the correct plugin in the correct way, like this: /// <para><code>CustomPlugin.Get()</code></para></param> /// <param name="getter">A getter for the field or property to tween. /// <para>Example usage with lambda:</para><code>()=> myProperty</code></param> /// <param name="setter">A setter for the field or property to tween /// <para>Example usage with lambda:</para><code>x=> myProperty = x</code></param> /// <param name="endValue">The end value to reach</param><param name="duration">The tween's duration</param> public static TweenerCore <T1, T2, TPlugOptions> To <T1, T2, TPlugOptions>( ABSTweenPlugin <T1, T2, TPlugOptions> plugin, DOGetter <T1> getter, DOSetter <T1> setter, T2 endValue, float duration ) where TPlugOptions : struct { return(ApplyTo(getter, setter, endValue, duration, plugin)); }
void Rewind(bool p_play, bool p_skipDelay) { if (!_enabled || _destroyed) { return; } Startup(); if (!_hasStarted) { OnStart(); } if (!_enabled || _destroyed) { return; // Killed in the OnStart callback } _isComplete = false; _isLoopingBack = false; delayCount = (p_skipDelay ? 0 : _delay); _elapsedDelay = (p_skipDelay ? _delay : 0); _completedLoops = 0; _fullElapsed = _elapsed = 0; int pluginsCount = plugins.Count; for (int i = 0; i < pluginsCount; ++i) { ABSTweenPlugin plug = plugins[i]; if (plug.easeReversed) { plug.ReverseEase(); } plug.Rewind(); } // Manage OnUpdate and OnRewinded. if (_fullElapsed != prevFullElapsed) { OnUpdate(); if (_fullElapsed == 0) { OnRewinded(); } } prevFullElapsed = _fullElapsed; if (p_play) { Play(); } else { Pause(); } }
/// <summary> /// Manages on plugin results behaviour. /// </summary> protected void OnPluginUpdated(ABSTweenPlugin p_plugin) { if (steadyIgnoreCallbacks || ignoreCallbacks) { return; } if (onPluginUpdated != null) { onPluginUpdated(); } else if (onPluginUpdatedWParms != null) { onPluginUpdatedWParms(new TweenEvent(this, onPluginUpdatedParms, p_plugin)); } }
static TweenerCore <T1, T2, TPlugOptions> ApplyTo <T1, T2, TPlugOptions>( DOGetter <T1> getter, DOSetter <T1> setter, T2 endValue, float duration, ABSTweenPlugin <T1, T2, TPlugOptions> plugin = null ) where TPlugOptions : struct { InitCheck(); TweenerCore <T1, T2, TPlugOptions> tweener = TweenManager.GetTweener <T1, T2, TPlugOptions>(); if (!Tweener.Setup(tweener, getter, setter, endValue, duration, plugin)) { TweenManager.Despawn(tweener); return(null); } return(tweener); }
/// <summary> /// If this Tweener contains a <see cref="PlugVector3Path"/>, returns it. /// Otherwise returns null. /// </summary> /// <returns></returns> private PlugVector3Path GetPlugVector3PathPlugin() { if (plugins == null) { return(null); } int pluginsCount = plugins.Count; for (int i = 0; i < pluginsCount; ++i) { ABSTweenPlugin plug = plugins[i]; PlugVector3Path plugVector3Path = plug as PlugVector3Path; if (plugVector3Path != null) { return(plugVector3Path); } } return(null); }
/// <summary> /// Startup this tween /// (might or might not call OnStart, depending if the tween is in a Sequence or not). /// Can be executed only once per tween. /// </summary> /// <param name="p_force">If TRUE forces startup even if it had already been executed</param> void Startup(bool p_force) { if (!p_force && startupDone || plugins == null) { return; } int pluginsCount = plugins.Count; for (int i = 0; i < pluginsCount; ++i) { ABSTweenPlugin plug = plugins[i]; if (!plug.wasStarted) { plug.Startup(); } } if (_speedBased) { // Reset duration based on value changes and speed. // Can't be done sooner because it needs to startup the plugins first. _originalNonSpeedBasedDuration = _duration; _duration = 0; for (int i = 0; i < pluginsCount; ++i) { ABSTweenPlugin plug = plugins[i]; if (plug.duration > _duration) { _duration = plug.duration; } } SetFullDuration(); } else if (p_force) { SetFullDuration(); // Reset full duration } base.Startup(); }
// =================================================================================== // INTERNAL METHODS ------------------------------------------------------------------ // CALLED BY DOTween when spawning/creating a new Tweener. // Returns TRUE if the setup is successful internal static bool Setup <T1, T2, TPlugOptions>( TweenerCore <T1, T2, TPlugOptions> t, DOGetter <T1> getter, DOSetter <T1> setter, T2 endValue, float duration, ABSTweenPlugin <T1, T2, TPlugOptions> plugin = null ) where TPlugOptions : struct { if (plugin != null) { t.tweenPlugin = plugin; } else { if (t.tweenPlugin == null) { t.tweenPlugin = PluginsManager.GetDefaultPlugin <T1, T2, TPlugOptions>(); } if (t.tweenPlugin == null) { // No suitable plugin found. Kill Debugger.LogError("No suitable plugin found for this type"); return(false); } } t.getter = getter; t.setter = setter; t.endValue = endValue; t.duration = duration; // Defaults t.autoKill = DOTween.defaultAutoKill; t.isRecyclable = DOTween.defaultRecyclable; t.easeType = DOTween.defaultEaseType; // Set to INTERNAL_Zero in case of 0 duration, but in DoStartup t.easeOvershootOrAmplitude = DOTween.defaultEaseOvershootOrAmplitude; t.easePeriod = DOTween.defaultEasePeriod; t.loopType = DOTween.defaultLoopType; t.isPlaying = DOTween.defaultAutoPlay == AutoPlay.All || DOTween.defaultAutoPlay == AutoPlay.AutoPlayTweeners; return(true); }
/// <summary> /// Updates the Tweener by the given elapsed time, /// and returns a value of <c>true</c> if the Tweener is complete. /// </summary> /// <param name="p_shortElapsed"> /// The elapsed time since the last update. /// </param> /// <param name="p_forceUpdate"> /// If <c>true</c> forces the update even if the Tweener is complete or paused, /// but ignores onUpdate, and sends onComplete and onStepComplete calls only if the Tweener wasn't complete before this call. /// </param> /// <param name="p_isStartupIteration"> /// If <c>true</c> means the update is due to a startup iteration (managed by Sequence Startup or HOTween.From), /// and all callbacks will be ignored. /// </param> /// <param name="p_ignoreCallbacks"> /// If <c>true</c> doesn't call any callback method. /// </param> /// <param name="p_ignoreDelay"> /// If <c>true</c> uses p_shortElapsed fully ignoring the delay /// (useful when setting the initial FROM state). /// </param> /// <returns> /// A value of <c>true</c> if the Tweener is not reversed and is complete (or the tween target doesn't exist anymore), otherwise <c>false</c>. /// </returns> internal bool Update(float p_shortElapsed, bool p_forceUpdate, bool p_isStartupIteration, bool p_ignoreCallbacks, bool p_ignoreDelay = false) { if (_destroyed) { return(true); } if (_target == null || _target.Equals(null)) { Kill(false); return(true); } if (!_enabled) { return(false); } if (_isComplete && !_isReversed && !p_forceUpdate) { return(true); } if (_fullElapsed == 0 && _isReversed && !p_forceUpdate) { return(false); } if (_isPaused && !p_forceUpdate) { return(false); } ignoreCallbacks = p_isStartupIteration || p_ignoreCallbacks; if (p_ignoreDelay || delayCount == 0) { Startup(); if (!_hasStarted) { OnStart(); } if (!_isReversed) { _fullElapsed += p_shortElapsed; _elapsed += p_shortElapsed; } else { _fullElapsed -= p_shortElapsed; _elapsed -= p_shortElapsed; } if (_fullElapsed > _fullDuration) { _fullElapsed = _fullDuration; } else if (_fullElapsed < 0) { _fullElapsed = 0; } } else { // Manage delay (delay doesn't go backwards). if (_timeScale != 0) { _elapsedDelay += p_shortElapsed / _timeScale; // Calculate delay independently of timeScale } if (_elapsedDelay < delayCount) { return(false); } if (_isReversed) { _fullElapsed = _elapsed = 0; } else { _fullElapsed = _elapsed = _elapsedDelay - delayCount; if (_fullElapsed > _fullDuration) { _fullElapsed = _fullDuration; } } _elapsedDelay = delayCount; delayCount = 0; Startup(); if (!_hasStarted) { OnStart(); } } // Set all elapsed and loops values. bool wasComplete = _isComplete; bool stepComplete = (!_isReversed && !wasComplete && _elapsed >= _duration); SetLoops(); SetElapsed(); _isComplete = (!_isReversed && _loops >= 0 && _completedLoops >= _loops); bool complete = (!wasComplete && _isComplete); // Update the plugins. float plugElapsed = (!_isLoopingBack ? _elapsed : _duration - _elapsed); int pluginsCount = plugins.Count; for (int i = 0; i < pluginsCount; ++i) { ABSTweenPlugin plug = plugins[i]; if (!_isLoopingBack && plug.easeReversed || _isLoopingBack && _loopType == LoopType.YoyoInverse && !plug.easeReversed) { plug.ReverseEase(); } if (_duration > 0) { plug.Update(plugElapsed); OnPluginUpdated(plug); // do callback } else { // 0 duration tweens OnPluginUpdated(plug); // do callback plug.Complete(); if (!wasComplete) { complete = true; } } } // Manage eventual pause, complete, update, rewinded, and stepComplete. if (_fullElapsed != prevFullElapsed) { OnUpdate(); if (_fullElapsed == 0) { if (!_isPaused) { _isPaused = true; OnPause(); } OnRewinded(); } } if (complete) { if (!_isPaused) { _isPaused = true; OnPause(); } OnComplete(); } else if (stepComplete) { OnStepComplete(); } ignoreCallbacks = false; prevFullElapsed = _fullElapsed; return(complete); }
// *********************************************************************************** // INIT // *********************************************************************************** /// <summary> /// Initializes the given <see cref="Tweener"/> with the stored parameters. /// </summary> /// <param name="p_tweenObj"> /// The <see cref="Tweener"/> to initialize. /// </param> /// <param name="p_target"> /// The <see cref="Tweener"/> target. /// </param> internal void InitializeObject(Tweener p_tweenObj, object p_target) { InitializeOwner(p_tweenObj); if (speedBased && !easeSet) { easeType = EaseType.Linear; } p_tweenObj._pixelPerfect = pixelPerfect; p_tweenObj._speedBased = speedBased; p_tweenObj._easeType = easeType; p_tweenObj._easeAnimationCurve = easeAnimCurve; p_tweenObj._easeOvershootOrAmplitude = easeOvershootOrAmplitude; p_tweenObj._easePeriod = easePeriod; p_tweenObj._delay = p_tweenObj.delayCount = delay; p_tweenObj.isFrom = isFrom; p_tweenObj.onPluginOverwritten = onPluginOverwritten; p_tweenObj.onPluginOverwrittenWParms = onPluginOverwrittenWParms; p_tweenObj.onPluginOverwrittenParms = onPluginOverwrittenParms; // Parse properties and create/set plugins. p_tweenObj.plugins = new List <ABSTweenPlugin>(); Type targetType = p_target.GetType(); FieldInfo fieldInfo = null; int propDatasCount = propDatas.Count; for (int i = 0; i < propDatasCount; ++i) { HOTPropData data = propDatas[i]; // Store propInfo and fieldInfo to see if they exist, and then pass them to plugin init. PropertyInfo propInfo = targetType.GetProperty(data.propName); if (propInfo == null) { fieldInfo = targetType.GetField(data.propName); if (fieldInfo == null) { TweenWarning.Log("\"" + p_target + "." + data.propName + "\" is missing, static, or not public. The tween for this property will not be created."); continue; } } // Store correct plugin. ABSTweenPlugin plug; ABSTweenPlugin absTweenPlugin = data.endValOrPlugin as ABSTweenPlugin; if (absTweenPlugin != null) { // Use existing plugin. plug = absTweenPlugin; if (plug.ValidateTarget(p_target)) { if (plug.initialized) { // This plugin was already initialized with another Tweener. Clone it. plug = plug.CloneBasic(); // OPTIMIZE Uses Activator, which is slow. } } else { // Invalid target. TweenWarning.Log(Utils.SimpleClassName(plug.GetType()) + " : Invalid target (" + p_target + "). The tween for this property will not be created."); continue; } } else { // Parse value to find correct plugin to use. plug = null; // string propType = (propInfo != null ? propInfo.PropertyType.ToString() : fieldInfo.FieldType.ToString()); // string shortPropType = propType.Substring(propType.IndexOf(".") + 1); string shortPropType = propInfo != null ? _TypeToShortString.ContainsKey(propInfo.PropertyType) ? _TypeToShortString[propInfo.PropertyType] : "" : _TypeToShortString.ContainsKey(fieldInfo.FieldType) ? _TypeToShortString[fieldInfo.FieldType] : ""; switch (shortPropType) { case "Vector2": if (!ValidateValue(data.endValOrPlugin, PlugVector2.validValueTypes)) { break; } plug = new PlugVector2((Vector2)data.endValOrPlugin, data.isRelative); break; case "Vector3": if (!ValidateValue(data.endValOrPlugin, PlugVector3.validValueTypes)) { break; } plug = new PlugVector3((Vector3)data.endValOrPlugin, data.isRelative); break; case "Vector4": if (!ValidateValue(data.endValOrPlugin, PlugVector4.validValueTypes)) { break; } plug = new PlugVector4((Vector4)data.endValOrPlugin, data.isRelative); break; case "Quaternion": if (!ValidateValue(data.endValOrPlugin, PlugQuaternion.validValueTypes)) { break; } if (data.endValOrPlugin is Vector3) { plug = new PlugQuaternion((Vector3)data.endValOrPlugin, data.isRelative); } else { plug = new PlugQuaternion((Quaternion)data.endValOrPlugin, data.isRelative); } break; case "Color": if (!ValidateValue(data.endValOrPlugin, PlugColor.validValueTypes)) { break; } plug = new PlugColor((Color)data.endValOrPlugin, data.isRelative); break; case "Color32": if (!ValidateValue(data.endValOrPlugin, PlugColor32.validValueTypes)) { break; } plug = new PlugColor32((Color32)data.endValOrPlugin, data.isRelative); break; case "Rect": if (!ValidateValue(data.endValOrPlugin, PlugRect.validValueTypes)) { break; } plug = new PlugRect((Rect)data.endValOrPlugin, data.isRelative); break; case "String": if (!ValidateValue(data.endValOrPlugin, PlugString.validValueTypes)) { break; } plug = new PlugString(data.endValOrPlugin.ToString(), data.isRelative); break; case "Int32": if (!ValidateValue(data.endValOrPlugin, PlugInt.validValueTypes)) { break; } plug = new PlugInt((int)data.endValOrPlugin, data.isRelative); break; case "UInt32": if (!ValidateValue(data.endValOrPlugin, PlugUInt.validValueTypes)) { break; } plug = new PlugUInt(Convert.ToUInt32(data.endValOrPlugin), data.isRelative); break; default: if (data.endValOrPlugin.GetType() != typeof(Boolean)) { try { plug = new PlugFloat(Convert.ToSingle(data.endValOrPlugin), data.isRelative); } catch (Exception) { TweenWarning.Log("No valid plugin for animating \"" + p_target + "." + data.propName + "\" (of type " + (propInfo != null ? propInfo.PropertyType : fieldInfo.FieldType) + "). The tween for this property will not be created."); continue; } } break; } if (plug == null) { TweenWarning.Log("The end value set for \"" + p_target + "." + data.propName + "\" tween is invalid. The tween for this property will not be created."); continue; } } plug.Init(p_tweenObj, data.propName, easeType, targetType, propInfo, fieldInfo); p_tweenObj.plugins.Add(plug); } }
/// <summary> /// Sets a property or field to tween, /// directly assigning the given <c>TweenPlugin</c> to it. /// Behaves as <c>NewProp()</c>, but without removing the other property tweens that were set in this <see cref="TweenParms"/>. /// </summary> /// <param name="p_propName"> /// The name of the property. /// </param> /// <param name="p_plugin"> /// The <see cref="ABSTweenPlugin"/> to use. /// </param> public TweenParms Prop(string p_propName, ABSTweenPlugin p_plugin) { return(Prop(p_propName, p_plugin, false)); }
// =================================================================================== // METHODS --------------------------------------------------------------------------- public void AddTween(Tweener p_tween) { if (enabled) { // Check running tweens for eventual overwrite. List <ABSTweenPlugin> addPlugs = p_tween.plugins; int runningTweensCount = runningTweens.Count - 1; int addPlugsCount = addPlugs.Count; for (int i = runningTweensCount; i > -1; --i) { Tweener tw = runningTweens[i]; List <ABSTweenPlugin> twPlugins = tw.plugins; int twPluginsCount = twPlugins.Count; if (tw.target == p_tween.target) { // Check internal plugins. for (int n = 0; n < addPlugsCount; ++n) { ABSTweenPlugin addPlug = addPlugs[n]; for (int c = twPluginsCount - 1; c > -1; --c) { ABSTweenPlugin plug = twPlugins[c]; if (plug.propName == addPlug.propName && (addPlug.pluginId == -1 || plug.pluginId == -1 || plug.pluginId == addPlug.pluginId)) { if (tw.isSequenced && p_tween.isSequenced && tw.contSequence == p_tween.contSequence) { goto NEXT_TWEEN; } if (!tw._isPaused && (!tw.isSequenced || !tw.isComplete)) { // Overwrite old plugin. twPlugins.RemoveAt(c); twPluginsCount--; if (HOTween.isEditor && HOTween.warningLevel == WarningLevel.Verbose) { string t0 = addPlug.GetType().ToString(); t0 = t0.Substring(t0.LastIndexOf(".") + 1); string t1 = plug.GetType().ToString(); t1 = t1.Substring(t1.LastIndexOf(".") + 1); if (logWarnings) { TweenWarning.Log(t0 + " is overwriting " + t1 + " for " + tw.target + "." + plug.propName); } } // Check if whole tween needs to be removed. if (twPluginsCount == 0) { if (tw.isSequenced) { tw.contSequence.Remove(tw); } runningTweens.RemoveAt(i); tw.Kill(false); } // Dispatch eventual pluginOverwritten event if (tw.onPluginOverwritten != null) { tw.onPluginOverwritten(); } else if (tw.onPluginOverwrittenWParms != null) { tw.onPluginOverwrittenWParms(new TweenEvent(tw, tw.onPluginOverwrittenParms)); } // If whole tween was killed jump to next tween if (tw.destroyed) { goto NEXT_TWEEN; } } } } } NEXT_TWEEN :; } } } runningTweens.Add(p_tween); }
} // 0x004D8B60-0x004D8B80 // Methods internal static bool Setup <T1, T2, TPlugOptions>(TweenerCore <T1, T2, TPlugOptions> t, DOGetter <T1> getter, DOSetter <T1> setter, T2 endValue, float duration, ABSTweenPlugin <T1, T2, TPlugOptions> plugin = null) where TPlugOptions : struct, IPlugOptions => default;
internal TweenEvent(IHOTweenComponent p_tween, object[] p_parms, ABSTweenPlugin p_plugin) { _tween = p_tween; _parms = p_parms; _plugin = p_plugin; }
// *********************************************************************************** // CONSTRUCTOR // *********************************************************************************** internal TweenEvent(IHOTweenComponent p_tween, object[] p_parms) { _tween = p_tween; _parms = p_parms; _plugin = null; }