It’s line 368 :
using UnityEngine;
using System;
using Opsive.ThirdPersonController.Abilities;
namespace Opsive.ThirdPersonController
{
/// <summary>
/// A small class that stores the state name and the amount of time that it takes to transition to that state.
/// </summary>
[System.Serializable]
public class AnimatorStateData
{
[Tooltip("The name of the state")]
[SerializeField] protected string m_Name = "Movement";
[Tooltip("The time it takes to transition to the state")]
[SerializeField] protected float m_TransitionDuration = 0.2f;
[Tooltip("The Animator multiplier of the state")]
[SerializeField] protected float m_SpeedMultiplier = 1;
[Tooltip("Can the animation be replayed while it is already playing?")]
[SerializeField] protected bool m_CanReplay;
// Exposed properties
public string Name { get { return m_Name; } }
public float TransitionDuration { get { return m_TransitionDuration; } }
public float SpeedMultiplier { get { return m_SpeedMultiplier; } }
public bool CanReplay { get { return m_CanReplay; } }
/// <summary>
/// Constructor for AnimatorStateData.
/// </summary>
public AnimatorStateData(string name, float transitionDuration)
{
m_Name = name;
m_TransitionDuration = transitionDuration;
m_TransitionDuration = 0.2f;
m_SpeedMultiplier = 1;
}
}
/// <summary>
/// Extends AnimatorStateData to store data specific to the item states.
/// </summary>
[System.Serializable]
public class AnimatorItemStateData : AnimatorStateData
{
/// <summary>
/// Specifies the layer that the state can play within.
/// </summary>
public enum AnimatorLayer { Base = 1,
UpperBody = 2,
LeftArm = 4,
RightArm = 8,
LeftHand = 16,
RightHand = 32
}
[Tooltip("Should the Item name be added to the start of the state name?")]
[SerializeField] protected bool m_ItemNamePrefix;
[Tooltip("Specifies the layers that the state can use")]
[SerializeField] protected AnimatorLayer m_Layer = AnimatorLayer.UpperBody;
[Tooltip("Should states with a lower item priority be ignored?")]
[SerializeField] protected bool m_IgnoreLowerPriority;
[Tooltip("Should the animation force root motion? Only applies if the Layer is using the base layer")]
[SerializeField] protected bool m_ForceRootMotion;
// Internal variables
private ItemType m_ItemType;
private Ability m_Ability;
// Exposed properties
public bool ItemNamePrefix { get { return m_ItemNamePrefix; } set { m_ItemNamePrefix = false; } }
public AnimatorLayer Layer { set { m_Layer = value; } }
public bool IgnoreLowerPriority { get { return m_IgnoreLowerPriority; } set { m_IgnoreLowerPriority = value; } }
public bool ForceRootMotion { get { return m_ForceRootMotion; } }
public ItemType ItemType { get { return m_ItemType; } set { m_ItemType = value; } }
public Ability Ability { get { return m_Ability; } set { m_Ability = value; } }
/// <summary>
/// Constructor for AnimatorItemStateData.
/// </summary>
public AnimatorItemStateData(string name, float transitionDuration, bool itemNamePrefix)
: base(name, transitionDuration)
{
m_ItemNamePrefix = itemNamePrefix;
}
/// <summary>
/// Is the state within the specified layer?
/// </summary>
/// <param name="layer">The layer index to check against.</param>
/// <returns>True if the state is within the layer.</returns>
public bool IsStateWithinLayer(int layer)
{
return Utility.InLayerMask(layer, (int)m_Layer);
}
}
/// <summary>
/// Represents an array of AnimatorItemStateData. Can specify how to transition from one item state to another.
/// </summary>
[System.Serializable]
public class AnimatorItemGroupData
{
/// <summary>
/// Specifies how to change from one state to next.
/// </summary>
public enum Order { Random, // Randomlly choose a state within the array.
Sequential, // Move from the first element to the second, third, etc.
Combo, // Moves sequentually until the timeout is reached, then resets back to the start.
}
[Tooltip("Specifies how the Animator should transition from one state to another")]
[SerializeField] protected Order m_StateOrder;
[Tooltip("The amount of time that the next combo state must be run before resetting back to the start")]
[SerializeField] protected float m_ComboTimeout = 1;
[Tooltip("The list of states to cycle through")]
[SerializeField] protected AnimatorItemStateData[] m_States;
// Exposed properties
public Order StateOrder { get { return m_StateOrder; } }
public float ComboTimeout { get { return m_ComboTimeout; } }
// Exposed properties for Item Builder
public AnimatorItemStateData[] States { get { return m_States; } }
// Internal variables
private int m_NextStateIndex;
[NonSerialized] private AnimatorItemCollectionData m_ParentCollection; // Must be NonSerialized or Unity will cause an infinite loop.
/// <summary>
/// Constructor for AnimatorItemGroupData.
/// </summary>
public AnimatorItemGroupData(string name, float transitionDuration, bool itemNamePrefix)
{
m_States = new AnimatorItemStateData[] { new AnimatorItemStateData(name, transitionDuration, itemNamePrefix) };
}
/// <summary>
/// Initializes the AnimatorItemGroupData.
/// </summary>
/// <param name="parentCollection">The AnimatorItemCollectionData that represents the group.</param>
/// <param name="itemType">The ItemType that represents the group.</param>
/// <param name="ability">The Ability that represents the group.</param>
public void Initialize(AnimatorItemCollectionData parentCollection, ItemType itemType, Ability ability)
{
m_ParentCollection = parentCollection;
for (int i = 0; i < m_States.Length; ++i) {
m_States*.ItemType = itemType;*
m_States*.Ability = ability;
_}_
_}*_
///
/// Returns the state in the array.
///
/// The layer to get the state of.
/// The state in the array.
public AnimatorItemStateData GetState(int layer)
{
var nextStateIndex = m_StateOrder == Order.Random ? m_NextStateIndex : m_ParentCollection.NextStateIndex % m_States.Length;
if (m_StateOrder == Order.Combo && m_ParentCollection.LastComboRetirevalTime + m_ComboTimeout < Time.time) {
// Reset the state index if the retrieval time of the next state isn’t faster than the timeout. This will force
// the combo to reset back to the start.
nextStateIndex = 0;
m_ParentCollection.ResetNextState();
}
var itemState = m_States[nextStateIndex];
if (itemState != null && itemState.IsStateWithinLayer(layer)) {
return itemState;
}
return null;
}
///
/// Advance to the next state.
///
public void NextState()
{
if (m_StateOrder == Order.Random) {
m_NextStateIndex = UnityEngine.Random.Range(0, m_States.Length);
}
}
}
///
/// Contains an array of AnimatorItemGroupData elements. Allows for multiple sets of item states.
///
[System.Serializable]
public class AnimatorItemSetData
{
///
/// Specifies how to change from between the item states.
///
public enum Order
{
Random, // Randomlly choose a group.
Sequential, // Move from the first element to the second, third, etc.
}
[Tooltip(“A list of the available item groups”)]
[SerializeField] protected AnimatorItemGroupData[] m_Groups;
[Tooltip(“Specifies how to change between the item states”)]
[SerializeField] protected Order m_GroupOrder;
// Exposed properties for Item Builder
public AnimatorItemGroupData[] Groups { get { return m_Groups; } }
// Internal variables
private int m_NextGroupIndex;
///
/// Consturctor for AnimatorItemSetData.
///
public AnimatorItemSetData(string name, float transitionDuration, bool itemNamePrefix)
{
m_Groups = new AnimatorItemGroupData[] { new AnimatorItemGroupData(name, transitionDuration, itemNamePrefix) };
}
///
/// Initializes the AnimatorItemSetData.
///
/// The AnimatorItemCollectionData that represents the group.
/// The ItemType that represents the group.
public virtual void Initialize(AnimatorItemCollectionData parentCollection, ItemType itemType)
{
for (int i = 0; i < m_Groups.Length; ++i) {
m_Groups*.Initialize(parentCollection, itemType, null);
_}
}*_
///
/// Returns the next AnimatorItemGroupData.
///
/// The next AnimatorItemGroupData.
public AnimatorItemGroupData GetStates()
{
return m_Groups[m_NextGroupIndex];
}
///
/// Advance to the next state.
///
public void NextState()
{
m_Groups[m_NextGroupIndex].NextState();
}
///
/// The next state index should be reset back to the beginning.
///
public void ResetNextState()
{
if (m_GroupOrder == Order.Random) {
m_NextGroupIndex = UnityEngine.Random.Range(0, m_Groups.Length);
} else {
m_NextGroupIndex++;
if (m_NextGroupIndex >= m_Groups.Length) {
m_NextGroupIndex = 0;
}
}
}
}
///
/// Extends AnimatorItemSetData by allowing a particular item state to belong to an Ability.
///
[Serializable]
public class AnimatorItemAbilitySetData : AnimatorItemSetData
{
[Tooltip(“Specifies the ability that should be active when the states can play”)]
[SerializeField] protected Ability m_Ability;
// Exposed Properties
public Ability Ability { get { return m_Ability; } }
///
/// Constructor for AnimatorItemAbilitySetData.
///
public AnimatorItemAbilitySetData(string name, float transitionDuration, bool itemNamePrefix) : base(name, transitionDuration, itemNamePrefix) { }
///
/// Initializes the AnimatorItemAbilitySetData.
///
/// The AnimatorItemCollectionData that represents the set.
/// The ItemType that represents the set.
public override void Initialize(AnimatorItemCollectionData parentCollection, ItemType itemType)
{
for (int i = 0; i < m_Groups.Length; ++i) {
m_Groups*.Initialize(parentCollection, itemType, m_Ability);
_}
}
}*_
///
/// Organizes a set of AnimatorItemGroupData into one parent object.
///
[System.Serializable]
public class AnimatorItemCollectionData
{
[Tooltip(“The states for when idle”)]
[SerializeField] protected AnimatorItemSetData m_Idle;
[Tooltip(“The states for when moving”)]
[SerializeField] protected AnimatorItemSetData m_Movement;
[Tooltip(“The states for when an ability is active”)]
[SerializeField] protected AnimatorItemAbilitySetData[] m_Abilities;
// Internal variables
private AnimatorItemSetData m_ActiveState;
private int m_NextStateIndex;
private float m_LastRetrievalTime = -1;
// Exposed properties
public int NextStateIndex { get { return m_NextStateIndex; } }
public float LastComboRetirevalTime { get { return m_LastRetrievalTime; } }
public float LastUpperBodyStateTransition { get { return m_ActiveState.GetStates().GetState(1).TransitionDuration; } }
// Exposed properties for Item Builder
public AnimatorItemSetData Idle { get { return m_Idle; } }
public AnimatorItemSetData Movement { get { return m_Movement; } }
///
/// Constructor for AnimatorItemCollectionData.
///
public AnimatorItemCollectionData(string idleName, string movementName, float transitionDuration, bool itemNamePrefix)
{
m_Idle = new AnimatorItemSetData(idleName, transitionDuration, itemNamePrefix);
m_Movement = new AnimatorItemSetData(movementName, transitionDuration, itemNamePrefix);
m_Abilities = new AnimatorItemAbilitySetData[] { };
}
///
/// Initializes the AnimatorItemCollectionData to its starting values.
///
/// The ItemType that represents the collection.
public void Initialize(ItemType itemType)
{
m_Idle.Initialize(this, itemType);
m_Movement.Initialize(this, itemType);
if (m_Abilities != null && m_Abilities.Length > 0) {
for (int i = 0; i < m_Abilities.Length; ++i) {
// Arrange the ability states according to the ability priority. This allows the higher priority abilities to be able to specify the state name prefix
// ahead of the lower priority abilities.
Array.Sort(m_Abilities, delegate (AnimatorItemAbilitySetData state1, AnimatorItemAbilitySetData state2) {
if (state1.Ability == null || state2.Ability == null) {
return 0;
}
return state1.Ability.Index.CompareTo(state2.Ability.Index);
});
m_Abilities*.Initialize(this, itemType);
_}
}
}*_
///
/// Returns the AnimatorItemStateData of the given AnimatorItemGroupData.
///
/// The layer to get the state of.
/// Is the character moving?
/// The AnimatorItemStateData of the given AnimatorItemGroupData. Can be null.
public AnimatorItemStateData GetState(int layer, bool moving)
{
var abilityStates = m_Abilities;
if (abilityStates != null) {
// Abilities have the highest priority.
for (int i = 0; i < abilityStates.Length; ++i) {
if (abilityStates*.Ability.IsActive) {*
var state = GetState(layer, abilityStates*);*
if (state != null) {
return state;
}
}
}
}
if (moving) {
// Moving has the next highest priority.
var state = GetState(layer, m_Movement);
if (state != null) {
return state;
}
} else {
// Idle has the lowest priority.
var state = GetState(layer, m_Idle);
if (state != null) {
return state;
}
}
return null;
}