So I tried to create a movement script that functions similarly to how Source Engine/Quake handles movement, meaning it would allow some movement techniques like air strafing and bunny hopping. However, with the code so far when I move the player character even a tiny bit, it would somehow just zoom off into the horizon. Right now, I am trying to figure out if the problem lies in the values set in the Inspector or in the code as is. And I can’t come to any conclusion as I still have the problem I described.
Here is the movement script:
public enum MoveState
{
ground,
air
}
public class PlayerMove : MonoBehaviour
{
[System.Serializable]
public class MovementSettings
{
public float MaxSpeed;
public float Acceleration;
public MovementSettings(float maxSpeed, float accel)
{
MaxSpeed = maxSpeed;
Acceleration = accel;
}
}
private float playerHeight = 2f;
[SerializeField] private Transform Orientation;
[Header("Movement")]
[SerializeField] private float friction = 6f;
[SerializeField] private MovementSettings groundSettings = new MovementSettings(6, 12);
[SerializeField] private MovementSettings airSettings = new MovementSettings(6, 2);
private MoveState state;
[Header("Jump")]
[SerializeField] private float jumpForce = 8f;
private float horizontalMovement, verticalMovement;
private Vector3 slopeMoveDirection;
public Vector3 moveDirection { get; private set; }
private Rigidbody rb;
[Header("Ground Detection")]
[SerializeField] LayerMask groundMask;
[SerializeField] private float groundDistance = 0.4f;
[SerializeField] private Transform groundCheck;
public bool isGrounded { get; private set; }
public bool canDoubleJump { get; set; }
RaycastHit slopeHit;
private void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
}
private void Update()
{
//Check that the player model is hitting the ground layer
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded)
{
state = MoveState.ground;
canDoubleJump = true;
}
else
{
state = MoveState.air;
}
//Check player input
PlayerInput();
//check if player wants to jump
checkJump();
if (Input.GetKeyDown(KeyCode.LeftControl))
{
transform.localScale = slideScale;
transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z);
}
//checkIfCanSlide();
if (Input.GetKeyUp(KeyCode.LeftControl))
{
transform.localScale = playerScale;
transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
}
//Gets slope movement
slopeMoveDirection = Vector3.ProjectOnPlane(moveDirection, slopeHit.normal);
//movement state
switch (state)
{
case MoveState.ground:
if (OnSlope()) { moveDirection = MoveGround(slopeMoveDirection.normalized, rb.velocity); }
else { moveDirection = MoveGround(moveDirection.normalized, rb.velocity); };
break;
case MoveState.air:
moveDirection = MoveAir(moveDirection.normalized, rb.velocity);
break;
}
Debug.Log(moveDirection);
rb.AddForce(moveDirection, ForceMode.Acceleration);
}
private void PlayerInput()
{
//movement direction
horizontalMovement = Input.GetAxisRaw("Horizontal");
verticalMovement = Input.GetAxisRaw("Vertical");
//Calculate move direction
moveDirection = horizontalMovement * Orientation.right + verticalMovement * Orientation.forward;
}
private void checkJump()
{
if(isGrounded && Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
else if(!isGrounded && canDoubleJump && Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
canDoubleJump = false;
}
}
private Vector3 Accelerate(Vector3 wishDir, Vector3 prevVelocity, float accelerate, float max_velocity)
{
float projVel = Vector3.Dot(prevVelocity, wishDir);
float accelVel = accelerate * Time.deltaTime;
if(projVel + accelVel > max_velocity)
{
accelVel = max_velocity - projVel;
}
return prevVelocity + (wishDir * accelVel);
}
private Vector3 MoveGround(Vector3 wishDir, Vector3 prevVelocity)
{
float speed = prevVelocity.magnitude;
if(speed != 0)
{
float drop = speed * friction * Time.deltaTime;
prevVelocity *= Mathf.Max(speed - drop, 0) / speed;
}
return Accelerate(wishDir, prevVelocity, groundSettings.Acceleration, groundSettings.MaxSpeed);
}
private Vector3 MoveAir(Vector3 wishDir, Vector3 prevVelocity)
{
prevVelocity = new Vector3(prevVelocity.x, 0f, prevVelocity.z);
return Accelerate(wishDir, prevVelocity, airSettings.Acceleration, airSettings.MaxSpeed);
}
private bool OnSlope()
{
if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight / 2 + 0.5f)) {
if(slopeHit.normal != Vector3.up)
{
return true;
}
}
return false;
}
}
Anyone noticed anything off or anything that would lead to this issue?