projectEli/Assets/NeoFPS/Core/MotionGraphs/Behaviours/BodyTiltBehaviour.cs
2022-11-06 20:28:33 -05:00

201 lines
8.2 KiB
C#

using UnityEngine;
using NeoFPS.CharacterMotion;
using NeoFPS.CharacterMotion.Parameters;
namespace NeoFPS.CharacterMotion.Behaviours
{
[MotionGraphElement("Character/BodyTilt", "BodyTiltBehaviour")]
[HelpURL("https://docs.neofps.com/manual/motiongraphref-mgb-bodytiltbehaviour.html")]
public class BodyTiltBehaviour : MotionGraphBehaviour
{
[SerializeField, Tooltip("The maximum tilt angle from vertical")]
private float m_TiltAngle = 15f;
[SerializeField, Range(0f, 1f), Tooltip("The point to tilt from normalised between the base of the character (0) and the head position of the character (1)")]
private float m_NormalisedTiltPoint = 0f;
[SerializeField, Tooltip("How is the tilt direction calculated. \"CharacterRelative\" uses the direction vector in the character's local space. \"WorldSpace\" ignores character direction. \"MoveDirection\" tilts away from the direction of movement")]
private TiltMode m_TiltMode = TiltMode.CharacterRelative;
[SerializeField, Tooltip("The direction parameter to use to drive the tilt")]
private VectorParameter m_DirectionVector = null;
[SerializeField, Tooltip("Is the tilt amount based on the velocity of the character")]
private bool m_VelocityBased = true;
[SerializeField, Tooltip("The speed below which the tilt amount will be 0")]
private float m_MinSpeed = 0f;
[SerializeField, Tooltip("The speed above which the tilt amount will be 1")]
private float m_MaxSpeed = 10f;
public enum TiltMode
{
CharacterRelative,
WorldSpace,
Velocity,
VelocityLateral,
Input,
InputLateral,
TiltTowards
}
private BodyTilt m_BodyTilt = null;
public override void OnValidate()
{
m_TiltAngle = Mathf.Clamp(m_TiltAngle, -45f, 45f);
// Clamp speeds
if (m_MinSpeed < 0f)
m_MinSpeed = 0f;
m_MaxSpeed = Mathf.Clamp(m_MaxSpeed, Mathf.Max(0.1f, m_MinSpeed), float.MaxValue);
}
public override void Initialise(MotionGraphConnectable o)
{
base.Initialise(o);
// Get the body tilt component
var character = controller.GetComponent<ICharacter>();
if (character != null && character.bodyTransformHandler != null)
m_BodyTilt = character.bodyTransformHandler.GetComponent<BodyTilt>();
if (m_BodyTilt == null)
Debug.Log("Body tilt not found");
if (m_TiltMode == TiltMode.TiltTowards)
m_VelocityBased = false;
}
public override void OnExit()
{
if (m_BodyTilt != null)
m_BodyTilt.ResetTilt();
}
public override void Update()
{
if (m_BodyTilt == null)
return;
// Tilt amount
float amount = 1f;
// Get the tilt direction
Vector2 tiltDirection = Vector2.zero;
switch (m_TiltMode)
{
case TiltMode.CharacterRelative:
{
Vector3 v = m_DirectionVector.value;
tiltDirection.x = v.x;
tiltDirection.y = v.z;
}
break;
case TiltMode.WorldSpace:
{
Vector3 v = m_DirectionVector.value;
tiltDirection.x = Vector3.Dot(v, controller.characterController.right);
tiltDirection.y = Vector3.Dot(v, controller.characterController.forward);
}
break;
case TiltMode.Velocity:
{
Vector3 v = controller.characterController.velocity;
tiltDirection.x = Vector3.Dot(v, controller.characterController.right);
tiltDirection.y = Vector3.Dot(v, controller.characterController.forward);
}
break;
case TiltMode.VelocityLateral:
{
Vector3 v = controller.characterController.velocity;
tiltDirection.x = Vector3.Dot(v, controller.characterController.right);
}
break;
case TiltMode.Input:
tiltDirection = controller.inputMoveDirection * controller.inputMoveScale;
break;
case TiltMode.InputLateral:
tiltDirection.x = controller.inputMoveDirection.x * controller.inputMoveScale;
break;
case TiltMode.TiltTowards:
{
Vector3 v = (m_DirectionVector.value - controller.localTransform.position).normalized;
float up = Vector3.Dot(v, controller.characterController.up);
tiltDirection.x = Vector3.Dot(v, controller.characterController.right);
tiltDirection.y = Vector3.Dot(v, controller.characterController.forward);
amount = (1f - Mathf.Abs(up));
}
break;
}
float magnitude = tiltDirection.magnitude;
if (magnitude < 0.001f)
{
// Reset tilt
m_BodyTilt.ResetTilt();
}
else
{
// Normalize the tilt direction
tiltDirection /= magnitude;
// Get tilt amount based on velocity
if (m_VelocityBased)
{
// Get the speed
float speed = 0f;
switch (m_TiltMode)
{
case TiltMode.VelocityLateral:
speed = magnitude;
break;
case TiltMode.Input:
{
float forward = Vector3.Dot(
controller.characterController.velocity,
controller.characterController.forward
) * tiltDirection.y;
if (forward < 0f)
forward = 0f;
float lateral = Vector3.Dot(
controller.characterController.velocity,
controller.characterController.right
) * tiltDirection.x;
if (lateral < 0f)
lateral = 0f;
speed = forward + lateral;
}
break;
case TiltMode.InputLateral:
{
speed = Vector3.Dot(
controller.characterController.velocity,
controller.characterController.right
) * tiltDirection.x;
if (speed < 0f)
speed = 0f;
}
break;
default:
{
Vector3 flattenedVelocity = Vector3.ProjectOnPlane(
controller.characterController.velocity,
controller.characterController.up
);
speed = flattenedVelocity.magnitude;
}
break;
}
// Get the tilt amount
amount = Mathf.Clamp01((speed - m_MinSpeed) / (m_MaxSpeed - m_MinSpeed));
}
m_BodyTilt.SetTilt(tiltDirection, m_TiltAngle * amount, m_NormalisedTiltPoint);
}
}
public override void CheckReferences(IMotionGraphMap map)
{
m_DirectionVector = map.Swap(m_DirectionVector);
}
}
}