1
0
mirror of https://github.com/Cardidi/dotween-upm-fork.git synced 2025-12-20 09:16:02 +08:00
2015-03-18 19:30:48 +01:00

342 lines
9.8 KiB
C#

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class GoTween : AbstractGoTween
{
// Tween specific properties
public object target { get; private set; } // the target of the tweens
public float delay { get; private set; } // delay before starting the actual animations
private float _elapsedDelay; // total time delayed
private bool _delayComplete; // once we complete the delay this gets set so we can reverse and play properly for the future
public bool isFrom { get; private set; } // a value of true will make this a "from" tween
private List<AbstractTweenProperty> _tweenPropertyList = new List<AbstractTweenProperty>();
private string targetTypeString;
/// <summary>
/// sets the ease type for all Tweens. this will overwrite the ease types for each Tween!
/// </summary>
private GoEaseType _easeType;
public GoEaseType easeType
{
get
{
return _easeType;
}
set
{
_easeType = value;
// change ease type of all existing tweens.
foreach( var tween in _tweenPropertyList )
tween.setEaseType( value );
}
}
/// <summary>
/// initializes a new instance and sets up the details according to the config parameter
/// </summary>
public GoTween( object target, float duration, GoTweenConfig config, Action<AbstractGoTween> onComplete = null )
{
// default to removing on complete
autoRemoveOnComplete = true;
// allow events by default
allowEvents = true;
// setup callback bools
_didInit = false;
_didBegin = false;
// flag the onIterationStart event to fire.
// as long as goTo is not called on this tween, the onIterationStart event will fire
// as soon as the delay, if any, is completed.
_fireIterationStart = true;
this.target = target;
this.targetTypeString = target.GetType().ToString();
this.duration = duration;
// copy the TweenConfig info over
id = config.id;
delay = config.delay;
loopType = config.loopType;
iterations = config.iterations;
_easeType = config.easeType;
updateType = config.propertyUpdateType;
isFrom = config.isFrom;
timeScale = config.timeScale;
_onInit = config.onInitHandler;
_onBegin = config.onBeginHandler;
_onIterationStart = config.onIterationStartHandler;
_onUpdate = config.onUpdateHandler;
_onIterationEnd = config.onIterationEndHandler;
_onComplete = config.onCompleteHandler;
if( config.isPaused )
state = GoTweenState.Paused;
// if onComplete is passed to the constructor it wins. it is left as the final param to allow an inline Action to be
// set and maintain clean code (Actions always try to be the last param of a method)
if( onComplete != null )
_onComplete = onComplete;
// add all our properties
for( var i = 0; i < config.tweenProperties.Count; ++i )
{
var tweenProp = config.tweenProperties[i];
// if the tween property is initialized already it means it is being reused so we need to clone it
if( tweenProp.isInitialized )
tweenProp = tweenProp.clone();
addTweenProperty( tweenProp );
}
// calculate total duration
if( iterations < 0 )
totalDuration = float.PositiveInfinity;
else
totalDuration = iterations * duration;
}
/// <summary>
/// tick method. if it returns true it indicates the tween is complete
/// </summary>
public override bool update( float deltaTime )
{
// properties are prepared only once on the first update of the tween.
if ( !_didInit )
onInit();
// should we validate the target?
if( Go.validateTargetObjectsEachTick )
{
// This might seem to be overkill, but on the case of Transforms that
// have been destroyed, target == null will return false, whereas
// target.Equals(null) will return true. Otherwise we don't really
// get the benefits of the nanny.
if( target == null || target.Equals(null) )
{
// if the target doesn't pass validation
Debug.LogWarning( "target validation failed. destroying the tween to avoid errors. Target type: " + this.targetTypeString );
autoRemoveOnComplete = true;
return true;
}
}
// we only fire the begin callback once per run.
if ( !_didBegin )
onBegin();
// handle delay and return if we are still delaying
if( !_delayComplete && _elapsedDelay < delay )
{
// if we have a timeScale set we need to remove its influence so that delays are always in seconds
if( timeScale != 0 )
_elapsedDelay += deltaTime / timeScale;
// are we done delaying?
if( _elapsedDelay >= delay )
_delayComplete = true;
return false;
}
// loops only start once the delay has completed.
if ( _fireIterationStart )
onIterationStart();
// base will calculate the proper elapsedTime, iterations, etc.
base.update( deltaTime );
// if we are looping back on a PingPong loop
var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
//Debug.Log(string.Format("{0} : {1} -- {2}", _elapsedTime, convertedElapsedTime, _isLoopingBackOnPingPong ? "Y" : "N"));
// update all properties
for( var i = 0; i < _tweenPropertyList.Count; ++i )
_tweenPropertyList[i].tick( convertedElapsedTime );
onUpdate();
if ( _fireIterationEnd )
onIterationEnd();
if( state == GoTweenState.Complete )
{
onComplete();
return true; // true if complete
}
return false; // false if not complete
}
/// <summary>
/// we are valid if we have a target and at least one TweenProperty
/// </summary>
public override bool isValid()
{
return target != null;
}
/// <summary>
/// adds the tween property if it passes validation and initializes the property
/// </summary>
public void addTweenProperty( AbstractTweenProperty tweenProp )
{
// make sure the target is valid for this tween before adding
if( tweenProp.validateTarget( target ) )
{
// ensure we dont add two tweens of the same property so they dont fight
if( _tweenPropertyList.Contains( tweenProp ) )
{
Debug.Log( "not adding tween property because one already exists: " + tweenProp );
return;
}
_tweenPropertyList.Add( tweenProp );
tweenProp.init( this );
}
else
{
Debug.Log( "tween failed to validate target: " + tweenProp );
}
}
public override bool removeTweenProperty( AbstractTweenProperty property )
{
if( _tweenPropertyList.Contains( property ) )
{
_tweenPropertyList.Remove( property );
return true;
}
return false;
}
public override bool containsTweenProperty( AbstractTweenProperty property )
{
return _tweenPropertyList.Contains( property );
}
public void clearTweenProperties()
{
_tweenPropertyList.Clear();
}
public override List<AbstractTweenProperty> allTweenProperties()
{
return _tweenPropertyList;
}
#region AbstractTween overrides
/// <summary>
/// called only once the first update of a tween.
/// </summary>
protected override void onInit()
{
base.onInit();
for ( var i = 0; i < _tweenPropertyList.Count; ++i )
_tweenPropertyList[i].prepareForUse();
}
/// <summary>
/// removes the tween and cleans up its state
/// </summary>
public override void destroy()
{
base.destroy();
_tweenPropertyList.Clear();
target = null;
}
/// <summary>
/// goes to the specified time clamping it from 0 to the total duration of the tween. if the tween is
/// not playing it will be force updated to the time specified.
/// </summary>
public override void goTo( float time , bool skipDelay = true )
{
// handle delay, which is specific to Tweens
if( skipDelay )
{
_elapsedDelay = delay;
}
else
{
_elapsedDelay = Mathf.Min( time, delay );
time -= _elapsedDelay;
}
_delayComplete = _elapsedDelay >= delay;
time = Mathf.Clamp( time, 0f, totalDuration );
// provide an early out for calling goto on the same time multiple times.
if ( time == _totalElapsedTime )
return;
// if we are doing a goTo at the "start" of the timeline, based on the isReversed variable,
// allow the onBegin and onIterationStart callback to fire again.
// we only allow the onIterationStart event callback to fire at the start of the timeline,
// as doing a goTo(x) where x % duration == 0 will trigger the onIterationEnd before we
// go to the start.
if ( ( isReversed && time == totalDuration ) || ( !isReversed && time == 0f ) )
{
_didBegin = false;
_fireIterationStart = true;
}
else
{
_didBegin = true;
_fireIterationStart = false;
}
// since we're doing a goTo, we want to stop this tween from remembering that it iterated.
// this could cause issues if you caused the tween to complete an iteration and then goTo somewhere
// else while still paused.
_didIterateThisFrame = false;
// force a time and completedIterations before we update
_totalElapsedTime = time;
_completedIterations = isReversed ? Mathf.CeilToInt( _totalElapsedTime / duration ) : Mathf.FloorToInt( _totalElapsedTime / duration );
update( 0 );
}
/// <summary>
/// completes the tween. sets the object to it's final position as if the tween completed normally.
/// takes into effect if the tween was playing forward or reversed.
/// </summary>
public override void complete()
{
if( iterations < 0 )
return;
// set delayComplete so we get one last update in before we die (base will set the elapsed time for us)
_delayComplete = true;
base.complete();
}
#endregion
}