// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System;
using System.Collections.Generic;
using System.Linq;
using Doozy.Runtime.Reactor.Internal;
using Doozy.Runtime.Reactor.Reactions;
using Doozy.Runtime.Reactor.Targets;
using UnityEngine;
namespace Doozy.Runtime.Reactor.Animations
{
///
/// Reactor animation that works with a list of sprites.
/// It works like a frame by frame animation, each sprite counting as a frame, for a sprite target.
///
[Serializable]
public class SpriteAnimation : ReactorAnimation
{
/// Reference to a sprite target component
public ReactorSpriteTarget spriteTarget { get; private set; }
[SerializeField] private List Sprites = new List();
/// List of sprites, each sprite counted as a frame for the animation
public List sprites => Sprites;
/// Check if a sprite target is referenced or not
public override bool hasTarget => spriteTarget != null;
[SerializeField] private SpriteTargetReaction Animation;
/// Sprite reaction designed to change (via a frame by frame animation) the sprite of a sprite target
public SpriteTargetReaction animation => Animation ?? (Animation = Reaction.Get());
/// Animation start frame
public int startFrame
{
get => animation.startFrame;
set => animation.startFrame = value;
}
/// Is the animation enabled
public override bool isEnabled => animation.enabled;
/// Is the animation in the idle state (is enabled, but not active)
public override bool isIdle => animation.isIdle;
/// Is the animation in the active state (is enabled and either playing or paused)
public override bool isActive => animation.isActive;
/// Is the animation in the paused state (is enabled, started playing and then paused)
public override bool isPaused => animation.isPaused;
/// Is the animation in the playing state (is enabled and started playing)
public override bool isPlaying => animation.isPlaying;
/// Is the animation in the start delay state (is enabled, started playing and waiting to start running after the start delay duration has passed)
public override bool inStartDelay => animation.inStartDelay;
/// Is the animation in the loop delay state (is enabled, started playing and is between loops waiting to continue running after the loop delay duration has passed)
public override bool inLoopDelay => animation.inLoopDelay;
/// Construct a new SpriteAnimation with the given sprite target
/// Sprite target
public SpriteAnimation(ReactorSpriteTarget target = null)
{
if (target == null)
return;
SetTarget(target);
}
/// Load a set of sprites to the animation. Each sprite is considered a frame.
/// Collection of sprites
public SpriteAnimation SetSprites(IEnumerable spriteEnumerable)
{
if (spriteEnumerable == null) return this;
Sprites.Clear();
Sprites.AddRange(spriteEnumerable);
return UpdateAnimationSprites();
}
/// Updates the list of sprites referenced in the animation
public SpriteAnimation UpdateAnimationSprites()
{
animation.SetSprites(Sprites, false);
return this;
}
/// Sorts the sprites in an alphabetical order from A to Z
public SpriteAnimation SortSpritesAz()
{
Sprites = Sprites.OrderBy(item => item.name).ToList();
return UpdateAnimationSprites();
}
/// Sorts the sprites in reverse alphabetical order from Z to A
public SpriteAnimation SortSpritesZa()
{
Sprites = Sprites.OrderByDescending(item => item.name).ToList();
return UpdateAnimationSprites();
}
/// Set the sprite target
/// Sprite target
public void SetTarget(ReactorSpriteTarget target)
{
spriteTarget = null;
_ = target ? target : throw new NullReferenceException(nameof(target));
spriteTarget = target;
Initialize();
}
/// Initialize de animation
public void Initialize()
{
animation?.Stop(true);
Animation ??= Reaction.Get();
animation?.SetTarget(spriteTarget);
UpdateValues();
}
///
/// Recycle the reactions controlled by this animation.
/// Reactions are pooled can (and should) be recycled to improve overall performance.
///
public override void Recycle() =>
animation?.Recycle();
///
/// Update the initial values for the reactions controlled by this animation
///
public override void UpdateValues()
{
UpdateAnimationSprites();
animation.UpdateValues();
}
///
/// Stop all the reactions controlled by this animation
///
public override void StopAllReactionsOnTarget() =>
Reaction.StopAllReactionsByTargetObject(spriteTarget, true);
/// Set the animation at the given progress value
/// Target progress [0,1]
public override void SetProgressAt(float targetProgress)
{
base.SetProgressAt(targetProgress);
if (!animation.enabled)
return;
UpdateAnimationSprites();
animation.SetProgressAt(targetProgress);
}
/// Play the animation at the given progress value from the current value
/// To progress [0,1]
public override void PlayToProgress(float toProgress)
{
base.PlayToProgress(toProgress);
if (!animation.enabled)
return;
UpdateAnimationSprites();
animation.PlayToProgress(toProgress);
}
/// Play the animation from the given progress value to the current value
/// From progress [0,1]
public override void PlayFromProgress(float fromProgress)
{
base.PlayFromProgress(fromProgress);
if (!animation.enabled)
return;
UpdateAnimationSprites();
animation.PlayFromProgress(fromProgress);
}
/// Play the animation from the given progress value to the given progress value
/// From progress [0,1]
/// To progress [0,1]
public override void PlayFromToProgress(float fromProgress, float toProgress)
{
base.PlayFromToProgress(fromProgress, toProgress);
if (!animation.enabled)
return;
UpdateAnimationSprites();
animation.PlayFromToProgress(fromProgress, toProgress);
}
/// Play the animation all the way
/// Play the animation in reverse?
public override void Play(bool inReverse = false)
{
if (spriteTarget == null)
return;
RegisterCallbacks();
if (!isActive)
{
StopAllReactionsOnTarget();
// ResetToStartValues();
}
if (!animation.enabled)
return;
UpdateAnimationSprites();
animation.Play(inReverse);
}
/// Reset all the reactions to their initial values (if the animation is enabled)
/// If true, forced will ignore if the animation is enabled or not
public override void ResetToStartValues(bool forced = false)
{
if(spriteTarget == null) return;
if (forced || animation.enabled)
{
UpdateAnimationSprites();
animation.SetValue(startFrame);
}
}
///
/// Stop the animation.
/// Called every time the animation is stopped. Also called before calling Finish()
///
public override void Stop()
{
if (animation.isActive || animation.enabled) animation.Stop();
base.Stop();
}
///
/// Finish the animation.
/// Called to mark that that animation completed playing.
///
public override void Finish()
{
if (animation.isActive || animation.enabled) animation.Finish();
base.Finish();
}
///
/// Reverse the animation's direction while playing.
/// Works only if the animation is active (it either playing or paused)
///
public override void Reverse()
{
if (animation.isActive) animation.Reverse();
else if (animation.enabled) animation.Play(PlayDirection.Reverse);
}
///
/// Rewind the animation to the start values
///
public override void Rewind()
{
if (!animation.enabled)
return;
UpdateAnimationSprites();
animation.Rewind();
}
///
/// Pause the animation.
/// Works only if the animation is playing.
///
public override void Pause() =>
animation.Pause();
///
/// Resume a paused animation.
/// Works only if the animation is paused.
///
public override void Resume() =>
animation.Resume();
/// Register all callbacks to the animation
protected override void RegisterCallbacks()
{
base.RegisterCallbacks();
if (!animation.enabled)
return;
startedReactionsCount++;
animation.OnPlayCallback += InvokeOnPlay;
animation.OnStopCallback += InvokeOnStop;
animation.OnFinishCallback += InvokeOnFinish;
}
/// Unregister OnPlayCallback
protected override void UnregisterOnPlayCallbacks()
{
if (!animation.enabled)
return;
animation.OnPlayCallback -= InvokeOnPlay;
}
/// Unregister OnStopCallback
protected override void UnregisterOnStopCallbacks()
{
if (!animation.enabled)
return;
animation.OnStopCallback -= InvokeOnStop;
}
/// Unregister OnFinishCallback
protected override void UnregisterOnFinishCallbacks()
{
if (!animation.enabled)
return;
animation.OnFinishCallback -= InvokeOnFinish;
}
}
}