// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik // using System; using System.Collections.Generic; using UnityEngine; using Object = UnityEngine.Object; namespace Animancer { /// A generic set of objects corresponding to up/right/down/left. /// /// Documentation: /// /// Directional Animation Sets /// /// https://kybernetik.com.au/animancer/api/Animancer/DirectionalSet_1 /// [AnimancerHelpUrl(typeof(DirectionalSet<>))] public abstract class DirectionalSet : ScriptableObject { /************************************************************************************************************************/ #region Read-Only /************************************************************************************************************************/ #if UNITY_ASSERTIONS private bool _AllowChanges; #endif /// [Assert-Only] Sets a debug flag to enable or disable the ability to modify this set. [System.Diagnostics.Conditional(Strings.Assertions)] public void AllowChanges(bool allow = true) { #if UNITY_ASSERTIONS _AllowChanges = allow; #endif } /// [Assert-Only] /// Throws an if wasn't called. /// [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 /************************************************************************************************************************/ /// The number of directions in this set. public abstract int DirectionCount { get; } /************************************************************************************************************************/ /// Returns the name of the specified `direction`. protected abstract string GetDirectionName(int direction); /************************************************************************************************************************/ /// Returns the object associated with the specified `direction`. public abstract T Get(int direction); /************************************************************************************************************************/ /// Returns the object closest to the specified `direction`. public abstract T Get(Vector2 direction); /************************************************************************************************************************/ /// Sets the object associated with the specified `direction`. public abstract void Set(int direction, T value); /************************************************************************************************************************/ /// [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). /// public int SetByName(string name, T value) { var direction = GetDirection(name); if (direction >= 0) Set(direction, value); return direction; } /// [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). /// public int SetByName(U value) where U : Object, T => SetByName(value.name, value); /************************************************************************************************************************/ #region Conversion /************************************************************************************************************************/ /// Returns a vector representing the specified `direction`. public abstract Vector2 GetDirection(int direction); /************************************************************************************************************************/ /// Returns the index of the direction which best matches the given `name`. public abstract int GetDirection(string name); /************************************************************************************************************************/ /// Returns a copy of the `vector` pointing in the closest direction this set has an object for. public abstract Vector2 Snap(Vector2 vector); /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Gathering /************************************************************************************************************************/ /// Adds all objects from this set to the `values`, starting from the specified `index`. public void AddTo(T[] values, int index) { var count = DirectionCount; for (int i = 0; i < count; i++) values[index + i] = Get(i); } /// Adds all objects from this set to the `values`. public void AddTo(List values) { var count = DirectionCount; for (int i = 0; i < count; i++) values.Add(Get(i)); } /************************************************************************************************************************/ /// /// Adds unit vectors corresponding to each of the objects in this set to the `directions`, /// starting from the specified `index`. /// public void AddTo(Vector2[] directions, int index) { var count = DirectionCount; for (int i = 0; i < count; i++) directions[index + i] = GetDirection(i); } /************************************************************************************************************************/ /// Calls and . public void AddTo(T[] values, Vector2[] directions, int index) { AddTo(values, index); AddTo(directions, index); } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ } }