You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1125 lines
41 KiB
C#
1125 lines
41 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using MalbersAnimations.Scriptables;
|
|
using UnityEngine.Events;
|
|
|
|
namespace MalbersAnimations.Controller
|
|
{
|
|
/// All Callbacks/Public Methods are Here
|
|
public partial class MAnimal
|
|
{
|
|
#region INPUTS
|
|
|
|
/// <summary>Disconnect and Reconnect the States and Modes to the Input Source</summary>
|
|
public virtual void ResetInputSource()
|
|
{
|
|
UpdateInputSource(false); //Disconnect
|
|
UpdateInputSource(true); //Reconnect
|
|
}
|
|
|
|
/// <summary>Updates all the Input from Malbers Input in case needed (Rewired conextion(</summary>
|
|
public virtual void UpdateInputSource(bool connect)
|
|
{
|
|
if (InputSource == null)
|
|
InputSource = gameObject.FindInterface<IInputSource>(); //Find if we have a InputSource
|
|
|
|
if (InputSource != null)
|
|
{
|
|
foreach (var state in states)
|
|
state.ConnectInput(InputSource, connect);
|
|
|
|
foreach (var mode in modes)
|
|
mode.ConnectInput(InputSource, connect);
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Player
|
|
/// <summary>Set an Animal as the Main Player and remove the otherOne</summary>
|
|
public virtual void SetMainPlayer()
|
|
{
|
|
if (MainAnimal) //if there's a main animal already seted
|
|
{
|
|
MainAnimal.isPlayer.Value = false;
|
|
}
|
|
|
|
this.isPlayer.Value = true;
|
|
MainAnimal = this;
|
|
}
|
|
|
|
public void DisableMainPlayer()
|
|
{
|
|
if (MainAnimal == this) MainAnimal = null;
|
|
}
|
|
#endregion
|
|
|
|
#region Teleport
|
|
/// <summary>Teleports the Animal to a Transform position </summary>
|
|
public virtual void Teleport(Transform newPos)
|
|
{
|
|
if (newPos) Teleport(newPos.position);
|
|
}
|
|
|
|
/// <summary>Teleports the Animal to a Transform Position, It also Rotates the Animal to that transform Rotation</summary>
|
|
public virtual void TeleportRot(Transform newPos)
|
|
{
|
|
if (newPos)
|
|
{
|
|
Teleport(newPos.position);
|
|
transform.rotation = newPos.rotation;
|
|
}
|
|
}
|
|
|
|
|
|
public virtual void Teleport(Vector3 newPos)
|
|
{
|
|
Teleport_Internal(newPos);
|
|
OnTeleport.Invoke(newPos);
|
|
}
|
|
|
|
/// <summary>Used by the States to Teleport withouth sending the Event </summary>
|
|
internal void Teleport_Internal(Vector3 newPos)
|
|
{
|
|
transform.position = newPos;
|
|
LastPos = transform.position;
|
|
platform = null;
|
|
//if (debugStates) Debugging($"{name}: Teleported to {newPos}");
|
|
}
|
|
|
|
|
|
private void Debugging(string value)
|
|
{
|
|
#if UNITY_EDITOR
|
|
Debug.Log($"<B>[{name}]</B> → <color=white>{value}</color>",this);
|
|
#endif
|
|
}
|
|
|
|
#endregion
|
|
|
|
// #region Animal Aligment
|
|
//public virtual void Aling_Position(Vector3 Destination, float time, AnimationCurve curve)
|
|
//{
|
|
// if (!Aligning) StartCoroutine(AlignPos(Destination,time,curve));
|
|
//}
|
|
|
|
//public virtual void Aling_Position(Vector3 Destination, Quaternion DestRot, float time, AnimationCurve curve)
|
|
//{
|
|
// if (!Aligning) StartCoroutine(AlignTransform(Destination, DestRot, time, curve));
|
|
//}
|
|
|
|
//private bool Aligning;
|
|
|
|
//IEnumerator AlignPos(Vector3 NewPosition, float time, AnimationCurve curve = null)
|
|
//{
|
|
// float elapsedTime = 0;
|
|
// Aligning = true;
|
|
|
|
// var Wait = new WaitForFixedUpdate();
|
|
|
|
// Vector3 CurrentPos = transform.position;
|
|
|
|
// while ((time > 0) && (elapsedTime <= time))
|
|
// {
|
|
// float result = curve != null ? curve.Evaluate(elapsedTime / time) : elapsedTime / time; //Evaluation of the Pos curve
|
|
// transform.position = Vector3.LerpUnclamped(CurrentPos, NewPosition, result);
|
|
// elapsedTime += Time.fixedDeltaTime;
|
|
|
|
// yield return Wait;
|
|
// }
|
|
|
|
// transform.position = NewPosition;
|
|
// Aligning = false;
|
|
// yield return null;
|
|
//}
|
|
//IEnumerator AlignTransform(Vector3 PosDestination, Quaternion RotDestination, float time, AnimationCurve curve = null)
|
|
//{
|
|
// float elapsedTime = 0;
|
|
// Aligning = true;
|
|
|
|
// Vector3 CurrentPos = transform.position;
|
|
// Quaternion CurrentRot = transform.rotation;
|
|
|
|
// var Wait = new WaitForFixedUpdate();
|
|
// while ((time > 0) && (elapsedTime <= time))
|
|
// {
|
|
// float result = curve != null ? curve.Evaluate(elapsedTime / time) : elapsedTime / time; //Evaluation of the Pos curve
|
|
// transform.position = Vector3.LerpUnclamped(CurrentPos, PosDestination, result);
|
|
// transform.rotation = Quaternion.LerpUnclamped(CurrentRot, RotDestination, result);
|
|
// elapsedTime += Time.fixedDeltaTime;
|
|
|
|
// yield return Wait;
|
|
// }
|
|
// transform.position = PosDestination;
|
|
// transform.rotation = RotDestination;
|
|
// Aligning = false;
|
|
// yield return null;
|
|
//}
|
|
// #endregion
|
|
|
|
#region Gravity
|
|
/// <summary>Resets the gravity to the default Vector.Down value</summary>
|
|
public void ResetGravityDirection() => Gravity = Vector3.down;
|
|
|
|
/// <summary>Clears the Gravity Logic</summary>
|
|
internal void ResetGravityValues()
|
|
{
|
|
GravityTime = m_gravityTime;
|
|
GravityStoredVelocity = Vector3.zero;
|
|
// GravitySpeed = 0;
|
|
}
|
|
internal void ResetUPVector()
|
|
{
|
|
RB.velocity = Vector3.ProjectOnPlane(RB.velocity, UpVector);
|
|
//Extra OPTIONAL
|
|
AdditivePosition = Vector3.ProjectOnPlane(AdditivePosition, UpVector);
|
|
DeltaPos = Vector3.ProjectOnPlane(DeltaPos, UpVector);
|
|
}
|
|
|
|
/// <summary>The Ground will change the Gravity Direction. Using the ground Normal as reference</summary>
|
|
/// <param name="value"> Enable/Disable the logic</param>
|
|
public void GroundChangesGravity(bool value) => ground_Changes_Gravity.Value = value;
|
|
|
|
|
|
/// <summary>Aling the character instantly to the Gravity Direction</summary>
|
|
public void AlignToGravity()
|
|
{
|
|
Quaternion AlignRot = Quaternion.FromToRotation(transform.up, UpVector) * transform.rotation; //Calculate the orientation to Terrain
|
|
base.transform.rotation = AlignRot;
|
|
}
|
|
#endregion
|
|
|
|
#region Stances
|
|
|
|
/// <summary>Toggle the New Stance with the Default Stance▼▲ </summary>
|
|
public void Stance_Toggle(StanceID NewStance) => Stance = (Stance.ID == NewStance.ID) ? DefaultStance : NewStance;
|
|
|
|
public void Stance_Set(StanceID id) => Stance = id;
|
|
|
|
public void Stance_Set(int id)
|
|
{
|
|
var NewStance = ScriptableObject.CreateInstance<StanceID>();
|
|
NewStance.name = "Stance(" + id+")";
|
|
NewStance.ID = id;
|
|
Stance = NewStance;
|
|
}
|
|
|
|
|
|
/// <summary>Changes the Last State on the Animator</summary>
|
|
public void Stance_SetLast(int id)
|
|
{
|
|
LastStance = id;
|
|
SetOptionalAnimParameter(hash_LastStance, LastStance); //Set on the Animator the Last Stance
|
|
}
|
|
|
|
|
|
|
|
public void Stance_Reset() => Stance = defaultStance;
|
|
|
|
#endregion
|
|
|
|
#region Animator Methods
|
|
|
|
/// <summary> Method required for the Interface IAnimator Listener to send messages From the Animator to any class who uses this Interface</summary>
|
|
public virtual bool OnAnimatorBehaviourMessage(string message, object value)
|
|
{
|
|
foreach (var state in states) state.ReceiveMessages(message, value);
|
|
|
|
return this.InvokeWithParams(message, value);
|
|
}
|
|
|
|
public void SetAnimatorSpeed(float value) => AnimatorSpeed = value;
|
|
|
|
|
|
/// <summary>Set a Int on the Animator</summary>
|
|
public virtual void SetAnimParameter(int hash, int value) => Anim.SetInteger(hash, value);
|
|
|
|
/// <summary>Set a float on the Animator</summary>
|
|
public virtual void SetAnimParameter(int hash, float value) => Anim.SetFloat(hash, value);
|
|
|
|
/// <summary>Set a Bool on the Animator</summary>
|
|
public virtual void SetAnimParameter(int hash, bool value) => Anim.SetBool(hash, value);
|
|
|
|
/// <summary>Set a Trigger to the Animator</summary>
|
|
public virtual void SetAnimParameter(int hash) => Anim.SetTrigger(hash);
|
|
|
|
public virtual void SetOptionalAnimParameter(int Hash, float value)
|
|
{
|
|
if (Hash != 0) SetFloatParameter(Hash, value);
|
|
}
|
|
|
|
public virtual void SetOptionalAnimParameter(int Hash, int value)
|
|
{
|
|
if (Hash != 0) SetIntParameter(Hash, value);
|
|
}
|
|
|
|
public virtual void SetOptionalAnimParameter(int Hash, bool value)
|
|
{
|
|
if (Hash!=0) SetBoolParameter(Hash, value);
|
|
}
|
|
|
|
public virtual void SetOptionalAnimParameter(int Hash)
|
|
{
|
|
if (Hash != 0) SetTriggerParameter(Hash);
|
|
}
|
|
|
|
/// <summary> Set the Parameter Random to a value and pass it also to the Animator </summary>
|
|
public void SetRandom(int value, int priority)
|
|
{
|
|
if (!enabled || Sleep) return;
|
|
|
|
if (priority >= RandomPriority)
|
|
{
|
|
RandomPriority = priority;
|
|
RandomID = Randomizer ? value : 0;
|
|
SetOptionalAnimParameter(hash_Random, RandomID);
|
|
}
|
|
}
|
|
|
|
public void ResetRandomPriority(int priority)
|
|
{
|
|
if (priority >= RandomPriority)
|
|
{
|
|
RandomPriority = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Used by Animator Events </summary>
|
|
public virtual void EnterTag(string tag) => AnimStateTag = Animator.StringToHash(tag);
|
|
#endregion
|
|
|
|
#region States
|
|
/// <summary> Set the StateFloat value and pass it to the StateFloat parameter on the Animator </summary>
|
|
public void State_SetFloat(float value)
|
|
{
|
|
// Debug.Log($"State_Float: {value:F3}");
|
|
State_Float = value;
|
|
SetFloatParameter(hash_StateFloat, State_Float);
|
|
}
|
|
|
|
|
|
/// <summary> Set the StateFloat value and pass it to the StateFloat parameter on the Animator. Uses a Smooth Value </summary>
|
|
public void State_SetFloat(float value, float smoothValue)
|
|
{
|
|
// Debug.Log($"State_Float: {value:F3}");
|
|
State_Float = Mathf.Lerp(State_Float, value, smoothValue * DeltaTime);
|
|
SetFloatParameter(hash_StateFloat, State_Float);
|
|
}
|
|
|
|
|
|
/// <summary>Find an old State and replace it for a new one at Runtime </summary>
|
|
public void State_Replace(State NewState)
|
|
{
|
|
if (CloneStates)
|
|
{
|
|
State instance = (State)ScriptableObject.CreateInstance(NewState.GetType());
|
|
instance = ScriptableObject.Instantiate(NewState); //Create a clone from the Original Scriptable Objects! IMPORTANT
|
|
instance.name = instance.name.Replace("(Clone)", "(C)");
|
|
NewState = instance;
|
|
}
|
|
|
|
var oldState = states.Find(s => s.ID == NewState.ID);
|
|
|
|
if (oldState)
|
|
{
|
|
var index = states.IndexOf(oldState);
|
|
var oldStatePriority = oldState.Priority;
|
|
|
|
if (CloneStates) Destroy(oldState); //Destroy the Clone
|
|
|
|
oldState = NewState;
|
|
oldState.AwakeState(this);
|
|
oldState.Priority = oldStatePriority;
|
|
oldState.InitializeState();
|
|
oldState.ExitState();
|
|
|
|
|
|
states[index] = oldState; //Replace the list Item
|
|
|
|
UpdateInputSource(true); //Need to Update the Sources
|
|
}
|
|
}
|
|
|
|
/// <summary>Force the Activation of an state regarding if is enable or not</summary>
|
|
public virtual void State_Force(StateID ID) => State_Force(ID.ID);
|
|
|
|
/// <summary>Returns if the Animal has a state by its ID</summary>
|
|
public bool HasState(StateID ID) => HasState(ID.ID);
|
|
|
|
|
|
/// <summary>Returns if the Animal has a state by its int ID value</summary>
|
|
public bool HasState(int ID) => State_Get(ID) != null;
|
|
|
|
/// <summary>Returns if the Animal has a state by its name</summary>
|
|
public bool HasState(string statename) => states.Exists(s => s.name == statename);
|
|
|
|
/// <summary>Set the State Status on the Animator</summary>
|
|
public virtual void State_SetStatus(int status)
|
|
{
|
|
// Debug.Log("status = " + status);
|
|
SetIntParameter(hash_StateEnterStatus, status);
|
|
}
|
|
|
|
/// <summary>Set the State Exit Status on the Animator</summary>
|
|
public virtual void State_SetExitStatus(int ExitStatus) => SetOptionalAnimParameter(hash_StateExitStatus, ExitStatus);
|
|
|
|
public virtual void State_Enable(StateID ID) => State_Enable(ID.ID);
|
|
public virtual void State_Disable(StateID ID) => State_Disable(ID.ID);
|
|
|
|
public virtual void State_Enable(int ID) => State_Get(ID)?.Enable(true);
|
|
|
|
public virtual void State_Disable(int ID) => State_Get(ID)?.Enable(false);
|
|
|
|
/// <summary>Force the Activation of an state regarding if is enable or not</summary>
|
|
public virtual void State_Force(int ID)
|
|
{
|
|
State state = State_Get(ID);
|
|
|
|
if (state == ActiveState)
|
|
{
|
|
state.ForceActivate();
|
|
|
|
StartCoroutine(C_EnterCoreAnim(state)); //Little Hack!
|
|
}
|
|
else
|
|
state.ForceActivate();
|
|
}
|
|
|
|
IEnumerator C_EnterCoreAnim(State state)
|
|
{
|
|
state.IsPending = true;
|
|
yield return null;
|
|
// yield return null;
|
|
state.AnimationTagEnter(AnimStateTag);
|
|
}
|
|
|
|
/// <summary> Allow Lower States to be activated </summary>
|
|
public virtual void State_AllowExit(StateID ID) => State_AllowExit(ID.ID);
|
|
|
|
/// <summary> Allow Lower States to be activated </summary>
|
|
public virtual void State_AllowExit(int ID)
|
|
{
|
|
State state = State_Get(ID);
|
|
if (state && state != ActiveState) return; //Do not Exit if we are not the Active State
|
|
state?.AllowExit();
|
|
}
|
|
|
|
public virtual void State_Allow_Exit(int nextState)
|
|
{
|
|
if (ActiveState.AllowExit())
|
|
{
|
|
if (nextState != -1) State_Activate(nextState);
|
|
}
|
|
}
|
|
public virtual void State_Allow_Exit(int nextState , int exitStatus)
|
|
{
|
|
if (ActiveState.AllowExit())
|
|
{
|
|
State_SetExitStatus(exitStatus);
|
|
if (nextState != -1) State_Activate(nextState);
|
|
}
|
|
}
|
|
|
|
public virtual void State_Active_IsPersistent(bool value) => ActiveState.IsPersistent = value;
|
|
|
|
public virtual void State_InputTrue(StateID ID) => State_Get(ID)?.SetInput(true);
|
|
public virtual void State_InputFalse(StateID ID) => State_Get(ID)?.SetInput(false);
|
|
public virtual void ActiveStateAllowExit() => ActiveState.AllowExit();
|
|
|
|
|
|
/// <summary>Try to Activate a State direclty from the Animal Script </summary>
|
|
public virtual void State_Activate(StateID ID) => State_Activate(ID.ID);
|
|
|
|
|
|
/// <summary>Try to Activate a State by its ID, Checking the necessary conditions for activation</summary>
|
|
public virtual bool State_TryActivate(int ID)
|
|
{
|
|
State NewState = State_Get(ID);
|
|
if (NewState && NewState.CanBeActivated)
|
|
{
|
|
return NewState.TryActivate();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>Try to Activate a State direclty from the Animal Script </summary>
|
|
public virtual void State_Activate(int ID)
|
|
{
|
|
State NewState = State_Get(ID);
|
|
|
|
if (NewState && NewState.CanBeActivated) NewState.Activate();
|
|
}
|
|
|
|
/// <summary> Return a State by its ID value </summary>
|
|
public virtual State State_Get(int ID) => states.Find(s => s.ID == ID);
|
|
|
|
/// <summary> Return a State by its ID</summary>
|
|
public virtual State State_Get(StateID ID)
|
|
{
|
|
if (ID == null) return null;
|
|
return State_Get(ID.ID);
|
|
}
|
|
|
|
/// <summary> Call the Reset State on the given State </summary>
|
|
public virtual void State_Reset(int ID) => State_Get(ID)?.ResetState();
|
|
|
|
/// <summary> Call the Reset State on the given State </summary>
|
|
public virtual void State_Reset(StateID ID) => State_Reset(ID.ID);
|
|
|
|
///<summary> Find to the Possible State and store it to the (PreState) using an StateID value</summary>
|
|
public virtual void State_Pin(StateID stateID) => State_Pin(stateID.ID);
|
|
|
|
///<summary> Find to the Possible State and store it to the (PreState) using an int value</summary>
|
|
public virtual void State_Pin(int stateID) => Pin_State = State_Get(stateID);
|
|
|
|
///<summary>Use the (PreState) the and Try to activate it using an Input</summary>
|
|
public virtual void State_Pin_ByInput(bool input) => Pin_State?.ActivatebyInput(input);
|
|
public virtual void State_Pin_ByInputToggle() => Pin_State?.ActivatebyInput(!Pin_State.InputValue);
|
|
|
|
///<summary> Send to the Possible State (PreState) the value of the Input</summary>
|
|
public virtual void State_Activate_by_Input(StateID stateID, bool input) => State_Activate_by_Input(stateID.ID, input);
|
|
|
|
///<summary> Send to the Possible State (PreState) the value of the Input</summary>
|
|
public virtual void State_Activate_by_Input(int stateID, bool input)
|
|
{
|
|
State_Pin(stateID);
|
|
State_Pin_ByInput(input);
|
|
}
|
|
|
|
///<summary>If the Pin State is the Active State then it will set the StateExit Status</summary>
|
|
public virtual void State_Pin_ExitStatus(int stateExitStatus)
|
|
{
|
|
if (Pin_State != null && Pin_State.IsActiveState)
|
|
State_SetExitStatus(stateExitStatus);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Modes
|
|
public bool HasMode(ModeID ID) => HasMode(ID.ID);
|
|
|
|
/// <summary> Returns if the Animal has a mode By its ID</summary>
|
|
public bool HasMode(int ID) => Mode_Get(ID) != null;
|
|
|
|
/// <summary> Returns a Mode by its ID</summary>
|
|
public virtual Mode Mode_Get(ModeID ModeID) => Mode_Get(ModeID.ID);
|
|
|
|
/// <summary> Returns a Mode by its ID</summary>
|
|
public virtual Mode Mode_Get(int ModeID) => modes.Find(m => m.ID == ModeID);
|
|
|
|
/// <summary> Set the Parameter Int ID to a value and pass it also to the Animator </summary>
|
|
public void SetModeStatus(int value)
|
|
{
|
|
// Debug.Log("SetModeStatus" + value);
|
|
|
|
SetIntParameter?.Invoke(hash_ModeStatus, ModeStatus = value);
|
|
}
|
|
|
|
public void Mode_SetPower(float value) => SetOptionalAnimParameter(hash_ModePower, ModePower = value);
|
|
|
|
/// <summary>Activate a Random Ability on the Animal using a Mode ID</summary>
|
|
public virtual void Mode_Activate(ModeID ModeID) => Mode_Activate(ModeID.ID, -99);
|
|
|
|
/// <summary>Enable a mode on the Animal</summary>
|
|
/// <param name="ModeID">ID of the Mode</param>
|
|
/// <param name="AbilityIndex">Ability Index. If this value is -1 then the Mode will activate a random Ability</param>
|
|
public virtual void Mode_Activate(ModeID ModeID, int AbilityIndex) => Mode_Activate(ModeID.ID, AbilityIndex);
|
|
|
|
public virtual void Mode_Activate_By_Input(ModeID ModeID, bool InputValue) => Mode_Get(ModeID.ID).ActivatebyInput(InputValue);
|
|
|
|
#region INTERFACE ICHARACTER ACTION
|
|
public bool PlayAction(int Set, int Index) => Mode_TryActivate(Set, Index);
|
|
|
|
public bool ForceAction(int Set, int Index) => Mode_ForceActivate(Set, Index);
|
|
|
|
public bool IsPlayingAction => IsPlayingMode;
|
|
#endregion
|
|
|
|
/// <summary>Activate a mode on the Animal combining the Mode and Ability e.g 4002</summary>
|
|
public virtual void Mode_Activate(int ModeID)
|
|
{
|
|
if (ModeID == 0) return;
|
|
|
|
var id = Mathf.Abs(ModeID / 1000);
|
|
|
|
if (id == 0)
|
|
{
|
|
Mode_Activate(ModeID, -99);
|
|
}
|
|
else
|
|
{
|
|
Mode_Activate(id, ModeID % 100);
|
|
}
|
|
}
|
|
|
|
/// <summary>Activate a mode on the Animal</summary>
|
|
/// <param name="ModeID">ID of the Mode</param>
|
|
/// <param name="AbilityIndex">Ability Index. If this value is -99 then the Mode will activate a random Ability</param>
|
|
public virtual void Mode_Activate(int ModeID, int AbilityIndex)
|
|
{
|
|
var mode = Mode_Get(ModeID);
|
|
|
|
if (mode != null)
|
|
{
|
|
Pin_Mode = mode;
|
|
Pin_Mode.TryActivate(AbilityIndex);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("You are trying to Activate a Mode but here's no Mode with the ID or is Disabled: " + ModeID);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>Activate a mode on the Animal</summary>
|
|
/// <param name="ModeID">ID of the Mode</param>
|
|
/// <param name="AbilityIndex">Ability Index. If this value is -99 then the Mode will activate a random Ability</param>
|
|
public virtual void Mode_Activate(int ModeID, int AbilityIndex, AbilityStatus status)
|
|
{
|
|
var mode = Mode_Get(ModeID);
|
|
|
|
if (mode != null)
|
|
{
|
|
Pin_Mode = mode;
|
|
|
|
var ability = Pin_Mode.GetAbility(AbilityIndex);
|
|
|
|
if (ability != null)
|
|
{
|
|
ability.Status = status; //Change the Status of the ability
|
|
}
|
|
|
|
Pin_Mode.TryActivate(AbilityIndex);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("You are trying to Activate a Mode but here's no Mode with the ID or is Disabled: " + ModeID);
|
|
}
|
|
}
|
|
|
|
|
|
public virtual bool Mode_ForceActivate(ModeID ModeID, int AbilityIndex) => Mode_ForceActivate(ModeID.ID, AbilityIndex);
|
|
|
|
public virtual void Mode_ForceActivate(ModeID ModeID) => Mode_ForceActivate(ModeID.ID, 0);
|
|
|
|
public virtual bool Mode_ForceActivate(int ModeID, int AbilityIndex)
|
|
{
|
|
var mode = Mode_Get(ModeID);
|
|
|
|
if (mode != null)
|
|
{
|
|
Pin_Mode = mode;
|
|
return Pin_Mode.ForceActivate(AbilityIndex);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/// <summary> Returns True and Activate the mode in case ir can be Activated, if not it will return false</summary>
|
|
public bool Mode_TryActivate(int ModeID, int AbilityIndex = -99)
|
|
{
|
|
var mode = Mode_Get(ModeID);
|
|
|
|
if (mode != null)
|
|
{
|
|
Pin_Mode = mode;
|
|
return Pin_Mode.TryActivate(AbilityIndex);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool Mode_TryActivate(int ModeID, int AbilityIndex, AbilityStatus status, float time = 0)
|
|
{
|
|
var mode = Mode_Get(ModeID);
|
|
|
|
if (mode != null)
|
|
{
|
|
Pin_Mode = mode;
|
|
return Pin_Mode.TryActivate(AbilityIndex, status, time);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/// <summary>Stop all modes </summary>
|
|
public virtual void Mode_Stop()
|
|
{
|
|
if (IsPlayingMode)
|
|
{
|
|
activeMode.InputValue = false;
|
|
Mode_Interrupt();
|
|
}
|
|
else
|
|
{
|
|
ModeAbility = 0; //Reset Mode
|
|
SetModeStatus(Int_ID.Available);
|
|
return;
|
|
}
|
|
//ActiveMode.PlayingMode = false;
|
|
ActiveMode = null;
|
|
ModeTime = 0; //Reset Mode Time
|
|
}
|
|
|
|
/// <summary> Re-Check all the Sprint conditions and Invoke the Sprint Event </summary>
|
|
public virtual void SprintUpdate() => Sprint = sprint; //Check Again the sprint everytime a new state is active IMPORTANT
|
|
public virtual void Sprint_Set(bool value) => Sprint = value;
|
|
|
|
|
|
|
|
/// <summary>Set IntID to -2 to exit the Mode Animation</summary>
|
|
public virtual void Mode_Interrupt() => SetModeStatus(Int_ID.Interrupted);
|
|
|
|
/// <summary>Deactivate all modes</summary>
|
|
public virtual void Mode_Disable_All()
|
|
{
|
|
foreach (var mod in modes) mod.Disable();
|
|
}
|
|
|
|
/// <summary>Reactivate all modes</summary>
|
|
public virtual void Mode_Enable_All()
|
|
{
|
|
foreach (var mod in modes) mod.Enable();
|
|
}
|
|
|
|
/// <summary>Disable a Mode by his ID</summary>
|
|
public virtual void Mode_Disable(ModeID id) => Mode_Disable((int)id);
|
|
|
|
/// <summary>Disable a Mode by his ID</summary>
|
|
public virtual void Mode_Disable(int id) => Mode_Get(id)?.Disable();
|
|
|
|
public virtual void Mode_Disable(string mod)
|
|
{
|
|
foreach (var M in modes)
|
|
{
|
|
if (mod.Contains(M.Name))
|
|
M.Disable();
|
|
}
|
|
}
|
|
|
|
public virtual void Mode_Enable(string mod)
|
|
{
|
|
foreach (var M in modes)
|
|
{
|
|
if (mod.Contains(M.Name))
|
|
M.Enable();
|
|
}
|
|
}
|
|
|
|
/// <summary>Set the Active Ability Index of a Mode</summary>
|
|
public virtual void Mode_ActiveAbilityIndex(int Mode, int ActiveAbility) => Mode_Get(Mode).SetAbilityIndex(ActiveAbility);
|
|
|
|
/// <summary>Enable a Mode by his ID</summary>
|
|
public virtual void Mode_Enable(ModeID id) => Mode_Enable(id.ID);
|
|
|
|
/// <summary>Enable a Mode by his ID</summary>
|
|
public virtual void Mode_Enable(int id) => Mode_Get(id)?.Enable();
|
|
|
|
/// <summary>Pin a mode to Activate later</summary>
|
|
public virtual void Mode_Pin(ModeID ID)
|
|
{
|
|
if (Pin_Mode != null && Pin_Mode.ID == ID) return; //the mode is already pinned
|
|
|
|
var pin = Mode_Get(ID);
|
|
|
|
Pin_Mode = null; //Important! Clean the Pin Mode
|
|
if (pin != null && pin.Active) Pin_Mode = pin;
|
|
}
|
|
|
|
/// <summary>Pin an Ability on the Pin Mode to Activate later</summary>
|
|
public virtual void Mode_Pin_Ability(int AbilityIndex)
|
|
{
|
|
if (AbilityIndex == 0) return;
|
|
if (Pin_Mode != null) Pin_Mode.SetAbilityIndex(AbilityIndex);
|
|
}
|
|
|
|
|
|
/// <summary>Enable/Disables an Ability on a mode, Returns true if the Method succeeded</summary>
|
|
public virtual bool Mode_Ability_Enable(int ModeID, int AbilityID, bool enable)
|
|
{
|
|
var mode = Mode_Get(ModeID);
|
|
if (mode != null)
|
|
{
|
|
var ability = mode.GetAbility(AbilityID);
|
|
if (ability != null)
|
|
{
|
|
ability.Active = enable;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>Pin an Ability on the Pin Mode to Activate later</summary>
|
|
public virtual void Mode_Pin_Ability_Enable(int AbilityIndex)
|
|
{
|
|
if (AbilityIndex == 0) return;
|
|
var ability = Pin_Mode?.GetAbility(AbilityIndex);
|
|
if (ability != null) ability.Active = true;
|
|
}
|
|
|
|
/// <summary>Pin an Ability on the Pin Mode to Activate later</summary>
|
|
public virtual void Mode_Pin_Disable_Ability(int AbilityIndex)
|
|
{
|
|
if (AbilityIndex == 0) return;
|
|
var ability = Pin_Mode?.GetAbility(AbilityIndex);
|
|
if (ability != null) ability.Active = false;
|
|
}
|
|
|
|
|
|
/// <summary>Changes Pinned Mode Status in all the Abilities</summary>
|
|
public virtual void Mode_Pin_Status(int aMode)
|
|
{
|
|
if (Pin_Mode != null)
|
|
{
|
|
foreach (var ability in Pin_Mode.Abilities)
|
|
{
|
|
ability.Status = (AbilityStatus)aMode;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Changes the Pinned Mode time when using Hold by time Status</summary>
|
|
public virtual void Mode_Pin_Time(float time)
|
|
{
|
|
if (Pin_Mode != null)
|
|
foreach (var ab in Pin_Mode.Abilities)
|
|
ab.AbilityTime= time;
|
|
}
|
|
|
|
public virtual void Mode_Pin_Enable(bool value) => Pin_Mode?.SetActive(value);
|
|
public virtual void Mode_Pin_EnableInvert(bool value) => Pin_Mode?.SetActive(!value);
|
|
|
|
public virtual void Mode_Pin_Input(bool value) => Pin_Mode?.ActivatebyInput(value);
|
|
|
|
/// <summary>Tries to Activate the Pin Mode</summary>
|
|
public virtual void Mode_Pin_Activate() => Pin_Mode?.TryActivate();
|
|
|
|
/// <summary>Tries to Activate the Pin Mode with an Ability</summary>
|
|
public virtual void Mode_Pin_AbilityActivate(int AbilityIndex) => Pin_Mode?.TryActivate(AbilityIndex);
|
|
|
|
#endregion
|
|
|
|
#region Movement
|
|
public virtual void Strafe_Toggle() => Strafe ^= true;
|
|
|
|
/// <summary>Gets the movement from the Input Script or AI</summary>
|
|
public virtual void Move(Vector3 move)
|
|
{
|
|
UseRawInput = false;
|
|
RawInputAxis = move;//.normalized; //Store the Last Raw Direction sent (Important to Normalize?? why??)
|
|
Rotate_at_Direction = false;
|
|
DeltaAngle = 0;
|
|
}
|
|
|
|
/// <summary>Gets the movement from the Input using a 2 Vector (ex UI Axis Joystick)</summary>
|
|
public virtual void Move(Vector2 move) => Move(new Vector3(move.x, 0, move.y));
|
|
|
|
/// <summary>Gets the movement from the Input ignoring the Direction Vector, using a 2 Vector (ex UI Axis Joystick)</summary>
|
|
public virtual void MoveWorld(Vector2 move) => MoveWorld(new Vector3(move.x, 0, move.y));
|
|
|
|
/// <summary>Stop the animal from moving, cleaning the Movement Axis</summary>
|
|
public virtual void StopMoving()
|
|
{
|
|
RawInputAxis = Vector3.zero;
|
|
DeltaAngle = 0;
|
|
}
|
|
|
|
/// <summary>Add Inertia to the Movement</summary>d
|
|
public virtual void AddInertia(ref Vector3 Inertia, float speed = 1f)
|
|
{
|
|
AdditivePosition += Inertia;
|
|
Inertia = Vector3.Lerp(Inertia, Vector3.zero, DeltaTime * speed);
|
|
}
|
|
#endregion
|
|
|
|
#region Speeds
|
|
/// <summary>Change the Speed Up</summary>
|
|
public virtual void SpeedUp() => Speed_Add(+1);
|
|
|
|
/// <summary> Changes the Speed Down </summary>
|
|
public virtual void SpeedDown() => Speed_Add(-1);
|
|
|
|
/// <summary> Get a SpeedSet by its name</summary>
|
|
public virtual MSpeedSet SpeedSet_Get(string name) => speedSets.Find(x => x.name == name);
|
|
|
|
public virtual MSpeed Speed_GetModifier(string name, int index)
|
|
{
|
|
var set = SpeedSet_Get(name);
|
|
|
|
if (set != null && index < set.Speeds.Count)
|
|
return set[index - 1];
|
|
|
|
return MSpeed.Default;
|
|
}
|
|
|
|
/// <summary>Set a custom speed created via script and it uses it as the Current Speed Modifier (used on the Fall and Jump State)</summary>
|
|
public virtual void SetCustomSpeed(MSpeed customSpeed, bool keepInertiaSpeed = false)
|
|
{
|
|
CustomSpeed = true;
|
|
CurrentSpeedModifier = customSpeed;
|
|
|
|
//currentSpeedSet = null; //IMPORTANT SET THE CURRENT SPEED SET TO NULL
|
|
|
|
if (keepInertiaSpeed)
|
|
{
|
|
CalculateTargetSpeed(); //Important needs to calculate the Target Speed again
|
|
InertiaPositionSpeed = TargetSpeed; //Set the Target speed to the Fall Speed so there's no Lerping when the speed changes
|
|
}
|
|
}
|
|
|
|
private void Speed_Add(int change) => CurrentSpeedIndex += change;
|
|
|
|
|
|
/// <summary> Set an specific Speed for the active speed modifier </summary>
|
|
public virtual void Speed_CurrentIndex_Set(int speedIndex) => CurrentSpeedIndex = speedIndex;
|
|
|
|
/// <summary> Set an specific Speed for the active State using IntVars </summary>
|
|
public virtual void Speed_CurrentIndex_Set(IntVar speedIndex) => CurrentSpeedIndex = speedIndex;
|
|
|
|
/// <summary>Lock the Speed on the Current Speed Set</summary>
|
|
public virtual void Speed_Lock(bool lockSpeed) => CurrentSpeedSet.LockSpeed = lockSpeed;
|
|
|
|
/// <summary>Lock the Speed on a Speed Set using the SpeedSet Name</summary>
|
|
public virtual void Speed_Lock(string SpeedSetName, bool lockSpeed) => Speed_Lock(SpeedSetName, lockSpeed, 0);
|
|
|
|
/// <summary>Lock the Speed on a Speed Set using the SpeedSet Name, and the Speed LockIndex</summary>
|
|
public virtual void Speed_Lock(string SpeedSetName, bool lockSpeed, int LockIndex)
|
|
{
|
|
var speedSet = SpeedSet_Get(SpeedSetName);
|
|
|
|
if (speedSet != null)
|
|
{
|
|
if (LockIndex != 0)
|
|
speedSet.LockIndex = Mathf.Clamp(LockIndex, 1, speedSet.Speeds.Count);
|
|
|
|
speedSet.LockSpeed = lockSpeed;
|
|
|
|
if (lockSpeed)
|
|
{
|
|
OnSpeedChange.Invoke(speedSet.LockedSpeedModifier);
|
|
EnterSpeedEvent(CurrentSpeedIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void SpeedSet_Lock(string SpeedSetName) => Speed_Lock(SpeedSetName, true, 0);
|
|
public virtual void SpeedSet_Unlock(string SpeedSetName) => Speed_Lock(SpeedSetName, false, 0);
|
|
|
|
|
|
/// <summary>Set a Speed Modifier and its indexx</summary>
|
|
public virtual void SpeedSet_Set_Active(string SpeedSetName, int activeIndex)
|
|
{
|
|
var speedSet = SpeedSet_Get(SpeedSetName);
|
|
|
|
if (speedSet != null)
|
|
{
|
|
speedSet.CurrentIndex = activeIndex;
|
|
|
|
if (CurrentSpeedSet == speedSet)
|
|
{
|
|
CurrentSpeedIndex = activeIndex;
|
|
speedSet.StartVerticalIndex = activeIndex; //Set the Start Vertical Index as the new Speed
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void Speed_Update_Current() => CurrentSpeedIndex = CurrentSpeedIndex;
|
|
|
|
/// <summary> Change the Top Index of a Speed Set</summary>
|
|
public virtual void Speed_SetTopIndex(int topIndex)
|
|
{
|
|
CurrentSpeedSet.TopIndex = topIndex;
|
|
Speed_Update_Current();
|
|
}
|
|
|
|
public virtual void Speed_SetTopIndex(string SpeedSetName, int topIndex)
|
|
{
|
|
var speedSet = SpeedSet_Get(SpeedSetName);
|
|
if (speedSet != null)
|
|
{
|
|
speedSet.TopIndex = topIndex;
|
|
Speed_Update_Current();
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> Change the Speed of a Speed Set</summary>
|
|
public virtual void SpeedSet_Set_Active(string SpeedSetName, string activeSpeed)
|
|
{
|
|
var speedSet = speedSets.Find(x => x.name.ToLower() == SpeedSetName.ToLower());
|
|
|
|
if (speedSet != null)
|
|
{
|
|
var mspeedIndex = speedSet.Speeds.FindIndex(x => x.name.ToLower() == activeSpeed.ToLower());
|
|
|
|
if (mspeedIndex != -1)
|
|
{
|
|
speedSet.CurrentIndex = mspeedIndex + 1;
|
|
|
|
if (CurrentSpeedSet == speedSet)
|
|
{
|
|
CurrentSpeedIndex = mspeedIndex + 1;
|
|
speedSet.StartVerticalIndex = CurrentSpeedIndex; //Set the Start Vertical Index as the new Speed
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("There's no Speed Set called : " + SpeedSetName);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Extras
|
|
|
|
|
|
/// <summary>
|
|
/// Adds a Custom Force to the Animal
|
|
/// </summary>
|
|
/// <param name="Direction">Direction of the Force Applied to the Animal</param>
|
|
/// <param name="Force"> Amount of Force aplied to the Direction</param>
|
|
/// <param name="Aceleration">Smoothens value to apply the force. Higher values faster the force is appled</param>
|
|
/// <param name="ResetGravity">Every time a force is applied, the Gravity Aceleration will be reseted</param>
|
|
/// <param name="ForceAirControl"></param>
|
|
/// <param name="LimitForce"></param>
|
|
public virtual void Force_Add(
|
|
Vector3 Direction, float Force, float Aceleration,
|
|
bool ResetGravity, bool ForceAirControl = true, float LimitForce = 0)
|
|
{
|
|
var CurrentForce = CurrentExternalForce + GravityStoredVelocity; //Calculate the Starting force
|
|
|
|
if (LimitForce > 0 && CurrentForce.magnitude > LimitForce)
|
|
CurrentForce = CurrentForce.normalized * LimitForce; //Add the Bounce
|
|
|
|
CurrentExternalForce = CurrentForce;
|
|
ExternalForce = Direction.normalized * Force;
|
|
ExternalForceAcel = Aceleration;
|
|
|
|
if (ActiveState.ID == StateEnum.Fall) //If we enter to a zone from the Fall state.. Reset the Fall Current Distance
|
|
{
|
|
var fall = ActiveState as Fall;
|
|
fall.FallCurrentDistance = 0;
|
|
}
|
|
|
|
if (ResetGravity) GravityTime = 0;
|
|
|
|
ExternalForceAirControl = ForceAirControl;
|
|
}
|
|
|
|
public virtual void Force_Remove(float Aceleration = 0)
|
|
{
|
|
ExternalForceAcel = Aceleration;
|
|
ExternalForce = Vector3.zero;
|
|
}
|
|
|
|
internal void Force_Reset()
|
|
{
|
|
CurrentExternalForce = Vector3.zero;
|
|
ExternalForce = Vector3.zero;
|
|
ExternalForceAcel = 0;
|
|
}
|
|
|
|
/// <summary> Disable the animal Compoent after a time </summary>
|
|
public virtual void DisableSelf(float time) => this.Delay_Action(time, () => enabled = false);
|
|
|
|
|
|
|
|
/// <summary> If the Animal has touched the ground then Grounded will be set to true </summary>
|
|
public bool CheckIfGrounded()
|
|
{
|
|
AlignRayCasting();
|
|
|
|
if (MainRay && FrontRay && !DeepSlope)
|
|
{
|
|
return Grounded = true; //Activate the Grounded Parameter so the Idle and the Locomotion State can be activated
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void Always_Forward(bool value) => AlwaysForward = value;
|
|
|
|
/// <summary>Activate Attack triggers </summary>
|
|
public virtual void ActivateDamager(int ID)
|
|
{
|
|
if (Sleep) return;
|
|
|
|
if (ID == -1) //Enable all Attack Triggers
|
|
{
|
|
foreach (var dam in Attack_Triggers) dam.DoDamage(true);
|
|
}
|
|
else if (ID == 0) //Disable all Attack Triggers
|
|
{
|
|
foreach (var dam in Attack_Triggers) dam.DoDamage(false);
|
|
}
|
|
else
|
|
{
|
|
var Att_T = Attack_Triggers.FindAll(x => x.Index == ID); //Enable just a trigger with an index
|
|
|
|
if (Att_T != null)
|
|
foreach (var dam in Att_T) dam.DoDamage(true);
|
|
}
|
|
}
|
|
|
|
/// <summary>Store all the Animal Colliders </summary>
|
|
internal void GetAnimalColliders()
|
|
{
|
|
var colls = GetComponentsInChildren<Collider>(true).ToList(); //Get all the Active colliders
|
|
|
|
colliders = new List<Collider>();
|
|
|
|
foreach (var item in colls)
|
|
{
|
|
if (!item.isTrigger/* && item.gameObject.layer == gameObject.layer*/) colliders.Add(item); //Add the Animal Colliders Only
|
|
}
|
|
}
|
|
|
|
/// <summary>Enable/Disable All Colliders on the animal. Avoid the Triggers </summary>
|
|
public virtual void EnableColliders(bool active)
|
|
{
|
|
//Debug.Log("EnableColliders = " + active);
|
|
|
|
foreach (var item in colliders)
|
|
{
|
|
if (item) item.enabled = active;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Disable this Script and MalbersInput Script if it has it.</summary>
|
|
public virtual void DisableAnimal()
|
|
{
|
|
enabled = false;
|
|
MalbersInput MI = GetComponent<MalbersInput>();
|
|
if (MI) MI.enabled = false;
|
|
}
|
|
|
|
public void SetTimeline(bool isonTimeline)
|
|
{
|
|
Sleep = isonTimeline;
|
|
|
|
//Unparent the Rotator since breaks the Cinemachine Logic
|
|
if (Rotator != null) RootBone.parent = isonTimeline ? null : Rotator;
|
|
}
|
|
|
|
|
|
/// <summary>InertiaPositionSpeed = TargetSpeed</summary>
|
|
public void ResetInertiaSpeed() => InertiaPositionSpeed = TargetSpeed;
|
|
|
|
public void UseCameraBasedInput() => UseCameraInput = true;
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
{
|
|
OnDisable();
|
|
}
|
|
#endregion
|
|
}
|
|
} |