using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(CharacterController))] 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 Vector3 GroundVelocity = new Vector3(); private float FallingVelocity; private float LastGroundedTime; private float SlideStartTime; private void Awake() { Character = GetComponent(); } 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; } 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; } } }