campfire/Assets/Scripts/PlayerController.cs

114 lines
4.2 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(CameraBobber))]
public class PlayerController : MonoBehaviour {
public float MovementSpeed;
public float JumpVelocity;
public float SlideVelocity;
[Tooltip("How long after falling off a ledge can the player still jump?")]
public float JumpGracePeriod;
[Tooltip("Lower values make the movement feel floatier.")]
public float Antislipperiness = 1;
[Tooltip("Lower values make the movement feel floatier in air.")]
public float AntislipperinessInAir = 1;
[Header("Runtime values")]
public bool Grounded;
public Vector3 GroundNormal;
private CharacterController Character;
private CameraBobber Bobber;
private Vector3 GroundVelocity = new Vector3();
private float FallingVelocity;
private float LastGroundedTime;
private float SlideStartTime;
private void Awake() {
Character = GetComponent<CharacterController>();
Bobber = GetComponent<CameraBobber>();
}
private void Start() {
LastGroundedTime = -JumpGracePeriod;
Grounded = false;
}
private void Update() {
Vector3 CurrentVelocity = new Vector3();
GroundNormal = RaycastGroundNormal();
// Sliding
bool Sliding = Grounded && Vector3.Angle(GroundNormal, Vector3.up) > Character.slopeLimit;
// Groundedness stuff and gravity
if (Character.isGrounded && !Sliding) {
FallingVelocity = Mathf.Max(0, FallingVelocity);
LastGroundedTime = Time.time;
} else {
FallingVelocity += Physics.gravity.y * Time.deltaTime;
}
Grounded = Time.time - LastGroundedTime <= JumpGracePeriod && FallingVelocity <= 0;
// Jumping
if (Input.GetButton("Jump") && Grounded) {
FallingVelocity = JumpVelocity;
Grounded = false;
}
CurrentVelocity += FallingVelocity * Vector3.up;
float SlippyFactor = Grounded ? Antislipperiness : AntislipperinessInAir;
// Subtract friction
float FrictionFactor = Mathf.Max(GroundVelocity.magnitude, 1);
float Friction = Mathf.Min(GroundVelocity.magnitude, FrictionFactor * SlippyFactor * Time.deltaTime);
GroundVelocity -= Friction * GroundVelocity.normalized;
// Add player input momentum
float TargetSpeed = MovementSpeed; // Tweak this to enable running or stuff
Vector3 Move = transform.forward * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal");
// If Move magnitude is < 0, it's probably an analog stick, so scale target speed accordingly.
TargetSpeed *= Mathf.Min(1, Move.magnitude);
if (Move.magnitude > 0) {
Move.Normalize();
if (Grounded) {
// Slow down when moving on slopes
TargetSpeed *= Vector3.Dot(Vector3.up, GroundNormal);
}
float CurrentSpeed = Vector3.Dot(Move, GroundVelocity);
float SpeedDiff = TargetSpeed - CurrentSpeed;
float Acceleration = Mathf.Min(SpeedDiff, TargetSpeed * SlippyFactor * Time.deltaTime);
GroundVelocity += Move * Acceleration;
}
CurrentVelocity += GroundVelocity;
// Sliiide
if (Sliding) {
CurrentVelocity = Vector3.ProjectOnPlane(CurrentVelocity, GroundNormal);
CurrentVelocity += Vector3.ProjectOnPlane(-Vector3.up, GroundNormal) * SlideVelocity;
}
Bobber.BobMagnitude = Mathf.Lerp(Bobber.BobMagnitude, TargetSpeed > 0 ? GroundVelocity.magnitude / TargetSpeed : 1, 5f * Time.deltaTime);
Bobber.Moving = GroundVelocity.magnitude > 0.1f;
Bobber.InAir = !Grounded;
Character.Move(CurrentVelocity * Time.deltaTime);
}
private Vector3 RaycastGroundNormal() {
RaycastHit Hit;
if (Physics.CapsuleCast(
transform.position + Vector3.up * Character.radius,
transform.position + Vector3.up * (Character.height - Character.radius),
Character.radius, -Vector3.up, out Hit, Character.skinWidth * 2)) {
return Hit.normal;
} else {
return Vector3.up;
}
}
}