// Animancer // https://kybernetik.com.au/animancer // Copyright 2021 Kybernetik //
using UnityEngine;
using System;
#if UNITY_EDITOR
using Animancer.Editor;
using UnityEditor;
#endif
namespace Animancer
{
///
/// https://kybernetik.com.au/animancer/api/Animancer/AnimancerTransitionAsset
[CreateAssetMenu(menuName = Strings.MenuPrefix + "Animancer Transition", order = Strings.AssetMenuOrder + 0)]
[HelpURL(Strings.DocsURLs.APIDocumentation + "/" + nameof(AnimancerTransitionAsset))]
public class AnimancerTransitionAsset : AnimancerTransitionAsset
{
/************************************************************************************************************************/
#if UNITY_EDITOR
///
protected override void Reset()
{
Transition = new ClipTransition();
}
#endif
/************************************************************************************************************************/
///
/// An wrapper which stores its own and
/// to allow multiple objects to reference the same transition asset without interfering
/// with each other.
///
///
/// Documentation:
/// Transition Assets - UnShared
///
/// https://kybernetik.com.au/animancer/api/Animancer/UnShared_3
///
[Serializable]
public class UnShared : ITransition, ITransitionWithEvents, IWrapper
where TAsset : AnimancerTransitionAsset
where TTransition : ITransition, IHasEvents
where TState : AnimancerState
{
/************************************************************************************************************************/
[SerializeField]
private TAsset _Asset;
/// The wrapped by this object.
public ref TAsset Asset => ref _Asset;
///
object IWrapper.WrappedObject => _Asset;
/// The wrapped by this object.
public ref TTransition Transition => ref _Asset.Transition;
/************************************************************************************************************************/
/// Can this transition create a valid ?
public virtual bool IsValid => _Asset.IsValid();
/************************************************************************************************************************/
private AnimancerState _BaseState;
///
/// The state that was created by this object. Specifically, this is the state that was most recently
/// passed into (usually by ).
///
/// You can use or
/// to get or create the state for a
/// specific object.
///
/// is simply a shorthand for casting this to .
///
public AnimancerState BaseState
{
get => _BaseState;
private set
{
_BaseState = value;
if (_State != value)
_State = null;
}
}
/************************************************************************************************************************/
private TState _State;
///
/// The state that was created by this object. Specifically, this is the state that was most recently
/// passed into (usually by ).
///
///
///
/// You can use or
/// to get or create the state for a
/// specific object.
///
/// This property is shorthand for casting the to .
///
///
///
/// The is not actually a . This should only
/// happen if a different type of state was created by something else and registered using the
/// , causing this to pass that
/// state into instead of calling to make the correct type of
/// state.
///
public TState State
{
get
{
if (_State == null)
_State = (TState)BaseState;
return _State;
}
protected set
{
BaseState = _State = value;
}
}
/************************************************************************************************************************/
private AnimancerEvent.Sequence _Events;
///
/// This property stores a copy of the events from the
public virtual AnimancerEvent.Sequence Events
{
get
{
if (_Events == null)
_Events = new AnimancerEvent.Sequence(SerializedEvents.GetEventsOptional());
return _Events;
}
}
///
public virtual ref AnimancerEvent.Sequence.Serializable SerializedEvents => ref _Asset.Transition.SerializedEvents;
/************************************************************************************************************************/
/// Wraps and assigns the local .
public virtual void Apply(AnimancerState state)
{
BaseState = state;
_Asset.Apply(state);
if (_Events == null)
{
_Events = SerializedEvents.GetEventsOptional();
if (_Events == null)
return;
_Events = new AnimancerEvent.Sequence(_Events);
}
state.Events = _Events;
}
/************************************************************************************************************************/
///
public virtual object Key => _Asset.Key;
///
public virtual float FadeDuration => _Asset.FadeDuration;
///
public virtual FadeMode FadeMode => _Asset.FadeMode;
///
public virtual TState CreateState() => State = (TState)_Asset.CreateState();
///
AnimancerState ITransition.CreateState() => BaseState = _Asset.CreateState();
/************************************************************************************************************************/
}
/************************************************************************************************************************/
#if UNITY_EDITOR
/// [Editor-Only]
/// A for .
///
///
/// This class doesn't inherit from (which would let it draw the button to open the
/// ) because it would only show the Transition Asset reference field without
/// any of the actual values (fade duration, speed, etc.) and trying to redirect everything necessary to preview
/// the asset's transition would require significant additional complexity.
///
/// This issue can be avoided using the
///
/// Nested Inspectors in Inspector Gadgets by opening the asset's Inspector and previewing it directly.
///
[CustomPropertyDrawer(typeof(UnShared<,,>), true)]
public class UnSharedTransitionDrawer : PropertyDrawer
{
/************************************************************************************************************************/
///
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var height = AnimancerGUI.LineHeight;
if (property.propertyType == SerializedPropertyType.ManagedReference &&
property.isExpanded)
height += AnimancerGUI.LineHeight + AnimancerGUI.StandardSpacing;
return height;
}
/************************************************************************************************************************/
///
public override void OnGUI(Rect area, SerializedProperty property, GUIContent label)
{
if (property.propertyType == SerializedPropertyType.ManagedReference)
{
using (new TypeSelectionButton(area, property, true))
EditorGUI.PropertyField(area, property, label, true);
}
else
{
var transitionProperty = property.FindPropertyRelative("_Asset");
EditorGUI.PropertyField(area, transitionProperty, label, false);
}
}
/************************************************************************************************************************/
}
#endif
}
}