chore: initial commit
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2022 Kybernetik //
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A set of up/right/down/left animations.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimationSet2
|
||||
///
|
||||
[CreateAssetMenu(
|
||||
menuName = Strings.MenuPrefix + "Directional Animation Set/2 Directions",
|
||||
order = Strings.AssetMenuOrder + 4)]
|
||||
[AnimancerHelpUrl(typeof(DirectionalAnimationSet2))]
|
||||
public class DirectionalAnimationSet2 : DirectionalSet2<AnimationClip>,
|
||||
IAnimationClipSource
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>[<see cref="IAnimationClipSource"/>] Adds all animations from this set to the `clips`.</summary>
|
||||
void IAnimationClipSource.GetAnimationClips(List<AnimationClip> clips)
|
||||
=> AddTo(clips);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9673a15309479c4087f3fcb1cda880e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A set of up/right/down/left animations.</summary>
|
||||
/// <remarks>
|
||||
/// Consider using <c>DirectionalSet<AnimationClip></c> in code instead of this class
|
||||
/// to allow <see cref="DirectionalAnimationSet4"/> and <see cref="DirectionalAnimationSet8"/>
|
||||
/// to be used interchangeably.
|
||||
/// <para></para>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimationSet4
|
||||
///
|
||||
[CreateAssetMenu(
|
||||
menuName = Strings.MenuPrefix + "Directional Animation Set/4 Directions",
|
||||
order = Strings.AssetMenuOrder + 5)]
|
||||
[AnimancerHelpUrl(typeof(DirectionalAnimationSet4))]
|
||||
public class DirectionalAnimationSet4 : DirectionalSet4<AnimationClip>,
|
||||
IAnimationClipSource
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>[<see cref="IAnimationClipSource"/>] Adds all animations from this set to the `clips`.</summary>
|
||||
void IAnimationClipSource.GetAnimationClips(List<AnimationClip> clips)
|
||||
=> AddTo(clips);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6eceeb59a892d074db28203df8e4cd3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A set of up/right/down/left animations with diagonals as well.</summary>
|
||||
/// <remarks>
|
||||
/// Consider using <c>DirectionalSet<AnimationClip></c> in code instead of this class
|
||||
/// to allow <see cref="DirectionalAnimationSet4"/> and <see cref="DirectionalAnimationSet8"/>
|
||||
/// to be used interchangeably.
|
||||
/// <para></para>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimationSet8
|
||||
///
|
||||
[CreateAssetMenu(
|
||||
menuName = Strings.MenuPrefix + "Directional Animation Set/8 Directions",
|
||||
order = Strings.AssetMenuOrder + 6)]
|
||||
[AnimancerHelpUrl(typeof(DirectionalAnimationSet8))]
|
||||
public class DirectionalAnimationSet8 : DirectionalSet8<AnimationClip>,
|
||||
IAnimationClipSource
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>[<see cref="IAnimationClipSource"/>] Adds all animations from this set to the `clips`.</summary>
|
||||
void IAnimationClipSource.GetAnimationClips(List<AnimationClip> clips)
|
||||
=> AddTo(clips);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b5b6ac0c7ebd7b41b307d920db7b245
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,402 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A <see cref="DirectionalAnimations3D{T}"/> using <see cref="int"/> as the group type.</summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <strong>Sample:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/samples/sprites/character-3d">
|
||||
/// Directional Character 3D</see>
|
||||
/// </remarks>
|
||||
///
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimations3D
|
||||
///
|
||||
[AddComponentMenu(Strings.MenuPrefix + "Directional Animations 3D")]
|
||||
[AnimancerHelpUrl(typeof(DirectionalAnimations3D))]
|
||||
public class DirectionalAnimations3D : DirectionalAnimations3D<int> { }
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// A component which manages a screen-facing billboard and plays animations from a
|
||||
/// <see cref="DirectionalSet4{T}"/> to make it look like a <see cref="Sprite"/>
|
||||
/// based character is facing a particular direction in 3D space.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <strong>Sample:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/samples/sprites/character-3d">
|
||||
/// Directional Character 3D</see>
|
||||
/// </remarks>
|
||||
///
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimations3D_1
|
||||
///
|
||||
[AnimancerHelpUrl(typeof(DirectionalAnimations3D<>))]
|
||||
public class DirectionalAnimations3D<TGroup> : MonoBehaviour
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
#region Fields and Properties
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The object to rotate according to the " + nameof(Mode))]
|
||||
private Transform _Transform;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The object to rotate according to the <see cref="Mode"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Uses this <see cref="Component.transform"/> by default.</remarks>
|
||||
public ref Transform Transform
|
||||
=> ref _Transform;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The " + nameof(UnityEngine.Camera) + " to make the " + nameof(Transform) + " face towards" +
|
||||
"\n\nLeave this null to automatically use the Main Camera")]
|
||||
private Transform _Camera;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The <see cref="UnityEngine.Camera"/> to make the <see cref="Transform"/> face towards.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Leave this <c>null</c> to automatically use the <see cref="Camera.main"/>.
|
||||
/// </remarks>
|
||||
public Transform Camera
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Camera == null)
|
||||
{
|
||||
var camera = UnityEngine.Camera.main;
|
||||
if (camera != null)
|
||||
_Camera = camera.transform;
|
||||
}
|
||||
|
||||
return _Camera;
|
||||
}
|
||||
set => _Camera = value;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The " + nameof(AnimancerComponent) + " to play animations on")]
|
||||
private AnimancerComponent _Animancer;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The <see cref="AnimancerComponent"/> to play animations on.
|
||||
/// </summary>
|
||||
public ref AnimancerComponent Animancer
|
||||
=> ref _Animancer;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The " + nameof(DirectionalAnimationSet4) + " or " + nameof(DirectionalAnimationSet8) +
|
||||
" to play animations from (Forwards in 3D space corresponds to the Up animation)")]
|
||||
private DirectionalSet<AnimationClip> _Animations;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The animations to choose between based on the <see cref="Forward"/> direction.
|
||||
/// </summary>
|
||||
/// <remarks>Forwards in 3D space corresponds to the Up animation.</remarks>
|
||||
public ref DirectionalSet<AnimationClip> Animations
|
||||
=> ref _Animations;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The World-Space direction this character is facing used to select which animation to play")]
|
||||
private Vector3 _Forward = Vector3.forward;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The World-Space direction this character is facing used to select which animation to play.
|
||||
/// </summary>
|
||||
public Vector3 Forward
|
||||
{
|
||||
get => _Forward;
|
||||
set
|
||||
{
|
||||
_Forward = value;
|
||||
if (!enabled)
|
||||
PlayCurrentAnimation(TimeSynchronizer.CurrentGroup);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Functions used to face the <see cref="Transform"/> towards the <see cref="Camera"/>.</summary>
|
||||
public enum BillboardMode
|
||||
{
|
||||
/// <summary>Don't control the <see cref="Transform"/>.</summary>
|
||||
None,
|
||||
|
||||
/// <summary>Copy the <see cref="Camera"/> 's rotation.</summary>
|
||||
MatchRotation,
|
||||
|
||||
/// <summary>Face the <see cref="Camera"/>'s position.</summary>
|
||||
FacePosition,
|
||||
|
||||
/// <summary>As <see cref="MatchRotation"/>, but only rotate around the Y axis.</summary>
|
||||
UprightMatchRotation,
|
||||
|
||||
/// <summary>As <see cref="FacePosition"/>, but only rotate around the Y axis.</summary>
|
||||
UprightFacePosition,
|
||||
|
||||
/// <summary>
|
||||
/// As <see cref="UprightMatchRotation"/>,
|
||||
/// and also scale on the Y axis to maintain the same screen size
|
||||
/// regardless of the <see cref="Camera"/>'s Euler X Angle.</summary>
|
||||
/// <remarks>Only use this mode with an Orthographic Camera</remarks>
|
||||
UprightMatchRotationStretched,
|
||||
|
||||
/// <summary>
|
||||
/// As <see cref="UprightFacePosition"/>,
|
||||
/// and also scale on the Y axis to maintain the same screen size
|
||||
/// regardless of the <see cref="Camera"/>'s Euler X Angle.</summary>
|
||||
/// <remarks>Only use this mode with an Orthographic Camera</remarks>
|
||||
UprightFacePositionStretched,
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The function used to face the " + nameof(Transform) + " towards the " + nameof(Camera) + ":" +
|
||||
"\n• None - Don't control the " + nameof(Transform) +
|
||||
"\n• Match Rotation - Copy the " + nameof(Camera) + "'s rotation" +
|
||||
"\n• Face Position - Face the " + nameof(Camera) + "'s position" +
|
||||
"\n• Upright - As above, but only rotate around the Y axis" +
|
||||
"\n• Stretched - As above, and also scale on the Y axis to maintain the same screen size" +
|
||||
" regardless of the " + nameof(Camera) + "'s Euler X Angle (only use with an Orthographic Camera)")]
|
||||
private BillboardMode _Mode = BillboardMode.UprightMatchRotation;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The function used to face the <see cref="Transform"/> towards the <see cref="Camera"/>.
|
||||
/// </summary>
|
||||
public BillboardMode Mode
|
||||
{
|
||||
get => _Mode;
|
||||
set
|
||||
{
|
||||
_Mode = value;
|
||||
ResetScaleIfNotStretched();
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Maintains the <see cref="AnimancerState.NormalizedTime"/> when swapping between animations.
|
||||
/// </summary>
|
||||
public readonly TimeSynchronizer<TGroup>
|
||||
TimeSynchronizer = new(default, true);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#region Methods
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Finds missing references,
|
||||
/// samples the current animation,
|
||||
/// and resets the scale to 1 if not using a stretched mode.
|
||||
/// </summary>
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
gameObject.GetComponentInParentOrChildren(ref _Transform);
|
||||
gameObject.GetComponentInParentOrChildren(ref _Animancer);
|
||||
|
||||
if (TryGetCurrentAnimation(out var animation))
|
||||
AnimancerUtilities.EditModeSampleAnimation(animation, _Animancer);
|
||||
|
||||
ResetScaleIfNotStretched();
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Finds missing references,
|
||||
/// samples the current animation,
|
||||
/// and resets the scale to 1 if not using a stretched mode.
|
||||
/// </summary>
|
||||
protected virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
if (TryGetCurrentAnimation(out var animation))
|
||||
AnimancerUtilities.EditModeSampleAnimation(animation, _Animancer);
|
||||
|
||||
if (_Transform == null)
|
||||
return;
|
||||
|
||||
var position = _Transform.position;
|
||||
var length = 1f;
|
||||
|
||||
var renderer = GetComponentInChildren<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
var bounds = renderer.bounds;
|
||||
position.y += bounds.extents.y;
|
||||
length = bounds.extents.magnitude;
|
||||
}
|
||||
|
||||
Gizmos.color = new(0.75f, 0.75f, 1, 1);
|
||||
Gizmos.DrawRay(position, Forward.normalized * length);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Applies the <see cref="Mode"/> then plays the appropriate animation
|
||||
/// based on the current rotation and <see cref="Forward"/> direction.
|
||||
/// </summary>
|
||||
protected virtual void Update()
|
||||
{
|
||||
UpdateTransform();
|
||||
PlayCurrentAnimation(TimeSynchronizer.CurrentGroup);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Applies the <see cref="Mode"/>.</summary>
|
||||
public void UpdateTransform()
|
||||
{
|
||||
switch (_Mode)
|
||||
{
|
||||
default:
|
||||
case BillboardMode.None:
|
||||
break;
|
||||
|
||||
case BillboardMode.MatchRotation:
|
||||
_Transform.rotation = Camera.rotation;
|
||||
break;
|
||||
|
||||
case BillboardMode.FacePosition:
|
||||
_Transform.rotation = Quaternion.LookRotation(_Transform.position - Camera.position);
|
||||
break;
|
||||
|
||||
case BillboardMode.UprightMatchRotation:
|
||||
_Transform.eulerAngles = new(0, Camera.eulerAngles.y, 0);
|
||||
break;
|
||||
|
||||
case BillboardMode.UprightFacePosition:
|
||||
var direction = _Transform.position - Camera.position;
|
||||
_Transform.eulerAngles = new(
|
||||
0,
|
||||
Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg,
|
||||
0);
|
||||
break;
|
||||
|
||||
case BillboardMode.UprightMatchRotationStretched:
|
||||
var eulerAngles = Camera.eulerAngles;
|
||||
_Transform.eulerAngles = new(0, eulerAngles.y, 0);
|
||||
StretchHeight(eulerAngles.x);
|
||||
break;
|
||||
|
||||
case BillboardMode.UprightFacePositionStretched:
|
||||
StretchHeight(Camera.eulerAngles.x);
|
||||
goto case BillboardMode.UprightFacePosition;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Scales the <see cref="Transform"/> on the Y axis to maintain the same screen size
|
||||
/// regardless of the <see cref="Camera"/>'s Euler X Angle.
|
||||
/// </summary>
|
||||
/// <remarks>This calculation only makes sense with an orthographic camera.</remarks>
|
||||
private void StretchHeight(float eulerX)
|
||||
{
|
||||
if (eulerX > 180)
|
||||
eulerX -= 360;
|
||||
else if (eulerX < -180)
|
||||
eulerX += 360;
|
||||
|
||||
_Transform.localScale = new(
|
||||
1,
|
||||
1 / Mathf.Cos(eulerX * Mathf.Deg2Rad),
|
||||
1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the <see cref="Transform.localScale"/> to 1 if not using a stretched <see cref="Mode"/>.
|
||||
/// </summary>
|
||||
private void ResetScaleIfNotStretched()
|
||||
{
|
||||
if (_Transform == null)
|
||||
return;
|
||||
|
||||
switch (_Mode)
|
||||
{
|
||||
case BillboardMode.UprightMatchRotationStretched:
|
||||
case BillboardMode.UprightFacePositionStretched:
|
||||
break;
|
||||
|
||||
default:
|
||||
_Transform.localScale = Vector3.one;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="Animations"/> and plays the appropriate animation
|
||||
/// based on the current rotation and <see cref="Forward"/> direction.
|
||||
/// </summary>
|
||||
public void SetAnimations(DirectionalSet<AnimationClip> animations, TGroup group = default)
|
||||
{
|
||||
_Animations = animations;
|
||||
PlayCurrentAnimation(group);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Plays the appropriate animation based on the current rotation and <see cref="Forward"/> direction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the `group` is the same as the previous, the new animation will be given the same
|
||||
/// <see cref="AnimancerState.NormalizedTime"/> as the previous.
|
||||
/// </remarks>
|
||||
public void PlayCurrentAnimation(TGroup group)
|
||||
{
|
||||
if (TryGetCurrentAnimation(out var animation))
|
||||
{
|
||||
TimeSynchronizer.StoreTime(_Animancer);
|
||||
|
||||
_Animancer.Play(animation);
|
||||
|
||||
TimeSynchronizer.SyncTime(_Animancer, group);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get an appropriate animation based on the current rotation and <see cref="Forward"/> direction.
|
||||
/// </summary>
|
||||
private bool TryGetCurrentAnimation(out AnimationClip animation)
|
||||
{
|
||||
if (_Animations == null ||
|
||||
_Forward == default)
|
||||
{
|
||||
animation = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var localForward = _Transform.InverseTransformDirection(_Forward);
|
||||
var horizontalForward = new Vector2(localForward.x, localForward.z);
|
||||
|
||||
animation = _Animations.Get(horizontalForward);
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39d4b0d1540fd634c9ad4c6a16a999c5
|
||||
labels:
|
||||
- Example
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,101 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="ClipTransition"/> which gets its clip from a
|
||||
/// <see cref="DirectionalSet{T}"/> of <see cref="AnimationClip"/>s.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para></para>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// <para></para>
|
||||
/// <strong>Example:</strong><code>
|
||||
/// // Leave the Clip field empty in the Inspector and assign its AnimationSet instead.
|
||||
/// [SerializeField] private DirectionalClipTransition _Transition;
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// // Then you can just call SetDirection and Play it like any other transition.
|
||||
/// // All of the transition's details like Fade Duration and Events will be applied to whichever clip is plays.
|
||||
/// _Transition.SetDirection(Vector2.right);
|
||||
/// _Animancer.Play(_Transition);
|
||||
/// </code></remarks>
|
||||
///
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalClipTransition
|
||||
///
|
||||
[Serializable]
|
||||
public class DirectionalClipTransition : ClipTransition,
|
||||
ICopyable<DirectionalClipTransition>
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The animations used to determine the " + nameof(Clip))]
|
||||
private DirectionalSet<AnimationClip> _AnimationSet;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>]
|
||||
/// The <see cref="DirectionalSet{T}"/> used to determine the <see cref="ClipTransition.Clip"/>.
|
||||
/// </summary>
|
||||
public ref DirectionalSet<AnimationClip> AnimationSet
|
||||
=> ref _AnimationSet;
|
||||
|
||||
/// <summary>The name of the serialized backing field of <see cref="AnimationSet"/>.</summary>
|
||||
public const string AnimationSetField = nameof(_AnimationSet);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Sets the <see cref="ClipTransition.Clip"/> from the <see cref="AnimationSet"/>.</summary>
|
||||
public void SetDirection(Vector2 direction)
|
||||
=> Clip = _AnimationSet.Get(direction);
|
||||
|
||||
/// <summary>Sets the <see cref="ClipTransition.Clip"/> from the <see cref="AnimationSet"/>.</summary>
|
||||
public void SetDirection(int direction)
|
||||
=> Clip = _AnimationSet.Get(direction);
|
||||
|
||||
/// <summary>Sets the <see cref="ClipTransition.Clip"/> from the <see cref="AnimationSet"/>.</summary>
|
||||
public void SetDirection(Direction4 direction)
|
||||
=> SetDirection((int)direction);
|
||||
|
||||
/// <summary>Sets the <see cref="ClipTransition.Clip"/> from the <see cref="AnimationSet"/>.</summary>
|
||||
public void SetDirection(Direction8 direction)
|
||||
=> SetDirection((int)direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GatherAnimationClips(ICollection<AnimationClip> clips)
|
||||
{
|
||||
base.GatherAnimationClips(clips);
|
||||
clips.GatherFromSource(_AnimationSet);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Transition<ClipState> Clone(CloneContext context)
|
||||
{
|
||||
var clone = new DirectionalClipTransition();
|
||||
clone.CopyFrom(this, context);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void CopyFrom(DirectionalClipTransition copyFrom, CloneContext context)
|
||||
{
|
||||
base.CopyFrom(copyFrom, context);
|
||||
|
||||
_AnimationSet = copyFrom._AnimationSet;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5125aedb0106a4443a684797d8c73344
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,172 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A generic set of objects corresponding to up/right/down/left.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalSet_1
|
||||
///
|
||||
[AnimancerHelpUrl(typeof(DirectionalSet<>))]
|
||||
public abstract class DirectionalSet<T> : ScriptableObject
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
#region Read-Only
|
||||
/************************************************************************************************************************/
|
||||
|
||||
#if UNITY_ASSERTIONS
|
||||
private bool _AllowChanges;
|
||||
#endif
|
||||
|
||||
/// <summary>[Assert-Only] Sets a debug flag to enable or disable the ability to modify this set.</summary>
|
||||
[System.Diagnostics.Conditional(Strings.Assertions)]
|
||||
public void AllowChanges(bool allow = true)
|
||||
{
|
||||
#if UNITY_ASSERTIONS
|
||||
_AllowChanges = allow;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>[Assert-Only]
|
||||
/// Throws an <see cref="InvalidOperationException"/> if <see cref="AllowChanges"/> wasn't called.
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional(Strings.Assertions)]
|
||||
public void AssertAllowChanges()
|
||||
{
|
||||
#if UNITY_ASSERTIONS
|
||||
if (!_AllowChanges)
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to modify {this} because it is read-only." +
|
||||
$" Call {nameof(AllowChanges)}() before making any changes.");
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#region Directions
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>The number of directions in this set.</summary>
|
||||
public abstract int DirectionCount { get; }
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the name of the specified `direction`.</summary>
|
||||
protected abstract string GetDirectionName(int direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the object associated with the specified `direction`.</summary>
|
||||
public abstract T Get(int direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the object closest to the specified `direction`.</summary>
|
||||
public abstract T Get(Vector2 direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Sets the object associated with the specified `direction`.</summary>
|
||||
public abstract void Set(int direction, T value);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>[Editor-Only]
|
||||
/// Attempts to assign the `value` to one of this set's fields based on its `name` and
|
||||
/// returns the direction index of that field (or -1 if it was unable to determine the direction).
|
||||
/// </summary>
|
||||
public int SetByName(string name, T value)
|
||||
{
|
||||
var direction = GetDirection(name);
|
||||
if (direction >= 0)
|
||||
Set(direction, value);
|
||||
|
||||
return direction;
|
||||
}
|
||||
|
||||
/// <summary>[Editor-Only]
|
||||
/// Attempts to assign the `value` to one of this set's fields based on its name and
|
||||
/// returns the direction index of that field (or -1 if it was unable to determine the direction).
|
||||
/// </summary>
|
||||
public int SetByName<U>(U value)
|
||||
where U : Object, T
|
||||
=> SetByName(value.name, value);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#region Conversion
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns a vector representing the specified `direction`.</summary>
|
||||
public abstract Vector2 GetDirection(int direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the index of the direction which best matches the given `name`.</summary>
|
||||
public abstract int GetDirection(string name);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns a copy of the `vector` pointing in the closest direction this set has an object for.</summary>
|
||||
public abstract Vector2 Snap(Vector2 vector);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#region Gathering
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Adds all objects from this set to the `values`, starting from the specified `index`.</summary>
|
||||
public void AddTo(T[] values, int index)
|
||||
{
|
||||
var count = DirectionCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
values[index + i] = Get(i);
|
||||
}
|
||||
|
||||
/// <summary>Adds all objects from this set to the `values`.</summary>
|
||||
public void AddTo(List<T> values)
|
||||
{
|
||||
var count = DirectionCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
values.Add(Get(i));
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Adds unit vectors corresponding to each of the objects in this set to the `directions`,
|
||||
/// starting from the specified `index`.
|
||||
/// </summary>
|
||||
public void AddTo(Vector2[] directions, int index)
|
||||
{
|
||||
var count = DirectionCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
directions[index + i] = GetDirection(i);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Calls <see cref="AddTo"/> and <see cref="AddTo"/>.</summary>
|
||||
public void AddTo(T[] values, Vector2[] directions, int index)
|
||||
{
|
||||
AddTo(values, index);
|
||||
AddTo(directions, index);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0d9246f866eb6740a90936cf5d67836
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,150 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2022 Kybernetik //
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A generic set of objects corresponding to left/right.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalSet2_1
|
||||
///
|
||||
[AnimancerHelpUrl(typeof(DirectionalSet2<>))]
|
||||
public class DirectionalSet2<T> : DirectionalSet<T>
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
#region Fields and Properties
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _Left;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction2.Left"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T Left
|
||||
{
|
||||
get => _Left;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_Left = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _Right;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction2.Right"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T Right
|
||||
{
|
||||
get => _Right;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_Right = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#region Directions
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int DirectionCount
|
||||
=> 2;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetDirectionName(int direction)
|
||||
=> ((Direction2)direction).ToString();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the object associated with the specified `direction`.</summary>
|
||||
public T Get(Direction2 direction)
|
||||
=> direction switch
|
||||
{
|
||||
Direction2.Left => _Left,
|
||||
Direction2.Right => _Right,
|
||||
_ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction),
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override T Get(int direction)
|
||||
=> Get((Direction2)direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override T Get(Vector2 direction)
|
||||
=> Get(direction.x);
|
||||
|
||||
/// <summary>Negative `direction` returns <see cref="Left"/>, 0 or positive returns <see cref="Right"/>.</summary>
|
||||
public T Get(float direction)
|
||||
=> direction < 0 ? _Left : _Right;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Sets the object associated with the specified `direction`.</summary>
|
||||
public void Set(Direction2 direction, T value)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case Direction2.Left: Left = value; break;
|
||||
case Direction2.Right: Right = value; break;
|
||||
default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Set(int direction, T value)
|
||||
=> Set((Direction2)direction, value);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Vector2 GetDirection(int direction)
|
||||
=> ((Direction2)direction).ToVector2();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetDirection(string name)
|
||||
{
|
||||
var direction = AnimancerUtilities.GetDirection(name);
|
||||
|
||||
if (direction.x == 0)
|
||||
direction.x = direction.y;
|
||||
|
||||
return direction.x switch
|
||||
{
|
||||
> 0 => (int)Direction2.Right,
|
||||
< 0 => (int)Direction2.Left,
|
||||
_ => -1
|
||||
};
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Vector2 Snap(Vector2 vector)
|
||||
=> Directions.SnapToDirection2(vector);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39fd354c6deee7842849491706a1da26
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,210 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A generic set of objects corresponding to up/right/down/left.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalSet4_1
|
||||
///
|
||||
[AnimancerHelpUrl(typeof(DirectionalSet4<>))]
|
||||
public class DirectionalSet4<T> : DirectionalSet<T>
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
#region Fields and Properties
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _Up;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction4.Up"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T Up
|
||||
{
|
||||
get => _Up;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_Up = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _Right;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction4.Right"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T Right
|
||||
{
|
||||
get => _Right;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_Right = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _Down;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction4.Down"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T Down
|
||||
{
|
||||
get => _Down;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_Down = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _Left;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction4.Left"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T Left
|
||||
{
|
||||
get => _Left;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_Left = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#region Directions
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int DirectionCount
|
||||
=> 4;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetDirectionName(int direction)
|
||||
=> ((Direction4)direction).ToString();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the object associated with the specified `direction`.</summary>
|
||||
public T Get(Direction4 direction)
|
||||
=> direction switch
|
||||
{
|
||||
Direction4.Up => _Up,
|
||||
Direction4.Right => _Right,
|
||||
Direction4.Down => _Down,
|
||||
Direction4.Left => _Left,
|
||||
_ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction),
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override T Get(int direction)
|
||||
=> Get((Direction4)direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override T Get(Vector2 direction)
|
||||
{
|
||||
if (direction.x >= 0)
|
||||
{
|
||||
if (direction.y >= 0)
|
||||
return direction.x > direction.y ? _Right : _Up;
|
||||
else
|
||||
return direction.x > -direction.y ? _Right : _Down;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (direction.y >= 0)
|
||||
return direction.x < -direction.y ? _Left : _Up;
|
||||
else
|
||||
return direction.x < direction.y ? _Left : _Down;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Sets the object associated with the specified `direction`.</summary>
|
||||
public void Set(Direction4 direction, T value)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case Direction4.Up: Up = value; break;
|
||||
case Direction4.Right: Right = value; break;
|
||||
case Direction4.Down: Down = value; break;
|
||||
case Direction4.Left: Left = value; break;
|
||||
default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Set(int direction, T value)
|
||||
=> Set((Direction4)direction, value);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Vector2 GetDirection(int direction)
|
||||
=> ((Direction4)direction).ToVector2();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetDirection(string name)
|
||||
{
|
||||
var direction = AnimancerUtilities.GetDirection(name);
|
||||
|
||||
if (direction.x == 0)
|
||||
{
|
||||
if (direction.y > 0)
|
||||
return (int)Direction4.Up;
|
||||
else if (direction.y < 0)
|
||||
return (int)Direction4.Down;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (direction.x > 0)
|
||||
return (int)Direction4.Right;
|
||||
else if (direction.x < 0)
|
||||
return (int)Direction4.Left;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Vector2 Snap(Vector2 vector)
|
||||
=> Directions.SnapToDirection4(vector);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36b7e15ac4728544a958431a6e72d911
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,227 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>A generic set of objects corresponding to up/right/down/left with diagonals as well.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/DirectionalSet8_1
|
||||
///
|
||||
[AnimancerHelpUrl(typeof(DirectionalSet8<>))]
|
||||
public class DirectionalSet8<T> : DirectionalSet4<T>
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
#region Fields and Properties
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _UpRight;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction8.UpRight"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T UpRight
|
||||
{
|
||||
get => _UpRight;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_UpRight = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _DownRight;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction8.DownRight"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T DownRight
|
||||
{
|
||||
get => _DownRight;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_DownRight = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _DownLeft;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction8.DownLeft"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T DownLeft
|
||||
{
|
||||
get => _DownLeft;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_DownLeft = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
[SerializeField]
|
||||
private T _UpLeft;
|
||||
|
||||
/// <summary>[<see cref="SerializeField"/>] The object for <see cref="Direction8.UpLeft"/>.</summary>
|
||||
/// <exception cref="ArgumentException"><see cref="AllowChanges"/> was not called before setting this value.</exception>
|
||||
public T UpLeft
|
||||
{
|
||||
get => _UpLeft;
|
||||
set
|
||||
{
|
||||
AssertAllowChanges();
|
||||
_UpLeft = value;
|
||||
AnimancerUtilities.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
#region Directions
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int DirectionCount
|
||||
=> 8;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetDirectionName(int direction)
|
||||
=> ((Direction8)direction).ToString();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the object associated with the specified `direction`.</summary>
|
||||
public T Get(Direction8 direction)
|
||||
=> direction switch
|
||||
{
|
||||
Direction8.Up => Up,
|
||||
Direction8.Right => Right,
|
||||
Direction8.Down => Down,
|
||||
Direction8.Left => Left,
|
||||
Direction8.UpRight => _UpRight,
|
||||
Direction8.DownRight => _DownRight,
|
||||
Direction8.DownLeft => _DownLeft,
|
||||
Direction8.UpLeft => _UpLeft,
|
||||
_ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction),
|
||||
};
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override T Get(int direction)
|
||||
=> Get((Direction8)direction);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override T Get(Vector2 direction)
|
||||
{
|
||||
var angle = Mathf.Atan2(direction.y, direction.x);
|
||||
var octant = Mathf.RoundToInt(8 * angle / (2 * Mathf.PI) + 8) % 8;
|
||||
return octant switch
|
||||
{
|
||||
0 => Right,
|
||||
1 => _UpRight,
|
||||
2 => Up,
|
||||
3 => _UpLeft,
|
||||
4 => Left,
|
||||
5 => _DownLeft,
|
||||
6 => Down,
|
||||
7 => _DownRight,
|
||||
_ => throw new ArgumentOutOfRangeException("Invalid octant"),
|
||||
};
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Sets the object associated with the specified `direction`.</summary>
|
||||
public void Set(Direction8 direction, T value)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case Direction8.Up: Up = value; break;
|
||||
case Direction8.Right: Right = value; break;
|
||||
case Direction8.Down: Down = value; break;
|
||||
case Direction8.Left: Left = value; break;
|
||||
case Direction8.UpRight: UpRight = value; break;
|
||||
case Direction8.DownRight: DownRight = value; break;
|
||||
case Direction8.DownLeft: DownLeft = value; break;
|
||||
case Direction8.UpLeft: UpLeft = value; break;
|
||||
default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Set(int direction, T value)
|
||||
=> Set((Direction8)direction, value);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Vector2 GetDirection(int direction)
|
||||
=> ((Direction8)direction).ToVector2();
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetDirection(string name)
|
||||
{
|
||||
var direction = AnimancerUtilities.GetDirection(name);
|
||||
|
||||
if (direction.x == 0)
|
||||
{
|
||||
if (direction.y > 0)
|
||||
return (int)Direction8.Up;
|
||||
else if (direction.y < 0)
|
||||
return (int)Direction8.Down;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (direction.x > 0)
|
||||
{
|
||||
if (direction.y > 0)
|
||||
return (int)Direction8.UpRight;
|
||||
else if (direction.y < 0)
|
||||
return (int)Direction8.DownRight;
|
||||
else
|
||||
return (int)Direction8.Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (direction.y > 0)
|
||||
return (int)Direction8.UpLeft;
|
||||
else if (direction.y < 0)
|
||||
return (int)Direction8.DownLeft;
|
||||
else
|
||||
return (int)Direction8.Left;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Vector2 Snap(Vector2 vector)
|
||||
=> Directions.SnapToDirection8(vector);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
#endregion
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3cebe3f939a8954395cc5920c892519
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,283 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Animancer
|
||||
{
|
||||
/// <summary>Left or Right.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/Direction2
|
||||
///
|
||||
public enum Direction2
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary><see cref="Vector2.left"/>.</summary>
|
||||
Left,
|
||||
|
||||
/// <summary><see cref="Vector2.right"/>.</summary>
|
||||
Right,
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Up, Right, Down, or Left.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/Direction4
|
||||
///
|
||||
public enum Direction4
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary><see cref="Vector2.up"/>.</summary>
|
||||
Up,
|
||||
|
||||
/// <summary><see cref="Vector2.right"/>.</summary>
|
||||
Right,
|
||||
|
||||
/// <summary><see cref="Vector2.down"/>.</summary>
|
||||
Down,
|
||||
|
||||
/// <summary><see cref="Vector2.left"/>.</summary>
|
||||
Left,
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Up, Right, Down, Left, or their diagonals.</summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/Direction8
|
||||
///
|
||||
public enum Direction8
|
||||
{
|
||||
/// <summary><see cref="Vector2.up"/>.</summary>
|
||||
Up,
|
||||
|
||||
/// <summary><see cref="Vector2.right"/>.</summary>
|
||||
Right,
|
||||
|
||||
/// <summary><see cref="Vector2.down"/>.</summary>
|
||||
Down,
|
||||
|
||||
/// <summary><see cref="Vector2.left"/>.</summary>
|
||||
Left,
|
||||
|
||||
/// <summary><see cref="Vector2"/>(0.7..., 0.7...).</summary>
|
||||
UpRight,
|
||||
|
||||
/// <summary><see cref="Vector2"/>(0.7..., -0.7...).</summary>
|
||||
DownRight,
|
||||
|
||||
/// <summary><see cref="Vector2"/>(-0.7..., -0.7...).</summary>
|
||||
DownLeft,
|
||||
|
||||
/// <summary><see cref="Vector2"/>(-0.7..., 0.7...).</summary>
|
||||
UpLeft,
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>
|
||||
/// Utilities relating to <see cref="Direction2"/>, <see cref="Direction4"/> and <see cref="Direction8"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <strong>Documentation:</strong>
|
||||
/// <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">
|
||||
/// Directional Animation Sets</see>
|
||||
/// </remarks>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer/Directions
|
||||
///
|
||||
public static class Directions
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>1 / (Square Root of 2).</summary>
|
||||
public const float InverseSqrt2 = 0.70710678118f;
|
||||
|
||||
/// <summary>A vector with a magnitude of 1 pointing up to the right.</summary>
|
||||
/// <remarks>The value is approximately (0.7, 0.7).</remarks>
|
||||
public static Vector2 UpRight => new(InverseSqrt2, InverseSqrt2);
|
||||
|
||||
/// <summary>A vector with a magnitude of 1 pointing down to the right.</summary>
|
||||
/// <remarks>The value is approximately (0.7, -0.7).</remarks>
|
||||
public static Vector2 DownRight => new(InverseSqrt2, -InverseSqrt2);
|
||||
|
||||
/// <summary>A vector with a magnitude of 1 pointing down to the left.</summary>
|
||||
/// <remarks>The value is approximately (-0.7, -0.7).</remarks>
|
||||
public static Vector2 DownLeft => new(-InverseSqrt2, -InverseSqrt2);
|
||||
|
||||
/// <summary>A vector with a magnitude of 1 pointing up to the left.</summary>
|
||||
/// <remarks>The value is approximately (-0.707, 0.707).</remarks>
|
||||
public static Vector2 UpLeft => new(-InverseSqrt2, InverseSqrt2);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the opposite of the given `direction`.</summary>
|
||||
public static Direction2 GetOppositeDirection(this Direction2 direction)
|
||||
=> (Direction2)(1 - direction);
|
||||
|
||||
/// <summary>Returns the opposite of the given `direction`.</summary>
|
||||
public static Direction4 GetOppositeDirection(this Direction4 direction)
|
||||
=> (Direction4)((int)(direction + 2) % 4);
|
||||
|
||||
/// <summary>Returns the opposite of the given `direction`.</summary>
|
||||
public static Direction8 GetOppositeDirection(this Direction8 direction)
|
||||
=> (Direction8)((int)(direction + 4) % 8);
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns a vector representing the specified `direction`.</summary>
|
||||
public static Vector2 ToVector2(this Direction2 direction)
|
||||
=> direction switch
|
||||
{
|
||||
Direction2.Left => Vector2.left,
|
||||
Direction2.Right => Vector2.right,
|
||||
_ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction),
|
||||
};
|
||||
|
||||
/// <summary>Returns a vector representing the specified `direction`.</summary>
|
||||
public static Vector2 ToVector2(this Direction4 direction)
|
||||
=> direction switch
|
||||
{
|
||||
Direction4.Up => Vector2.up,
|
||||
Direction4.Right => Vector2.right,
|
||||
Direction4.Down => Vector2.down,
|
||||
Direction4.Left => Vector2.left,
|
||||
_ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction),
|
||||
};
|
||||
|
||||
/// <summary>Returns a vector representing the specified `direction`.</summary>
|
||||
public static Vector2 ToVector2(this Direction8 direction)
|
||||
=> direction switch
|
||||
{
|
||||
Direction8.Up => Vector2.up,
|
||||
Direction8.Right => Vector2.right,
|
||||
Direction8.Down => Vector2.down,
|
||||
Direction8.Left => Vector2.left,
|
||||
Direction8.UpRight => UpRight,
|
||||
Direction8.DownRight => DownRight,
|
||||
Direction8.DownLeft => DownLeft,
|
||||
Direction8.UpLeft => UpLeft,
|
||||
_ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction),
|
||||
};
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the direction closest to the specified `vector.x`.</summary>
|
||||
/// <remarks>Negative `direction` returns <see cref="Left"/>, 0 or positive returns <see cref="Right"/>.</remarks>
|
||||
public static Direction2 ToDirection2(Vector2 vector)
|
||||
=> ToDirection2(vector.x);
|
||||
|
||||
/// <summary>Returns the direction closest to the specified `direction`.</summary>
|
||||
/// <remarks>Negative `direction` returns <see cref="Left"/>, 0 or positive returns <see cref="Right"/>.</remarks>
|
||||
public static Direction2 ToDirection2(float direction)
|
||||
=> direction < 0 ? Direction2.Left : Direction2.Right;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the direction closest to the specified `vector`.</summary>
|
||||
public static Direction4 ToDirection4(Vector2 vector)
|
||||
{
|
||||
if (vector.x >= 0)
|
||||
{
|
||||
if (vector.y >= 0)
|
||||
return vector.x > vector.y ? Direction4.Right : Direction4.Up;
|
||||
else
|
||||
return vector.x > -vector.y ? Direction4.Right : Direction4.Down;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vector.y >= 0)
|
||||
return vector.x < -vector.y ? Direction4.Left : Direction4.Up;
|
||||
else
|
||||
return vector.x < vector.y ? Direction4.Left : Direction4.Down;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns the direction closest to the specified `vector`.</summary>
|
||||
public static Direction4 ToDirection4(Vector2Int vector)
|
||||
{
|
||||
if (vector.x >= 0)
|
||||
{
|
||||
if (vector.y >= 0)
|
||||
return vector.x > vector.y ? Direction4.Right : Direction4.Up;
|
||||
else
|
||||
return vector.x > -vector.y ? Direction4.Right : Direction4.Down;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vector.y >= 0)
|
||||
return vector.x < -vector.y ? Direction4.Left : Direction4.Up;
|
||||
else
|
||||
return vector.x < vector.y ? Direction4.Left : Direction4.Down;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns the direction closest to the specified `vector`.</summary>
|
||||
public static Direction8 ToDirection8(Vector2 vector)
|
||||
{
|
||||
var angle = Mathf.Atan2(vector.y, vector.x);
|
||||
var octant = Mathf.RoundToInt(8 * angle / (2 * Mathf.PI) + 8) % 8;
|
||||
return octant switch
|
||||
{
|
||||
0 => Direction8.Right,
|
||||
1 => Direction8.UpRight,
|
||||
2 => Direction8.Up,
|
||||
3 => Direction8.UpLeft,
|
||||
4 => Direction8.Left,
|
||||
5 => Direction8.DownLeft,
|
||||
6 => Direction8.Down,
|
||||
7 => Direction8.DownRight,
|
||||
_ => throw new ArgumentOutOfRangeException("Invalid octant"),
|
||||
};
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <summary>Returns a copy of the `vector` pointing in the closest <see cref="Direction2"/>.</summary>
|
||||
public static Vector2 SnapToDirection2(Vector2 vector)
|
||||
=> vector.x < 0
|
||||
? new(-vector.magnitude, 0)
|
||||
: new(vector.magnitude, 0);
|
||||
|
||||
/// <summary>Returns a copy of the `vector` pointing in the closest <see cref="Direction4"/>.</summary>
|
||||
public static Vector2 SnapToDirection4(Vector2 vector)
|
||||
{
|
||||
var magnitude = vector.magnitude;
|
||||
var direction = ToDirection4(vector);
|
||||
vector = direction.ToVector2() * magnitude;
|
||||
return vector;
|
||||
}
|
||||
|
||||
/// <summary>Returns a copy of the `vector` pointing in the closest <see cref="Direction8"/>.</summary>
|
||||
public static Vector2 SnapToDirection8(Vector2 vector)
|
||||
{
|
||||
var magnitude = vector.magnitude;
|
||||
var direction = ToDirection8(vector);
|
||||
vector = direction.ToVector2() * magnitude;
|
||||
return vector;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fee4d3d52e50f824aa0e74d1291ec365
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user