I have a script which includes walking, running, jumping and sliding/crouching.
But there is an issue with jumping, because when i press the jump button (spacebar), the player jumps slightly in one of the directions parallel to the ground, so for instance when jumping he moves a little on the X axis.
There is another problem, because the player character can sometimes just freeze. In that situation, when i press spacebar whilst the player camera looks at the ground and i haven’t jumped in few seconds, i can’t jump until i move my camera.
Furthermore, an interesting thing i noticed i consider a problem is when the player is moving in the air and he lands, he loses velocity.
And the last issue i think is, when the player lands, he does not jump right away besides holding spacebar the whole time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
float xRot;
public float mouseSensivity = 10f;
public GameObject _Camera;
Rigidbody rb;
readonly float threshold = 0.01f;
public float acc;
public float maxSpeed, maxSprint, maxCrouch;
public float jumpForce;
public float slideForce;
public float counterMovement;
bool grounded = true;
public LayerMask groundLayers;
public float maxSlopeAngle;
public Vector2 slopeRange;
float mSlope_;
float x, y;
float mouseX, mouseY;
bool sprint, crouch, jump;
Vector3 regularScale = Vector3.one;
public Vector3 crouchScale;
Vector3 normal;
Vector3 wallNormal;
#region UnityStuff
private void Awake()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void Start()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
InputFunc();
Camera();
}
private void FixedUpdate()
{
Movement();
}
#endregion
void InputFunc()
{
x = Input.GetAxisRaw("Horizontal");
y = Input.GetAxisRaw("Vertical");
mouseX = Input.GetAxis("Mouse X");
mouseY = Input.GetAxis("Mouse Y");
sprint = Input.GetKey(KeyCode.LeftShift);
crouch = Input.GetKey(KeyCode.LeftControl);
jump = Input.GetKey(KeyCode.Space);
if (Input.GetKeyDown(KeyCode.LeftControl)) StartCrouch();
if (Input.GetKeyUp(KeyCode.LeftControl)) StopCrouch();
}
void StartCrouch()
{
transform.localScale = crouchScale;
transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z);
if (rb.velocity.magnitude > 0.5f)
{
if (grounded)
{
rb.AddForce(transform.forward * slideForce, ForceMode.Impulse);
}
}
}
void StopCrouch()
{
transform.localScale = regularScale;
transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
}
void Camera()
{
xRot -= mouseY * mouseSensivity;
xRot = Mathf.Clamp(xRot, -90f, 90f);
transform.Rotate(Vector3.up * mouseX * mouseSensivity);
_Camera.transform.localRotation = Quaternion.Euler(xRot, 0f, 0f);
}
void Movement()
{
float localMax = IsCrouchwalking() ? maxCrouch : (sprint ? maxSprint : maxSpeed);
Vector2 mag = FindVelRelativeToLook();
float xMag = mag.x, yMag = mag.y;
if (jump && grounded) Jump();
CounterMovement(mag);
if (crouch && grounded)
{
rb.AddForce(Vector3.down * 1000 * Time.deltaTime);
return;
}
if (x > 0 && xMag >= localMax) x = 0;
if (x < 0 && xMag <= -localMax) x = 0;
if (y > 0 && yMag >= localMax) y = 0;
if (y < 0 && yMag <= -localMax) y = 0;
float multiplierA = 1f, multiplier = 1f;
// Movement in air
if (!grounded) multiplierA = 0.15f;
// Movement while sliding
if (IsSliding() || crouch) multiplier = 0f;
//Apply forces to move player
rb.AddForce(transform.forward * y * acc * Time.fixedDeltaTime * multiplierA * multiplier);
rb.AddForce(transform.right * x * acc * Time.fixedDeltaTime * multiplierA * multiplier);
float vel = Mathf.Sqrt(Mathf.Pow(rb.velocity.x, 2) + Mathf.Pow(rb.velocity.z, 2));
bool uhohexclamationmark_youjustmfeexceededthemaxspeed = vel > localMax;
if (uhohexclamationmark_youjustmfeexceededthemaxspeed && !IsSliding())
{
float fallspeed = rb.velocity.y;
Vector3 n = rb.velocity.normalized * localMax;
rb.velocity = new Vector3(n.x, fallspeed, n.z);
}
}
void Jump()
{
rb.AddForce(Vector2.up * jumpForce * 0.948f);
rb.AddForce(normal * jumpForce * 0.316f);
}
void CounterMovement(Vector2 mag)
{
if (IsSliding() || !grounded) return;
if (Mathf.Abs(mag.x) > threshold && Mathf.Abs(x) < 0.05f || (mag.x < -threshold && x > 0) || (mag.x > threshold && x < 0))
{
rb.AddForce(acc * transform.right * Time.deltaTime * -mag.x * counterMovement);
}
if (Mathf.Abs(mag.y) > threshold && Mathf.Abs(y) < 0.05f || (mag.y < -threshold && y > 0) || (mag.y > threshold && y < 0))
{
rb.AddForce(acc * transform.forward * Time.deltaTime * -mag.y * counterMovement);
}
}
public Vector2 FindVelRelativeToLook()
{
float lookAngle = transform.eulerAngles.y;
float moveAngle = Mathf.Atan2(rb.velocity.x, rb.velocity.z) * Mathf.Rad2Deg;
float u = Mathf.DeltaAngle(lookAngle, moveAngle);
float v = 90 - u;
float magnitue = rb.velocity.magnitude;
float yMag = magnitue * Mathf.Cos(u * Mathf.Deg2Rad);
float xMag = magnitue * Mathf.Cos(v * Mathf.Deg2Rad);
return new Vector2(xMag, yMag);
}
private bool IsFloor(Vector3 v)
{
float angle = Vector3.Angle(Vector3.up, v);
return angle < maxSlopeAngle;
}
bool cancellingGrounded = false;
private void OnCollisionStay(Collision other)
{
//Make sure we are only checking for walkable layers
int layer = other.gameObject.layer;
if (groundLayers != (groundLayers | (1 << layer))) return;
mSlope_ = 0f;
//Iterate through every collision in a physics update
for (int i = 0; i < other.contactCount; i++)
{
Vector3 normal = other.contacts[i].normal;
//FLOOR
if (IsFloor(normal))
{
mSlope_ = mSlope_ < Vector3.Angle(Vector3.up, normal) ? Vector3.Angle(Vector3.up, normal) : mSlope_;
grounded = true;
cancellingGrounded = false;
this.normal = normal;
CancelInvoke(nameof(StopGrounded));
}
}
//Invoke ground/wall cancel, since we can't check normals with CollisionExit
float delay = 3f;
if (!cancellingGrounded)
{
cancellingGrounded = true;
Invoke(nameof(StopGrounded), Time.deltaTime * delay);
}
}
private void StopGrounded()
{
grounded = false;
}
bool IsSliding()
{
return rb.velocity.magnitude > maxCrouch && crouch;
}
bool IsCrouchwalking()
{
return rb.velocity.magnitude <= maxCrouch && crouch && grounded;
}
}
This is the script currently used for the player and the default values i use in unity inspector are:
Mouse Sensivity = 2.5
Acc = 4500
Max Speed = 6
Max Sprint = 14
Max Crouch = 5
Jump Force = 60
Slide Force = 5
Counter Movement = 0.075
Ground Layers -> Ground (Ground layer is set as the 31st layer)
Max Slope Angle = 35
It’s worth mentioning that the camera is inside the player capsule object.
I would be way more than happy if someone could look into this.