holopy3/Assets/Plugins/RootMotion/Shared Demo Assets/Scripts/Character Controllers/SimpleLocomotion.cs
2020-12-10 15:25:12 +01:00

142 lines
4.1 KiB
C#

using UnityEngine;
using System.Collections;
namespace RootMotion.Demos {
// The simplest multi-purpose locomotion controller for demo purposes. Can use root motion, simple procedural motion or the CharacterController
[RequireComponent(typeof(Animator))]
public class SimpleLocomotion : MonoBehaviour {
// The character rotation mode
[System.Serializable]
public enum RotationMode {
Smooth,
Linear
}
[Tooltip("The component that updates the camera.")]
public CameraController cameraController;
[Tooltip("Acceleration of movement.")]
public float accelerationTime = 0.2f;
[Tooltip("Turning speed.")]
public float turnTime = 0.2f;
[Tooltip("If true, will run on left shift, if not will walk on left shift.")]
public bool walkByDefault = true;
[Tooltip("Smooth or linear rotation.")]
public RotationMode rotationMode;
[Tooltip("Procedural motion speed (if not using root motion).")]
public float moveSpeed = 3f;
// Is the character grounded (using very simple y < something here for simplicity's sake)?
public bool isGrounded { get; private set; }
private Animator animator;
private float speed;
private float angleVel;
private float speedVel;
private Vector3 linearTargetDirection;
private CharacterController characterController;
void Start() {
animator = GetComponent<Animator>();
characterController = GetComponent<CharacterController>();
cameraController.enabled = false;
}
void Update() {
// Very basic planar method, should use collision events
isGrounded = transform.position.y < 0.1f;
Rotate();
Move();
}
void LateUpdate() {
// Update the camera last
cameraController.UpdateInput();
cameraController.UpdateTransform();
}
private void Rotate() {
if (!isGrounded) return;
// Updating the rotation of the character
Vector3 inputVector = GetInputVector();
if (inputVector == Vector3.zero) return;
Vector3 forward = transform.forward;
switch(rotationMode) {
case RotationMode.Smooth:
Vector3 targetDirection = cameraController.transform.rotation * inputVector;
float angleForward = Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg;
float angleTarget = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
// Smoothly rotating the character
float angle = Mathf.SmoothDampAngle(angleForward, angleTarget, ref angleVel, turnTime);
transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
break;
case RotationMode.Linear:
Vector3 inputVectorRaw = GetInputVectorRaw();
if (inputVectorRaw != Vector3.zero) linearTargetDirection = cameraController.transform.rotation * inputVectorRaw;
forward = Vector3.RotateTowards(forward, linearTargetDirection, Time.deltaTime * (1f /turnTime), 1f);
forward.y = 0f;
transform.rotation = Quaternion.LookRotation(forward);
break;
}
}
private void Move() {
// Speed interpolation
float speedTarget = walkByDefault? (Input.GetKey(KeyCode.LeftShift)? 1f: 0.5f): (Input.GetKey(KeyCode.LeftShift)? 0.5f: 1f);
speed = Mathf.SmoothDamp(speed, speedTarget, ref speedVel, accelerationTime);
// Moving the character by root motion
float s = GetInputVector().magnitude * speed;
animator.SetFloat("Speed", s);
// Procedural motion if we don't have root motion
bool proceduralMotion = !animator.hasRootMotion && isGrounded;
if (proceduralMotion) {
Vector3 move = transform.forward * s * moveSpeed;
if (characterController != null) {
characterController.SimpleMove(move);
} else {
transform.position += move * Time.deltaTime;
}
}
}
// Reads the Input to get the movement direction.
private Vector3 GetInputVector() {
Vector3 d = new Vector3(
Input.GetAxis("Horizontal"),
0f,
Input.GetAxis("Vertical")
);
d.z += Mathf.Abs(d.x) * 0.05f;
d.x -= Mathf.Abs(d.z) * 0.05f;
return d;
}
private Vector3 GetInputVectorRaw() {
return new Vector3(
Input.GetAxisRaw("Horizontal"),
0f,
Input.GetAxisRaw("Vertical")
);
}
}
}