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.
1394 lines
53 KiB
C#
1394 lines
53 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using MalbersAnimations.Utilities;
|
|
|
|
namespace MalbersAnimations.Controller
|
|
{
|
|
public partial class MAnimal
|
|
{
|
|
private void OnValidate()
|
|
{
|
|
if (Anim == null) Anim = GetComponentInParent<Animator>(); //Cache the Animator
|
|
if (RB == null) RB = GetComponentInParent<Rigidbody>(); //Cache the Rigid Body
|
|
if (Aimer == null) Aimer = gameObject.FindComponent<Aim>(); //Cache the Aim Component
|
|
}
|
|
|
|
void Awake()
|
|
{
|
|
DefaultCameraInput = UseCameraInput;
|
|
|
|
if (NoParent) transform.parent = null; //IMPORTANT the animal cannot be parent of any game Object (Known Issue)
|
|
|
|
|
|
if (Rotator != null)
|
|
{
|
|
if (RootBone == null)
|
|
{
|
|
if (Anim.avatar.isHuman)
|
|
RootBone = Anim.GetBoneTransform(HumanBodyBones.Hips).parent; //Get the RootBone from
|
|
else
|
|
RootBone = Rotator.GetChild(0); //Find the First Rotator Child THIS CAUSE ISSUES WITH TIMELINE!!!!!!!!!!!!
|
|
|
|
if (RootBone == null)
|
|
Debug.LogWarning("Make sure the Root Bone is Set on the Advanced Tab -> Misc -> RootBone. This is the Character's Avatar root bone");
|
|
}
|
|
|
|
if (RootBone != null && !RootBone.IsGrandchild(Rotator)) //If the rootbone is not grandchild Parent it
|
|
{
|
|
if (Rotator.position != RootBone.position)
|
|
{
|
|
var offset = new GameObject("Offset");
|
|
offset.transform.rotation = transform.rotation;
|
|
offset.transform.position = transform.position;
|
|
|
|
offset.transform.SetParent(Rotator);
|
|
RootBone.SetParent(offset.transform);
|
|
|
|
offset.transform.localScale = Vector3.one;
|
|
//RootBone.localScale = Vector3.one;
|
|
}
|
|
else
|
|
{
|
|
RootBone.parent = Rotator;
|
|
}
|
|
}
|
|
}
|
|
|
|
GetHashIDs();
|
|
|
|
//Initialize all SpeedModifiers
|
|
foreach (var set in speedSets) set.CurrentIndex = set.StartVerticalIndex;
|
|
|
|
RB.useGravity = false;
|
|
RB.constraints = RigidbodyConstraints.FreezeRotation;
|
|
RB.drag = 0;
|
|
|
|
//Initialize The Default Stance
|
|
if (defaultStance == null)
|
|
{
|
|
defaultStance = ScriptableObject.CreateInstance<StanceID>();
|
|
defaultStance.name = "Default";
|
|
defaultStance.ID = 0;
|
|
}
|
|
|
|
if (currentStance == null) currentStance = defaultStance; //Set the current Stance
|
|
|
|
GetAnimalColliders();
|
|
|
|
for (int i = 0; i < states.Count; i++)
|
|
{
|
|
if (states[i] == null) continue; //Skip Null States
|
|
|
|
if (CloneStates)
|
|
{
|
|
//Create a clone from the Original Scriptable Objects! IMPORTANT
|
|
var instance = ScriptableObject.Instantiate(states[i]);
|
|
instance.name = instance.name.Replace("(Clone)", "(C)");
|
|
states[i] = instance;
|
|
}
|
|
|
|
states[i].AwakeState(this);
|
|
}
|
|
|
|
if (!CloneStates)
|
|
Debug.LogWarning
|
|
(
|
|
$"[{name}] has [ClonesStates] disabled. " +
|
|
$"If multiple characters use the same states, it will cause issues." +
|
|
$" Use this only for runtime changes on a single character"
|
|
);
|
|
|
|
|
|
|
|
AwakeAllModes();
|
|
|
|
SetPivots();
|
|
CalculateHeight();
|
|
|
|
currentSpeedSet = defaultSpeedSet;
|
|
AlignUniqueID = UnityEngine.Random.Range(0, 99999);
|
|
|
|
|
|
if (CanStrafe && !Aimer) Debug.LogWarning("This character can strafe but there's no Aim component. Please add the Aim component");
|
|
|
|
//Editor Checking (Make sure the Animator has an Avatar)
|
|
if (Anim.avatar == null)
|
|
Debug.LogWarning("There's no Avatar on the Animator",Anim);
|
|
}
|
|
|
|
private void AwakeAllModes()
|
|
{
|
|
for (int i = 0; i < modes.Count; i++)
|
|
{
|
|
modes[i].Priority = modes.Count - i;
|
|
modes[i].AwakeMode(this);
|
|
}
|
|
}
|
|
|
|
public virtual void ResetController()
|
|
{
|
|
FindCamera();
|
|
|
|
if (Anim)
|
|
{
|
|
Anim.Rebind(); //Reset the Animator Controller
|
|
Anim.speed = AnimatorSpeed; //Set the Global Animator Speed
|
|
Anim.updateMode = AnimatorUpdateMode.AnimatePhysics;
|
|
|
|
|
|
var AllModeBehaviours = Anim.GetBehaviours<ModeBehaviour>();
|
|
|
|
if (AllModeBehaviours != null)
|
|
{
|
|
foreach (var ModeB in AllModeBehaviours) ModeB.InitializeBehaviour(this);
|
|
}
|
|
else
|
|
{
|
|
if (modes != null && modes.Count > 0)
|
|
{
|
|
Debug.LogWarning("Please check your Animator Controller. There's no Mode Behaviors Attached to it. Re-import the Animator again");
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var state in states)
|
|
{
|
|
state.InitializeState();
|
|
state.InputValue = false;
|
|
state.ResetState();
|
|
}
|
|
|
|
if (RB) RB.isKinematic = false; //Make use the Rigibody is not kinematic
|
|
EnableColliders(true); //Make sure to enable all colliders
|
|
|
|
|
|
|
|
CheckIfGrounded(); //Make the first Alignment
|
|
CalculateHeight();
|
|
|
|
|
|
activeState =
|
|
OverrideStartState == null ? //If we are not overriding
|
|
states[states.Count - 1] : //Set the First state as the active state (IMPORTANT TO BE THE FIRST THING TO DO)
|
|
State_Get(OverrideStartState); //Set the OverrideState
|
|
|
|
|
|
ActiveStateID = activeState.ID; //Set the New ActivateID
|
|
activeState.Activate();
|
|
lastState = activeState; //Do not use the Properties....
|
|
|
|
|
|
activeState.IsPending = false; //Force the active state to start without entering the animation.
|
|
ActiveState.CanExit = true; //Force that it can exit... so another can activate it
|
|
activeState.General.Modify(this); //Force the active state to Modify all the Animal Settings
|
|
|
|
JustActivateState = false; //Force this to false
|
|
|
|
State_SetFloat(0);
|
|
|
|
UsingMoveWithDirection = (UseCameraInput); //IMPORTANT
|
|
|
|
Mode_Stop();
|
|
|
|
//Set Start with Mode
|
|
if (StartWithMode.Value != 0)
|
|
{
|
|
if (StartWithMode.Value / 1000 == 0)
|
|
{
|
|
Mode_Activate(StartWithMode.Value);
|
|
}
|
|
else
|
|
{
|
|
var mode = StartWithMode.Value / 1000;
|
|
var modeAb = StartWithMode.Value % 1000;
|
|
if (modeAb == 0) modeAb = -99;
|
|
Mode_Activate(mode, modeAb);
|
|
}
|
|
}
|
|
|
|
|
|
LastPos = transform.position; //Store Last Animal Position
|
|
|
|
ForwardMultiplier = 1f; //Initialize the Forward Multiplier
|
|
GravityMultiplier = 1f;
|
|
|
|
MovementAxis =
|
|
MovementAxisRaw =
|
|
AdditivePosition =
|
|
InertiaPositionSpeed =
|
|
MovementAxisSmoothed = Vector3.zero; //Reset Vector Values
|
|
|
|
LockMovementAxis = (new Vector3(LockHorizontalMovement ? 0 : 1, LockUpDownMovement ? 0 : 1, LockForwardMovement ? 0 : 1));
|
|
|
|
UseRawInput = true; //Set the Raw Input as default.
|
|
UseAdditiveRot = true;
|
|
UseAdditivePos = true;
|
|
Grounded = true;
|
|
Randomizer = true;
|
|
AlwaysForward = AlwaysForward; // Execute the code inside Always Forward .... Why??? Don't know ..something to do with the Input stuff
|
|
Strafe = Strafe; // Execute the code inside Strafe
|
|
Stance = currentStance;
|
|
GlobalOrientToGround = GlobalOrientToGround; // Execute the code inside Global Orient
|
|
HasReachedMaxSlope = false;
|
|
SpeedMultiplier = 1;
|
|
CurrentCycle = Random.Range(0, 99999);
|
|
ResetGravityValues();
|
|
|
|
UpdateDamagerSet();
|
|
|
|
var TypeHash = TryOptionalParameter(m_Type);
|
|
SetOptionalAnimParameter(TypeHash, animalType); //This is only done once!
|
|
|
|
|
|
//Reset FreeMovement.
|
|
if (Rotator) Rotator.localRotation = Quaternion.identity;
|
|
Bank = 0;
|
|
PitchAngle = 0;
|
|
PitchDirection = Vector3.forward;
|
|
}
|
|
|
|
public virtual void FindCamera()
|
|
{
|
|
if (MainCamera == null) //Find the Camera
|
|
{
|
|
m_MainCamera.UseConstant = true;
|
|
|
|
var mainCam = MTools.FindMainCamera();
|
|
|
|
if (mainCam) m_MainCamera.Value = mainCam.transform;
|
|
//else
|
|
//{}
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Set Pivots")]
|
|
public void SetPivots()
|
|
{
|
|
Pivot_Hip = pivots.Find(item => item.name.ToUpper() == "HIP");
|
|
Pivot_Chest = pivots.Find(item => item.name.ToUpper() == "CHEST");
|
|
|
|
Has_Pivot_Hip = Pivot_Hip != null;
|
|
Has_Pivot_Chest = Pivot_Chest != null;
|
|
Starting_PivotChest = Has_Pivot_Chest;
|
|
|
|
CalculateHeight();
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying) UnityEditor.EditorUtility.SetDirty(this);
|
|
#endif
|
|
}
|
|
|
|
|
|
public void OnEnable()
|
|
{
|
|
if (Animals == null) Animals = new List<MAnimal>();
|
|
Animals.Add(this); //Save the the Animal on the current List
|
|
|
|
ResetInputSource(); //Connect the Inputs
|
|
|
|
if (isPlayer) SetMainPlayer();
|
|
|
|
SetBoolParameter += SetAnimParameter;
|
|
SetIntParameter += SetAnimParameter;
|
|
SetFloatParameter += SetAnimParameter;
|
|
SetTriggerParameter += SetAnimParameter;
|
|
|
|
if (!alwaysForward.UseConstant && alwaysForward.Variable != null)
|
|
alwaysForward.Variable.OnValueChanged += Always_Forward;
|
|
|
|
ResetController();
|
|
Sleep = false;
|
|
}
|
|
|
|
public void OnDisable()
|
|
{
|
|
if (Animals != null) Animals.Remove(this); //Remove all this animal from the Overall AnimalList
|
|
|
|
UpdateInputSource(false); //Disconnect the inputs
|
|
|
|
DisableMainPlayer();
|
|
|
|
MTools.ResetFloatParameters(Anim); //Reset all Anim Floats!!
|
|
RB.velocity = Vector3.zero;
|
|
|
|
SetBoolParameter -= SetAnimParameter;
|
|
SetIntParameter -= SetAnimParameter;
|
|
SetFloatParameter -= SetAnimParameter;
|
|
SetTriggerParameter -= SetAnimParameter;
|
|
|
|
|
|
if (!alwaysForward.UseConstant && alwaysForward.Variable != null)
|
|
alwaysForward.Variable.OnValueChanged -= Always_Forward;
|
|
|
|
if (states != null)
|
|
{
|
|
foreach (var st in states)
|
|
if (st != null) st.ExitState();
|
|
}
|
|
|
|
|
|
if (ActiveMode != null) ActiveMode.PlayingMode = false;
|
|
Mode_Stop();
|
|
}
|
|
|
|
|
|
public void CalculateHeight()
|
|
{
|
|
if (Has_Pivot_Hip)
|
|
{
|
|
if (height == 1) height = Pivot_Hip.position.y;
|
|
Center = Pivot_Hip.position; //Set the Center to be the Pivot Hip Position
|
|
}
|
|
else if (Has_Pivot_Chest)
|
|
{
|
|
if (height == 1) height = Pivot_Chest.position.y;
|
|
Center = Pivot_Chest.position;
|
|
}
|
|
|
|
if (Has_Pivot_Chest && Has_Pivot_Hip)
|
|
{
|
|
Center = (Pivot_Chest.position + Pivot_Hip.position) / 2;
|
|
}
|
|
}
|
|
|
|
/// <summary>Update all the Attack Triggers Inside the Animal... In case there are more or less triggers</summary>
|
|
public void UpdateDamagerSet()
|
|
{
|
|
Attack_Triggers = GetComponentsInChildren<IMDamager>(true).ToList(); //Save all Attack Triggers.
|
|
foreach (var at in Attack_Triggers)
|
|
{
|
|
at.Owner = (gameObject); //Tell to avery Damager that this Animal is the Owner
|
|
at.Active = false;
|
|
}
|
|
}
|
|
|
|
public void AttackTriggers_Update() => UpdateDamagerSet();
|
|
|
|
#region Animator Stuff
|
|
protected virtual void GetHashIDs()
|
|
{
|
|
if (Anim == null) return;
|
|
|
|
|
|
//Store all the Animator Parameter in a Dictionary
|
|
//animatorParams = new Hashtable();
|
|
animatorHashParams = new List<int>();
|
|
|
|
foreach (var parameter in Anim.parameters)
|
|
{
|
|
animatorHashParams.Add(parameter.nameHash);
|
|
}
|
|
|
|
#region Main Animator Parameters
|
|
//Movement
|
|
hash_Vertical = Animator.StringToHash(m_Vertical);
|
|
hash_Horizontal = Animator.StringToHash(m_Horizontal);
|
|
hash_SpeedMultiplier = Animator.StringToHash(m_SpeedMultiplier);
|
|
|
|
hash_Movement = Animator.StringToHash(m_Movement);
|
|
hash_Grounded = Animator.StringToHash(m_Grounded);
|
|
|
|
//States
|
|
hash_State = Animator.StringToHash(m_State);
|
|
hash_StateEnterStatus = Animator.StringToHash(m_StateStatus);
|
|
|
|
|
|
hash_LastState = Animator.StringToHash(m_LastState);
|
|
hash_StateFloat = Animator.StringToHash(m_StateFloat);
|
|
|
|
//Modes
|
|
hash_Mode = Animator.StringToHash(m_Mode);
|
|
|
|
hash_ModeStatus = Animator.StringToHash(m_ModeStatus);
|
|
#endregion
|
|
|
|
#region Optional Parameters
|
|
|
|
//Movement
|
|
hash_StateExitStatus = TryOptionalParameter(m_StateExitStatus);
|
|
//hash_StateEnterStatus = TryOptionalParameter(m_StateStatus);
|
|
hash_SpeedMultiplier = TryOptionalParameter(m_SpeedMultiplier);
|
|
|
|
hash_UpDown = TryOptionalParameter(m_UpDown);
|
|
hash_DeltaUpDown = TryOptionalParameter(m_DeltaUpDown);
|
|
|
|
hash_Slope = TryOptionalParameter(m_Slope);
|
|
|
|
|
|
hash_DeltaAngle = TryOptionalParameter(m_DeltaAngle);
|
|
hash_Sprint = TryOptionalParameter(m_Sprint);
|
|
|
|
//States
|
|
hash_StateTime = TryOptionalParameter(m_StateTime);
|
|
|
|
|
|
hash_Strafe = TryOptionalParameter(m_Strafe);
|
|
hash_StrafeAngle = TryOptionalParameter(m_strafeAngle);
|
|
|
|
//Stance
|
|
hash_Stance = TryOptionalParameter(m_Stance);
|
|
|
|
hash_LastStance = TryOptionalParameter(m_LastStance);
|
|
|
|
//Misc
|
|
hash_Random = TryOptionalParameter(m_Random);
|
|
hash_ModePower = TryOptionalParameter(m_ModePower);
|
|
|
|
//Triggers
|
|
hash_ModeOn = TryOptionalParameter(m_ModeOn);
|
|
hash_StateOn = TryOptionalParameter(m_StateOn);
|
|
// hash_StanceOn = TryOptionalParameter(m_StanceOn);
|
|
#endregion
|
|
}
|
|
|
|
|
|
//Send 0 if the Animator does not contain
|
|
private int TryOptionalParameter(string param)
|
|
{
|
|
var AnimHash = Animator.StringToHash(param);
|
|
|
|
if (!animatorHashParams.Contains(AnimHash))
|
|
return 0;
|
|
return AnimHash;
|
|
}
|
|
|
|
protected virtual void CacheAnimatorState()
|
|
{
|
|
m_PreviousCurrentState = m_CurrentState;
|
|
m_PreviousNextState = m_NextState;
|
|
m_PreviousIsAnimatorTransitioning = m_IsAnimatorTransitioning;
|
|
|
|
m_CurrentState = Anim.GetCurrentAnimatorStateInfo(0);
|
|
m_NextState = Anim.GetNextAnimatorStateInfo(0);
|
|
m_IsAnimatorTransitioning = Anim.IsInTransition(0);
|
|
|
|
if (m_IsAnimatorTransitioning)
|
|
{
|
|
if (m_NextState.fullPathHash != 0)
|
|
{
|
|
AnimStateTag = m_NextState.tagHash;
|
|
AnimState = m_NextState;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_CurrentState.fullPathHash != AnimState.fullPathHash)
|
|
{
|
|
AnimStateTag = m_CurrentState.tagHash;
|
|
}
|
|
|
|
AnimState = m_CurrentState;
|
|
}
|
|
|
|
var lastStateTime = StateTime;
|
|
// = m_CurrentState.normalizedTime;
|
|
StateTime = Mathf.Repeat(AnimState.normalizedTime, 1);
|
|
|
|
// Debug.Log("StateTime = " + StateTime);
|
|
|
|
if (lastStateTime > StateTime) StateCycle?.Invoke(ActiveStateID); //Check if the Animation Started again.
|
|
}
|
|
|
|
/// <summary>Link all Parameters to the animator</summary>
|
|
protected virtual void UpdateAnimatorParameters()
|
|
{
|
|
SetFloatParameter(hash_Vertical, VerticalSmooth);
|
|
SetFloatParameter(hash_Horizontal, HorizontalSmooth);
|
|
|
|
SetOptionalAnimParameter(hash_UpDown, UpDownSmooth);
|
|
SetOptionalAnimParameter(hash_DeltaUpDown, DeltaUpDown);
|
|
|
|
|
|
SetOptionalAnimParameter(hash_DeltaAngle, DeltaAngle);
|
|
SetOptionalAnimParameter(hash_Slope, SlopeNormalized);
|
|
SetOptionalAnimParameter(hash_SpeedMultiplier, SpeedMultiplier);
|
|
SetOptionalAnimParameter(hash_StateTime, StateTime);
|
|
}
|
|
#endregion
|
|
|
|
#region Inputs
|
|
internal void InputAxisUpdate()
|
|
{
|
|
if (UseRawInput)
|
|
{
|
|
if (AlwaysForward)
|
|
RawInputAxis.z = 1;
|
|
|
|
var inputAxis = RawInputAxis;
|
|
|
|
if (LockMovement || Sleep)
|
|
{
|
|
MovementAxis = Vector3.zero;
|
|
return;
|
|
}
|
|
|
|
if (MainCamera && UsingMoveWithDirection && !Strafe)
|
|
{
|
|
var Cam_Forward = Vector3.ProjectOnPlane(MainCamera.forward, UpVector).normalized; //Normalize the Camera Forward Depending the Up Vector IMPORTANT!
|
|
var Cam_Right = Vector3.ProjectOnPlane(MainCamera.right, UpVector).normalized;
|
|
|
|
Vector3 UpInput;
|
|
|
|
if (!FreeMovement)
|
|
{
|
|
UpInput = Vector3.zero; //Reset the UP Input in case is on the Ground
|
|
}
|
|
else
|
|
{
|
|
if (UseCameraUp)
|
|
{
|
|
UpInput = (inputAxis.y * MainCamera.up * LockMovementAxis.y);
|
|
UpInput += Vector3.Project(MainCamera.forward, UpVector) * inputAxis.z;
|
|
}
|
|
else
|
|
{
|
|
UpInput = (inputAxis.y * UpVector * LockMovementAxis.y);
|
|
}
|
|
}
|
|
|
|
var m_Move = (inputAxis.z * Cam_Forward) + (inputAxis.x * Cam_Right) + UpInput;
|
|
|
|
MoveFromDirection(m_Move);
|
|
}
|
|
else
|
|
{
|
|
MoveWorld(inputAxis);
|
|
}
|
|
}
|
|
else //Means that is Using a Direction Instead Update every frame
|
|
{
|
|
MoveFromDirection(RawInputAxis);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>Get the Raw Input Axis from a source</summary>
|
|
public virtual void SetInputAxis(Vector3 inputAxis)
|
|
{
|
|
UseRawInput = true;
|
|
RawInputAxis = inputAxis; // Store the last current use of the Input
|
|
if (UsingUpDownExternal)
|
|
RawInputAxis.y = UpDownAdditive; //Add the UPDown Additive from the Mobile.
|
|
}
|
|
|
|
|
|
|
|
public virtual void SetInputAxis(Vector2 inputAxis) => SetInputAxis(new Vector3(inputAxis.x, 0, inputAxis.y));
|
|
|
|
public virtual void SetInputAxisXY(Vector2 inputAxis) => SetInputAxis(new Vector3(inputAxis.x, inputAxis.y, 0));
|
|
|
|
public virtual void SetInputAxisYZ(Vector2 inputAxis) => SetInputAxis(new Vector3(0, inputAxis.x, inputAxis.y));
|
|
|
|
private float UpDownAdditive;
|
|
private bool UsingUpDownExternal;
|
|
|
|
/// <summary>Use this for Custom UpDown Movement</summary>
|
|
public virtual void SetUpDownAxis(float upDown)
|
|
{
|
|
UpDownAdditive = upDown;
|
|
UsingUpDownExternal = true;
|
|
SetInputAxis(RawInputAxis); //Call the Raw IMPORTANT
|
|
}
|
|
|
|
/// <summary>Gets the movement from the World Coordinates</summary>
|
|
/// <param name="move">World Direction Vector</param>
|
|
protected virtual void MoveWorld(Vector3 move)
|
|
{
|
|
UsingMoveWithDirection = false;
|
|
|
|
if (!UseSmoothVertical && move.z > 0) move.z = 1; //It will remove slowing Stick push when rotating and going Forward
|
|
Move_Direction = transform.TransformDirection(move).normalized; //Convert from world to relative IMPORTANT
|
|
|
|
SetMovementAxis(move);
|
|
}
|
|
|
|
private void SetMovementAxis(Vector3 move)
|
|
{
|
|
MovementAxisRaw = move;
|
|
MovementAxisRaw.z *= ForwardMultiplier;
|
|
|
|
MovementAxis = MovementAxisRaw;
|
|
MovementDetected = MovementAxisRaw != Vector3.zero;
|
|
|
|
MovementAxis.Scale(LockMovementAxis);
|
|
MovementAxis.Scale(ActiveState.MovementAxisMult);
|
|
}
|
|
|
|
/// <summary>Gets the movement values from a Direction</summary>
|
|
/// <param name="move">Direction Vector</param>
|
|
public virtual void MoveFromDirection(Vector3 move)
|
|
{
|
|
if (LockMovement)
|
|
{
|
|
MovementAxis = Vector3.zero;
|
|
return;
|
|
}
|
|
|
|
UsingMoveWithDirection = true;
|
|
|
|
if (move.magnitude > 1f) move.Normalize();
|
|
|
|
var UpDown = FreeMovement ? move.y : 0; //Ignore UP Down Axis when the Animal is not on Free movement
|
|
|
|
|
|
if (!FreeMovement)
|
|
move = Quaternion.FromToRotation(UpVector, SurfaceNormal) * move; //Rotate with the ground Surface Normal. CORRECT!
|
|
|
|
Move_Direction = move;
|
|
move = transform.InverseTransformDirection(move); //Convert the move Input from world to Local
|
|
|
|
// Debug.DrawRay(transform.position, move * 5, Color.yellow);
|
|
|
|
float turnAmount = Mathf.Atan2(move.x, move.z); //Convert it to Radians
|
|
float forwardAmount = move.z < 0 ? 0 : move.z;
|
|
|
|
// Find the difference between the current rotation of the player and the desired rotation of the player in radians.
|
|
float angleCurrent = Mathf.Atan2(Forward.x, Forward.z) * Mathf.Rad2Deg;
|
|
|
|
float targetAngle = Mathf.Atan2(Move_Direction.x, Move_Direction.z) * Mathf.Rad2Deg;
|
|
var Delta = Mathf.DeltaAngle(angleCurrent, targetAngle);
|
|
|
|
DeltaAngle = MovementDetected ? Delta : 0;
|
|
|
|
if (Mathf.Approximately(Delta, float.NaN)) DeltaAngle = 0f; //Remove the NAN Bug
|
|
|
|
if (Mathf.Abs(Vector3.Dot(Move_Direction, UpVector)) == 1)//Remove turn Mount when its goinf UP/Down
|
|
{
|
|
turnAmount = 0;
|
|
DeltaAngle = 0f;
|
|
}
|
|
|
|
|
|
//It will remove slowing Stick push when rotating and going Forward
|
|
if (!UseSmoothVertical)
|
|
{
|
|
forwardAmount = Mathf.Abs(move.z);
|
|
forwardAmount = forwardAmount > 0 ? 1 : forwardAmount;
|
|
}
|
|
else
|
|
{
|
|
if (Mathf.Abs(DeltaAngle) < TurnLimit)
|
|
forwardAmount = Mathf.Clamp01(Move_Direction.magnitude);
|
|
}
|
|
|
|
|
|
// if (Rotate_at_Direction) forwardAmount = 0;
|
|
|
|
|
|
SetMovementAxis(new Vector3(turnAmount, UpDown, forwardAmount));
|
|
}
|
|
|
|
/// <summary>Gets the movement from a Direction but it wont fo forward it will only rotate in place</summary>
|
|
public virtual void RotateAtDirection(Vector3 direction)
|
|
{
|
|
if (IsPlayingMode && !ActiveMode.AllowRotation) return;
|
|
|
|
RawInputAxis = direction; // Store the last current use of the Input
|
|
UseRawInput = false;
|
|
Rotate_at_Direction = true;
|
|
}
|
|
#endregion
|
|
|
|
#region Additional Speeds (Movement, Turn)
|
|
|
|
public void CalculateTargetSpeed()
|
|
{
|
|
//var lerp = CurrentSpeedModifier.lerpPosition * DeltaTime;
|
|
|
|
if ((!UseAdditivePos) || //Do nothing when UseAdditivePos is False
|
|
(IsPlayingMode && !ActiveMode.AllowMovement)) //Do nothing when the Mode Locks the Movement
|
|
{
|
|
//TargetSpeed = Vector3.Lerp(TargetSpeed, Vector3.zero, lerp);
|
|
TargetSpeed = Vector3.zero;
|
|
return;
|
|
}
|
|
|
|
Vector3 TargetDir = ActiveState.Speed_Direction();
|
|
|
|
float Speed_Modifier = Strafe ? CurrentSpeedModifier.strafeSpeed.Value : CurrentSpeedModifier.position.Value;
|
|
|
|
if (Strafe)
|
|
{
|
|
TargetDir = (Forward * VerticalSmooth) + (Right * HorizontalSmooth);
|
|
|
|
if (FreeMovement)
|
|
TargetDir += (Up * UpDownSmooth);
|
|
|
|
}
|
|
else
|
|
{
|
|
if ((VerticalSmooth < 0) && CurrentSpeedSet != null)//Decrease when going backwards and NOT Strafing
|
|
{
|
|
TargetDir *= -CurrentSpeedSet.BackSpeedMult.Value;
|
|
Speed_Modifier = CurrentSpeedSet[0].position;
|
|
}
|
|
if (FreeMovement)
|
|
{
|
|
float SmoothZYInput = Mathf.Clamp01(Mathf.Max(Mathf.Abs(UpDownSmooth), Mathf.Abs(VerticalSmooth))); // Get the Average Multiplier of both Z and Y Inputs
|
|
TargetDir *= SmoothZYInput;
|
|
}
|
|
else
|
|
{
|
|
TargetDir *= VerticalSmooth; //Use Only the Vertical Smooth while grounded
|
|
}
|
|
|
|
}
|
|
|
|
if (TargetDir.magnitude > 1) TargetDir.Normalize();
|
|
TargetSpeed = TargetDir * Speed_Modifier * DeltaTime * ScaleFactor; //Calculate these Once per Cycle Extremely important
|
|
|
|
//TargetSpeed = Vector3.Lerp(TargetSpeed, TargetDir * Speed_Modifier * DeltaTime * ScaleFactor, lerp); //Calculate these Once per Cycle Extremely important
|
|
|
|
HorizontalVelocity = Vector3.ProjectOnPlane(Inertia, UpVector);
|
|
HorizontalSpeed = HorizontalVelocity.magnitude;
|
|
}
|
|
|
|
private void MoveRotator()
|
|
{
|
|
if (!FreeMovement && Rotator)
|
|
{
|
|
if (PitchAngle != 0 || Bank != 0)
|
|
{
|
|
float limit = 0.005f;
|
|
var lerp = DeltaTime * (CurrentSpeedSet.PitchLerpOff);
|
|
|
|
Rotator.localRotation = Quaternion.Slerp(Rotator.localRotation, Quaternion.identity, lerp);
|
|
|
|
PitchAngle = Mathf.Lerp(PitchAngle, 0, lerp); //Lerp to zero the Pitch Angle when goind Down
|
|
Bank = Mathf.Lerp(Bank, 0, lerp);
|
|
|
|
if (Mathf.Abs(PitchAngle) < limit && Mathf.Abs(Bank) < limit)
|
|
{
|
|
Bank = PitchAngle = 0;
|
|
Rotator.localRotation = Quaternion.identity;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CalculatePitchDirectionVector();
|
|
}
|
|
}
|
|
|
|
public virtual void FreeMovementRotator(float Ylimit, float bank)
|
|
{
|
|
CalculatePitch(Ylimit);
|
|
CalculateBank(bank);
|
|
CalculateRotator();
|
|
}
|
|
|
|
internal virtual void CalculateRotator()
|
|
{
|
|
Rotator.localEulerAngles = new Vector3(PitchAngle, 0, Bank); //Angle for the Rotator
|
|
}
|
|
internal virtual void CalculateBank(float bank) => Bank = Mathf.Lerp(Bank, -bank * Mathf.Clamp(HorizontalSmooth, -1, 1), DeltaTime * CurrentSpeedSet.BankLerp);
|
|
internal virtual void CalculatePitch(float Ylimit)
|
|
{
|
|
float NewAngle = 0;
|
|
|
|
if (PitchDirection.sqrMagnitude > 0.0001) //Rotation PITCH
|
|
{
|
|
NewAngle = 90 - Vector3.Angle(UpVector, PitchDirection);
|
|
NewAngle = Mathf.Clamp(-NewAngle, -Ylimit, Ylimit);
|
|
}
|
|
|
|
var deltatime = DeltaTime * CurrentSpeedSet.PitchLerpOn;
|
|
|
|
PitchAngle = Mathf.Lerp(PitchAngle, NewAngle, deltatime);
|
|
DeltaUpDown = Mathf.Lerp(DeltaUpDown, -Mathf.DeltaAngle(PitchAngle, NewAngle), deltatime * 2);
|
|
|
|
if (Mathf.Abs(DeltaUpDown) < 0.01f) DeltaUpDown = 0;
|
|
}
|
|
|
|
|
|
/// <summary>Calculates the Pitch direction to Appy to the Rotator Transform</summary>
|
|
internal virtual void CalculatePitchDirectionVector()
|
|
{
|
|
var dir = Move_Direction != Vector3.zero ? Move_Direction : Forward;
|
|
PitchDirection = Vector3.Lerp(PitchDirection, dir, DeltaTime * CurrentSpeedSet.PitchLerpOn * 2);
|
|
}
|
|
|
|
/// <summary> Add more Speed to the current Move animations</summary>
|
|
protected virtual void AdditionalSpeed(float time)
|
|
{
|
|
// if (IsPlayingMode && !ActiveMode.AllowMovement) return; //Do nothing because the mode does not allow Additional Speed
|
|
|
|
var LerpPos = (Strafe) ? CurrentSpeedModifier.lerpStrafe : CurrentSpeedModifier.lerpPosition;
|
|
|
|
InertiaPositionSpeed = (LerpPos > 0) ?
|
|
Vector3.Lerp(InertiaPositionSpeed,UseAdditivePos ? TargetSpeed : Vector3.zero, time * LerpPos) : TargetSpeed;
|
|
|
|
AdditivePosition += InertiaPositionSpeed;
|
|
}
|
|
|
|
|
|
/// <summary>Add more Rotations to the current Turn Animations </summary>
|
|
protected virtual void AdditionalTurn(float time)
|
|
{
|
|
float SpeedRotation = CurrentSpeedModifier.rotation;
|
|
|
|
if (VerticalSmooth < 0.01 && !CustomSpeed && CurrentSpeedSet != null)
|
|
{
|
|
SpeedRotation = CurrentSpeedSet[0].rotation;
|
|
}
|
|
|
|
if (SpeedRotation < 0) return; //Do nothing if the rotation is lower than 0
|
|
|
|
if (MovementDetected)
|
|
{
|
|
float ModeRotation = (IsPlayingMode && !ActiveMode.AllowRotation) ? 0 : 1;//If the mode does not allow rotation set the multiplier to zero
|
|
|
|
if (UsingMoveWithDirection)
|
|
{
|
|
var TargetLocalRot = Quaternion.Euler(0, DeltaAngle, 0);
|
|
Quaternion targetRotation = Quaternion.Slerp(Quaternion.identity, TargetLocalRot, (SpeedRotation + 1) / 4 * ((TurnMultiplier + 1) * time * ModeRotation));
|
|
AdditiveRotation *= targetRotation;
|
|
}
|
|
else
|
|
{
|
|
float Turn = SpeedRotation * 10; //Add Extra Multiplier
|
|
float TurnInput = Mathf.Clamp(HorizontalSmooth, -1, 1) * (MovementAxis.z >= 0 ? 1 : -1); //Add +Rotation when going Forward and -Rotation when going backwards
|
|
AdditiveRotation *= Quaternion.Euler(0, Turn * TurnInput * time * ModeRotation, 0);
|
|
var TargetGlobal = Quaternion.Euler(0, TurnInput * (TurnMultiplier + 1), 0);
|
|
var AdditiveGlobal = Quaternion.Slerp(Quaternion.identity, TargetGlobal, time * (SpeedRotation + 1) * ModeRotation);
|
|
AdditiveRotation *= AdditiveGlobal;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> Movement Trot Walk Run (Velocity changes)</summary>
|
|
internal void MovementSystem(float DeltaTime)
|
|
{
|
|
float maxspeedV = CurrentSpeedModifier.Vertical;
|
|
float maxspeedH = 1;
|
|
|
|
var LerpUpDown = DeltaTime * CurrentSpeedSet.PitchLerpOn;
|
|
var LerpVertical = DeltaTime * CurrentSpeedModifier.lerpPosAnim;
|
|
var LerpTurn = DeltaTime * CurrentSpeedModifier.lerpRotAnim;
|
|
var LerpAnimator = DeltaTime * CurrentSpeedModifier.lerpAnimator;
|
|
|
|
if (Strafe)
|
|
{
|
|
maxspeedH = maxspeedV; //if the animal is strafing
|
|
// LerpVertical = LerpTurn = LerpUpDown = DeltaTime * CurrentSpeedModifier.lerpStrafe; //CHANGED: Still use Vertical for the Animator
|
|
}
|
|
|
|
if (IsPlayingMode && !ActiveMode.AllowMovement) //Active mode and Isplaying Mode is failing!!**************
|
|
MovementAxis = Vector3.zero;
|
|
|
|
var Horiz = Mathf.Lerp(HorizontalSmooth, MovementAxis.x * maxspeedH, LerpTurn);
|
|
|
|
float v = MovementAxis.z;
|
|
|
|
|
|
if (Rotate_at_Direction)
|
|
{
|
|
float r = 0;
|
|
v = 0; //Remove the Forward since its
|
|
Horiz = Mathf.SmoothDamp(HorizontalSmooth, MovementAxis.x * 4, ref r, inPlaceDamp * DeltaTime); //Using properly the smooth down
|
|
}
|
|
|
|
VerticalSmooth = LerpVertical > 0 ?
|
|
Mathf.Lerp(VerticalSmooth, v * maxspeedV, LerpVertical) :
|
|
MovementAxis.z * maxspeedV; //smoothly transitions bettwen Speeds
|
|
|
|
|
|
HorizontalSmooth = LerpTurn > 0 ? Horiz : MovementAxis.x * maxspeedH; //smoothly transitions bettwen Directions
|
|
|
|
UpDownSmooth = LerpVertical > 0 ?
|
|
Mathf.Lerp(UpDownSmooth, MovementAxis.y, LerpUpDown) :
|
|
MovementAxis.y; //smoothly transitions bettwen Directions
|
|
|
|
|
|
SpeedMultiplier = (LerpAnimator > 0) ?
|
|
Mathf.Lerp(SpeedMultiplier, CurrentSpeedModifier.animator.Value, LerpAnimator) :
|
|
CurrentSpeedModifier.animator.Value; //Changue the velocity of the animator
|
|
|
|
var zero = 0.005f;
|
|
|
|
if (Mathf.Abs(VerticalSmooth) < zero) VerticalSmooth = 0;
|
|
if (Mathf.Abs(HorizontalSmooth) < zero) HorizontalSmooth = 0;
|
|
if (Mathf.Abs(UpDownSmooth) < zero) UpDownSmooth = 0;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Platorm movement
|
|
public void SetPlatform(Transform newPlatform)
|
|
{
|
|
platform = newPlatform;
|
|
platform_LastPos = platform.position;
|
|
platform_Rot = platform.rotation;
|
|
}
|
|
|
|
public void PlatformMovement()
|
|
{
|
|
if (platform == null) return;
|
|
if (platform.gameObject.isStatic) return; //means it cannot move
|
|
|
|
var DeltaPlatformPos = platform.position - platform_LastPos;
|
|
//AdditivePosition.y += DeltaPlatformPos.y;
|
|
//DeltaPlatformPos.y = 0; //the Y is handled by the Fix Position
|
|
|
|
transform.position += DeltaPlatformPos; //Set it Directly to the Transform.. Additive Position can be reset any time..
|
|
|
|
|
|
Quaternion Inverse_Rot = Quaternion.Inverse(platform_Rot);
|
|
Quaternion Delta = Inverse_Rot * platform.rotation;
|
|
|
|
if (Delta != Quaternion.identity) // no rotation founded.. Skip the code below
|
|
{
|
|
var pos = transform.DeltaPositionFromRotate(platform, Delta);
|
|
|
|
// AdditivePosition += pos;
|
|
transform.position += pos; //Set it Directly to the Transform.. Additive Position can be reset any time..
|
|
}
|
|
|
|
//AdditiveRotation *= Delta;
|
|
transform.rotation *= Delta; //Set it Directly to the Transform.. Additive Position can be reset any time..
|
|
|
|
platform_LastPos = platform.position;
|
|
platform_Rot = platform.rotation;
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region Terrain Alignment
|
|
/// <summary>Raycasting stuff to align and calculate the ground from the animal ****IMPORTANT***</summary>
|
|
internal virtual void AlignRayCasting()
|
|
{
|
|
MainRay = FrontRay = false;
|
|
hit_Chest = new RaycastHit() { normal = Vector3.zero }; //Clean the Raycasts every time
|
|
hit_Hip = new RaycastHit(); //Clean the Raycasts every time
|
|
hit_Chest.distance = hit_Hip.distance = Height; //Reset the Distances to the Heigth of the animal
|
|
|
|
//var Direction = Gravity;
|
|
var Direction = -transform.up;
|
|
|
|
if (Physics.Raycast(Main_Pivot_Point, Direction, out hit_Chest, Pivot_Multiplier, GroundLayer, QueryTriggerInteraction.Ignore))
|
|
{
|
|
FrontRay = true;
|
|
|
|
if (debugGizmos)
|
|
{
|
|
Debug.DrawRay(hit_Chest.point, hit_Chest.normal * ScaleFactor * 0.2f, Color.green);
|
|
MTools.DrawWireSphere(Main_Pivot_Point + Direction * (hit_Chest.distance - RayCastRadius), Color.green, RayCastRadius * ScaleFactor);
|
|
}
|
|
|
|
//Calculate current Ground Angle
|
|
MainPivotSlope = Vector3.SignedAngle(hit_Chest.normal, UpVector, Right);
|
|
|
|
|
|
//Means that the Slope is higher thanthe Max slope so stop the animal from Going forward AND ONLY ON LOCOMOTION
|
|
if (MainPivotSlope > maxAngleSlope)
|
|
{
|
|
if (MovementAxisRaw.z > 0 && !hit_Chest.transform.gameObject.CompareTag(DebrisTag))
|
|
{
|
|
AdditivePosition = Vector3.ProjectOnPlane(AdditivePosition, Forward); //Remove Forward Movement
|
|
MovementAxis.z = 0;
|
|
|
|
if (!HasReachedMaxSlope)
|
|
{
|
|
HasReachedMaxSlope = true;
|
|
OnMaxSlopeReached.Invoke();
|
|
}
|
|
}
|
|
}
|
|
else if (MainPivotSlope < -maxAngleSlope) //Meaning it has touched the ground but the angle too deep
|
|
{
|
|
FrontRay = false;
|
|
HasReachedMaxSlope = false;
|
|
}
|
|
else
|
|
{
|
|
HasReachedMaxSlope = false;
|
|
|
|
if (platform != hit_Chest.transform) //Platforming logic
|
|
SetPlatform(hit_Chest.transform);
|
|
|
|
//Physic Logic (Push RigidBodys Down with the Weight)
|
|
hit_Chest.collider.attachedRigidbody?.AddForceAtPosition(Gravity * (RB.mass / 2), hit_Chest.point, ForceMode.Force);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
platform = null;
|
|
}
|
|
|
|
if (Has_Pivot_Hip && Has_Pivot_Chest) //Ray From the Hip to the ground
|
|
{
|
|
var hipPoint = Pivot_Hip.World(transform) + DeltaVelocity;
|
|
|
|
if (Physics.Raycast(hipPoint, Direction, out hit_Hip, ScaleFactor * Pivot_Hip.multiplier, GroundLayer, QueryTriggerInteraction.Ignore))
|
|
{
|
|
|
|
var MainPivotSlope = Vector3.SignedAngle(hit_Hip.normal, UpVector, Right);
|
|
|
|
if (MainPivotSlope < -maxAngleSlope) //Meaning it has touched the ground but the angle too deep
|
|
{
|
|
MainRay = false; //meaning the Slope is too deep
|
|
}
|
|
else
|
|
{
|
|
MainRay = true;
|
|
|
|
if (debugGizmos)
|
|
{
|
|
Debug.DrawRay(hit_Hip.point, hit_Hip.normal * ScaleFactor * 0.2f, Color.green);
|
|
MTools.DrawWireSphere(hipPoint + Direction * (hit_Hip.distance - RayCastRadius), Color.green, RayCastRadius * ScaleFactor);
|
|
}
|
|
|
|
if (platform != hit_Hip.transform) SetPlatform(hit_Hip.transform); //Platforming logic
|
|
|
|
hit_Hip.collider.attachedRigidbody?.AddForceAtPosition(Gravity * (RB.mass / 2), hit_Hip.point, ForceMode.Force);
|
|
|
|
if (!FrontRay/* && hit_Chest.normal == Vector3.zero*/) hit_Chest = hit_Hip; //If there's no Front Ray and it not collide with anything
|
|
}
|
|
}
|
|
else
|
|
{
|
|
platform = null;
|
|
|
|
if (FrontRay)
|
|
{
|
|
MovementAxis.z = 1; //Force going forward in case there's no Back Ray (HACK)
|
|
hit_Hip = hit_Chest; //In case there's no Hip Ray
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MainRay = FrontRay; //Just in case you dont have HIP RAY IMPORTANT FOR HUMANOID CHARACTERS
|
|
hit_Hip = hit_Chest; //In case there's no Hip Ray
|
|
}
|
|
|
|
if (ground_Changes_Gravity)
|
|
Gravity = -hit_Hip.normal;
|
|
|
|
|
|
// Debug.Log($"MainRay{MainRay} FrontRay{FrontRay}");
|
|
|
|
CalculateSurfaceNormal();
|
|
}
|
|
|
|
internal virtual void CalculateSurfaceNormal()
|
|
{
|
|
if (Has_Pivot_Hip)
|
|
{
|
|
Vector3 TerrainNormal;
|
|
|
|
if (Has_Pivot_Chest)
|
|
{
|
|
Vector3 direction = (hit_Chest.point - hit_Hip.point).normalized;
|
|
Vector3 Side = Vector3.Cross(UpVector, direction).normalized;
|
|
SurfaceNormal = Vector3.Cross(direction, Side).normalized;
|
|
|
|
TerrainNormal = SurfaceNormal;
|
|
}
|
|
else
|
|
{
|
|
SurfaceNormal = TerrainNormal = hit_Hip.normal;
|
|
}
|
|
|
|
TerrainSlope = Vector3.SignedAngle(TerrainNormal, UpVector, Right);
|
|
}
|
|
else
|
|
{
|
|
TerrainSlope = Vector3.SignedAngle(hit_Hip.normal, UpVector, Right);
|
|
SurfaceNormal = UpVector;
|
|
}
|
|
}
|
|
|
|
/// <summary>Align the Animal to Terrain</summary>
|
|
/// <param name="align">True: Aling to Surface Normal, False: Align to Up Vector</param>
|
|
internal virtual void AlignRotation(bool align, float time, float smoothness)
|
|
{
|
|
AlignRotation(align ? SurfaceNormal : UpVector, time, smoothness);
|
|
}
|
|
|
|
/// <summary>Align the Animal to a Custom </summary>
|
|
/// <param name="align">True: Aling to UP, False Align to Terrain</param>
|
|
internal virtual void AlignRotation(Vector3 alignNormal, float time, float Smoothness)
|
|
{
|
|
AlignRotLerpDelta = Mathf.Lerp(AlignRotLerpDelta, Smoothness, time * AlignRotDelta * 4);
|
|
|
|
Quaternion AlignRot = Quaternion.FromToRotation(transform.up, alignNormal) * transform.rotation; //Calculate the orientation to Terrain
|
|
Quaternion Inverse_Rot = Quaternion.Inverse(transform.rotation);
|
|
Quaternion Target = Inverse_Rot * AlignRot;
|
|
Quaternion Delta = Quaternion.Lerp(Quaternion.identity, Target, time * AlignRotLerpDelta); //Calculate the Delta Align Rotation
|
|
|
|
transform.rotation *= Delta;
|
|
//AdditiveRotation *= Delta;
|
|
}
|
|
|
|
/// <summary>Snap to Ground with Smoothing</summary>
|
|
internal void AlignPosition(float time)
|
|
{
|
|
if (!MainRay && !FrontRay) return; //DO NOT ALIGN IMPORTANT This caused the animals jumping upwards when falling down
|
|
AlignPosition(hit_Hip.distance, time, AlignPosLerp * 2);
|
|
}
|
|
|
|
internal void AlignPosition(float distance, float time, float Smoothness)
|
|
{
|
|
//Debug.Log(distance);
|
|
float difference = Height - distance;
|
|
|
|
if (!Mathf.Approximately(distance, Height))
|
|
{
|
|
AlignPosLerpDelta = Mathf.Lerp(AlignPosLerpDelta, Smoothness, time * AlignPosDelta);
|
|
|
|
var deltaHeight = difference * time * AlignPosLerpDelta;
|
|
|
|
Vector3 align = transform.rotation * new Vector3(0, deltaHeight, 0); //Rotates with the Transform to better alignment
|
|
AdditivePosition += align;
|
|
|
|
hit_Hip.distance += deltaHeight;
|
|
}
|
|
}
|
|
|
|
/// <summary>Snap to Ground with no Smoothing</summary>
|
|
internal virtual void AlignPosition_Distance(float distance)
|
|
{
|
|
float difference = Height - distance;
|
|
AdditivePosition += transform.rotation * new Vector3(0, difference, 0); //Rotates with the Transform to better alignment
|
|
}
|
|
|
|
|
|
/// <summary>Snap to Ground with no Smoothing</summary>
|
|
public virtual void AlignPosition()
|
|
{
|
|
float difference = Height - hit_Hip.distance;
|
|
AdditivePosition += transform.rotation * new Vector3(0, difference, 0); //Rotates with the Transform to better alignment
|
|
}
|
|
#endregion
|
|
|
|
/// <summary> Try Activate all other states </summary>
|
|
protected virtual void TryActivateState()
|
|
{
|
|
if (ActiveState.IsPersistent) return; //If the State cannot be interrupted the ignored trying activating any other States
|
|
if (JustActivateState) return; //Do not try to activate a new state since there already a new one on Activation
|
|
|
|
foreach (var trySt in states)
|
|
{
|
|
if (trySt.IsActiveState) continue; //Skip Re-Activating yourself
|
|
if (ActiveState.IgnoreLowerStates && ActiveState.Priority > trySt.Priority) return; //Do not check lower priority states
|
|
|
|
if ((trySt.UniqueID + CurrentCycle) % trySt.TryLoop != 0) continue; //Check the Performance Loop for the trying state
|
|
|
|
if (!ActiveState.IsPending && ActiveState.CanExit) //Means a new state can be activated
|
|
{
|
|
if ( trySt.Active &&
|
|
!trySt.OnEnterCoolDown &&
|
|
!trySt.IsSleep &&
|
|
!trySt.OnQueue &&
|
|
trySt.TryActivate())
|
|
{
|
|
trySt.Activate();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Check if the Active State can exit </summary>
|
|
protected virtual void TryExitActiveState()
|
|
{
|
|
if (ActiveState.CanExit && !ActiveState.IsPersistent)
|
|
ActiveState.TryExitState(DeltaTime); //if is not in transition and is in the Main Tag try to Exit to lower States
|
|
}
|
|
|
|
//private void FixedUpdate() => OnAnimalMove();
|
|
|
|
protected virtual void OnAnimatorMove() => OnAnimalMove();
|
|
|
|
|
|
protected virtual void OnAnimalMove()
|
|
{
|
|
if (Sleep)
|
|
{
|
|
Anim.ApplyBuiltinRootMotion();
|
|
return;
|
|
}
|
|
|
|
CacheAnimatorState();
|
|
ResetValues();
|
|
|
|
if (ActiveState == null) return;
|
|
|
|
DeltaTime = Time.fixedDeltaTime;
|
|
|
|
InputAxisUpdate(); //make sure when using Raw Input UPDATE the Calculations ****IMPORTANT****
|
|
|
|
ActiveState.SetCanExit(); //Check if the Active State can Exit to a new State (Was not Just Activated or is in transition)
|
|
|
|
PreStateMovement(this); //Check the Pre State Movement on External Scripts
|
|
|
|
ActiveState.OnStatePreMove(DeltaTime); //Call before the Target is calculated After the Input
|
|
|
|
CalculateTargetSpeed();
|
|
|
|
MoveRotator();
|
|
|
|
if (IsPlayingMode) ActiveMode.OnAnimatorMove(DeltaTime); //Do Charged Mode
|
|
|
|
AdditionalSpeed(DeltaTime);
|
|
if (UseAdditiveRot) AdditionalTurn(DeltaTime);
|
|
|
|
ApplyExternalForce();
|
|
|
|
if (Grounded)
|
|
{
|
|
|
|
if (AlignLoop.Value <= 1 || (AlignUniqueID + CurrentCycle) % AlignLoop.Value == 0)
|
|
AlignRayCasting();
|
|
|
|
AlignPosition(DeltaTime);
|
|
|
|
if (!UseCustomAlign)
|
|
AlignRotation(UseOrientToGround, DeltaTime, AlignRotLerp);
|
|
|
|
PlatformMovement();
|
|
}
|
|
else
|
|
{
|
|
MainRay = FrontRay = false;
|
|
SurfaceNormal = UpVector;
|
|
AlignPosLerpDelta = 0;
|
|
AlignRotLerpDelta = 0;
|
|
|
|
if (!UseCustomAlign)
|
|
AlignRotation(false, DeltaTime, AlignRotLerp); //Align to the Gravity Normal
|
|
TerrainSlope = 0;
|
|
}
|
|
|
|
ActiveState.OnStateMove(DeltaTime); //UPDATE THE STATE BEHAVIOUR
|
|
|
|
PostStateMovement(this); // Check the Post State Movement on External Scripts
|
|
|
|
TryExitActiveState();
|
|
TryActivateState();
|
|
|
|
MovementSystem(DeltaTime);
|
|
GravityLogic();
|
|
|
|
LastPos = transform.position;
|
|
|
|
if (float.IsNaN(AdditivePosition.x)) return;
|
|
|
|
if (!DisablePositionRotation)
|
|
{
|
|
if (RB)
|
|
{
|
|
if (RB.isKinematic)
|
|
{
|
|
transform.position += AdditivePosition;
|
|
}
|
|
else
|
|
{
|
|
// var OldRBVelocity = RB.velocity;
|
|
RB.velocity = Vector3.zero;
|
|
RB.angularVelocity = Vector3.zero;
|
|
|
|
if (DeltaTime > 0)
|
|
{
|
|
DesiredRBVelocity = AdditivePosition / DeltaTime;
|
|
RB.velocity = DesiredRBVelocity;
|
|
// RB.MoveRotation(transform.rotation * AdditiveRotation);// This does not work on newe versions of Unity
|
|
}
|
|
transform.rotation *= AdditiveRotation;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
transform.position += AdditivePosition;
|
|
transform.rotation *= AdditiveRotation;
|
|
}
|
|
|
|
Strafing_Rotation();
|
|
}
|
|
UpdateAnimatorParameters(); //Set all Animator Parameters
|
|
}
|
|
|
|
private void Strafing_Rotation()
|
|
{
|
|
if (Strafe && Aimer)
|
|
{
|
|
var RawDirection = Aimer.RawAimDirection;
|
|
|
|
Vector3 HorizontalDir = Vector3.ProjectOnPlane(RawDirection, UpVector);
|
|
Vector3 ForwardDir = Vector3.ProjectOnPlane(Forward, UpVector);
|
|
|
|
HorizontalAimAngle_Raw = -Vector3.SignedAngle(HorizontalDir, ForwardDir, UpVector);
|
|
|
|
|
|
StrafeDeltaValue = Mathf.Lerp(StrafeDeltaValue,
|
|
MovementDetected ? ActiveState.MovementStrafe : ActiveState.IdleStrafe,
|
|
DeltaTime * m_StrafeLerp);
|
|
|
|
SetOptionalAnimParameter(hash_StrafeAngle, HorizontalAimAngle_Raw);
|
|
|
|
// RB.MoveRotation(transform.rotation * Quaternion.Euler(0, HorizontalAimAngle_Raw * StrafeDeltaValue, 0));
|
|
transform.rotation *= Quaternion.Euler(0, HorizontalAimAngle_Raw * StrafeDeltaValue, 0);
|
|
}
|
|
else
|
|
{
|
|
HorizontalAimAngle_Raw = 0;
|
|
StrafeDeltaValue = 0;
|
|
SetOptionalAnimParameter(hash_StrafeAngle, HorizontalAimAngle_Raw);
|
|
}
|
|
}
|
|
|
|
/// <summary> This is used to add an External force to </summary>
|
|
private void ApplyExternalForce()
|
|
{
|
|
var Acel = ExternalForceAcel > 0 ? (DeltaTime * ExternalForceAcel) : 1; //Use Full for changing
|
|
|
|
CurrentExternalForce = Vector3.Lerp(CurrentExternalForce, ExternalForce, Acel);
|
|
|
|
if (CurrentExternalForce.sqrMagnitude <= 0.01f) CurrentExternalForce = Vector3.zero; //clean Tiny forces
|
|
|
|
|
|
if (CurrentExternalForce != Vector3.zero)
|
|
AdditivePosition += CurrentExternalForce * DeltaTime;
|
|
}
|
|
|
|
private void GravityLogic()
|
|
{
|
|
if (UseGravity)
|
|
{
|
|
if (Grounded) return; //Means has found the Ground
|
|
|
|
var GTime = DeltaTime * GravityTime;
|
|
|
|
GravityStoredVelocity = Gravity * GravityPower * (GTime * GTime / 2);
|
|
AdditivePosition += GravityStoredVelocity * DeltaTime; //Add Gravity if is in use
|
|
GravityTime++;
|
|
|
|
if (LimitGravityTime > 0 && LimitGravityTime < GravityTime) GravityTime--; //Make limit
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> Resets Additive Rotation and Additive Position to their default</summary>
|
|
void ResetValues()
|
|
{
|
|
DeltaRootMotion = RootMotion ? Anim.deltaPosition : Vector3.Lerp(DeltaRootMotion, Vector3.zero, currentSpeedModifier.lerpAnimator * DeltaTime);
|
|
|
|
// MainRay = FrontRay = false;
|
|
// AdditivePosition = Anim.deltaPosition;//? Anim.deltaPosition : Vector3.zero;
|
|
//AdditivePosition = RootMotion ? Anim.deltaPosition : Vector3.zero;
|
|
AdditivePosition = DeltaRootMotion;
|
|
AdditiveRotation = RootMotion ? Anim.deltaRotation : Quaternion.identity;
|
|
|
|
DeltaPos = transform.position - LastPos; //DeltaPosition from the last frame
|
|
CurrentCycle = (CurrentCycle + 1) % 999999999;
|
|
|
|
var DeltaRB = RB.velocity * DeltaTime;
|
|
DeltaVelocity = Grounded ? Vector3.ProjectOnPlane(DeltaRB, UpVector) : DeltaRB; //When is not grounded take the Up Vector this is the one!!!
|
|
}
|
|
}
|
|
} |