In my Rigidbody FPS controller script, I change the drag in the Rigidbody to prevent the player from going super fast. However, this has led to some problems such as me needing to add a constant down force when in the air to prevent floating down super slowly. I don’t want to change the drag value in my Rigidbody so that leads me to the question, how can I add counter-movement into my game?
Here is the script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class PlayerMovement : MonoBehaviour
{
public static PlayerMovement instance;
float playerHeight = 2f;
[SerializeField] Transform orientation;
[SerializeField] float moveSpeed = 6f;
[SerializeField] float airMultiplier = 0.4f;
float movementMultiplier = 10f;
[Header("Sprinting")]
[SerializeField] float walkSpeed = 4f;
[SerializeField] float sprintSpeed = 7f;
float crouchSpeedMod = 0.5f;
float shootSpeedMod = 0.8f;
float aimSpeedMod = 0.5f;
[SerializeField] float acceleration = 10f;
public bool isShooting;
public bool isAiming;
public bool isReloading;
public bool isSprinting;
public bool isCrouching;
[Header("Jumping")]
public float jumpForce = 5f;
public float downForce = 1f;
[Header("Keybinds")]
[SerializeField] KeyCode jumpKey = KeyCode.Space;
[SerializeField] KeyCode sprintKey = KeyCode.LeftShift;
[SerializeField] KeyCode slideKey = KeyCode.LeftControl;
[Header("Drag")]
[SerializeField] float groundDrag = 6f;
[SerializeField] float airDrag = 2f;
float horizontalMovement;
float verticalMovement;
[Header("Ground Detection")]
[SerializeField] Transform groundCheck;
[SerializeField] LayerMask groundMask;
[SerializeField] float groundDistance = 0.2f;
public bool isGrounded { get; private set; }
[Header("Sliding")]
public float slideForce = 25f;
public GameObject player;
Vector3 slide = new Vector3(1f, 0.5f, 1f);
public float shrinkSpeed = 3f;
public float slideScale = 0.75f, originalScale = 1f;
private float targetScale = 1f;
public float slideCooldown;
private float currentSlideCooldown;
Vector3 moveDirection;
Vector3 slopeMoveDirection;
Rigidbody rb;
RaycastHit slopeHit;
[Header("Speed Calc")]
Vector3 previousFramePos = Vector3.zero;
float currentSpeed = 0f;
public TMP_Text speedText;
[Header("Animation")]
public Animator anim;
private bool OnSlope()
{
if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight / 2 + 0.5f))
{
if (slopeHit.normal != Vector3.up)
{
return true;
}
else
{
return false;
}
}
return false;
}
private void Awake()
{
instance = this;
}
private void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
}
void Update()
{
transform.localScale = Vector3.Lerp(transform.localScale, new Vector3(0, targetScale), shrinkSpeed * Time.deltaTime);
if (currentSlideCooldown > 0f)
{
currentSlideCooldown -= Time.deltaTime;
}
else
{
if (Input.GetKeyDown(slideKey) && Input.GetKey(KeyCode.W))
{
StartSlide();
Crouch();
currentSlideCooldown = slideCooldown;
}
else if (Input.GetKeyUp(slideKey))
{
StopSlide();
}
}
if (Input.GetKeyDown(slideKey))
{
Crouch();
}
else if (Input.GetKeyUp(slideKey))
{
StopSlide();
}
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
MoveInput();
ControlDrag();
ControlSpeed();
ControlAnimations();
slopeMoveDirection = Vector3.ProjectOnPlane(moveDirection, slopeHit.normal);
float movementPerFrame = Vector3.Distance(new Vector3(previousFramePos.x, 0f, previousFramePos.z), new Vector3(transform.position.x, 0f, transform.position.z));
currentSpeed = movementPerFrame / Time.deltaTime;
previousFramePos = new Vector3(transform.position.x, 0f, transform.position.z);
speedText.text = "Speed: " + currentSpeed;
Debug.Log(rb.velocity.magnitude.ToString());
}
private void FixedUpdate()
{
MovePlayer();
if (!isGrounded)
rb.AddForce(Vector3.down * downForce, ForceMode.Force);
if (Input.GetKey(jumpKey) && isGrounded)
{
Jump();
StopSlide();
}
}
void MoveInput()
{
horizontalMovement = Input.GetAxisRaw("Horizontal");
verticalMovement = Input.GetAxisRaw("Vertical");
moveDirection = orientation.forward * verticalMovement + orientation.right * horizontalMovement;
}
void Jump()
{
if (isGrounded)
{
rb.velocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
}
void ControlSpeed()
{
if (Input.GetKey(sprintKey) && isGrounded)
{
isSprinting = true;
}
else if (!Input.GetKey(sprintKey))
{
isSprinting = false;
}
if (Input.GetKey(slideKey) && isGrounded)
{
isCrouching = true;
}
else
{
isCrouching = false;
}
if (isShooting || isAiming || isReloading || isCrouching)
{
isSprinting = false;
}
if (isSprinting)
{
moveSpeed = Mathf.Lerp(moveSpeed, sprintSpeed, acceleration * Time.deltaTime);
}
else
{
if (isCrouching)
{
if (isAiming)
{
if (isShooting)
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * shootSpeedMod * aimSpeedMod * crouchSpeedMod, acceleration * Time.deltaTime);
else
{
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * aimSpeedMod * crouchSpeedMod, acceleration * Time.deltaTime);
}
}
else
{
if (isShooting)
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * shootSpeedMod * crouchSpeedMod, acceleration * Time.deltaTime);
else
{
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * crouchSpeedMod, acceleration * Time.deltaTime);
}
}
}
else
{
if (isAiming)
{
if (isShooting)
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * shootSpeedMod * aimSpeedMod, acceleration * Time.deltaTime);
else
{
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * aimSpeedMod, acceleration * Time.deltaTime);
}
}
else
{
if (isShooting)
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed * shootSpeedMod, acceleration * Time.deltaTime);
else
{
moveSpeed = Mathf.Lerp(moveSpeed, walkSpeed, acceleration * Time.deltaTime);
}
}
}
}
}
void ControlAnimations()
{
if (isShooting)
{
anim.SetBool("isWalking", false);
anim.SetBool("isSprinting", false);
return;
}
if (!isGrounded)
{
anim.SetBool("isSprinting", false);
anim.SetBool("isWalking", false);
isSprinting = false;
return;
}
if (horizontalMovement != 0f || verticalMovement != 0f)
{
if (isSprinting)
{
anim.SetBool("isSprinting", true);
anim.SetBool("isWalking", false);
return;
}
else
{
anim.SetBool("isWalking", true);
anim.SetBool("isSprinting", false);
return;
}
}
else
{
anim.SetBool("isSprinting", false);
anim.SetBool("isWalking", false);
return;
}
}
void ControlDrag()
{
if (isGrounded)
{
rb.drag = groundDrag;
}
else
{
rb.drag = airDrag;
}
}
void MovePlayer()
{
if (isGrounded && !OnSlope())
{
rb.AddForce(moveDirection * moveSpeed * movementMultiplier, ForceMode.Acceleration);
}
else if (isGrounded && OnSlope())
{
rb.AddForce(slopeMoveDirection * moveSpeed * movementMultiplier, ForceMode.Acceleration);
}
else if (!isGrounded)
{
rb.AddForce(moveDirection * moveSpeed * movementMultiplier * airMultiplier, ForceMode.Acceleration);
}
}
void Crouch()
{
targetScale = slideScale;
}
void StartSlide()
{
if(rb.velocity.magnitude > 0.5f)
rb.AddForce(orientation.forward * slideForce);
}
void StopSlide()
{
targetScale = originalScale;
}
}