[SOLVED] FPS Crouch and Prone

Hi everyone!

Newbie question here. Why only one of the two works? If i have both crouch and prone, only the prone works, but if i delete prone, crouch works flawlessly. Both have different key bindings.

private void CrouchInput()
{
if (Input.GetKeyDown(crouchKey))
{
if (crouching)
{
prone = false;
}

else
crouching = true;
}

if (crouching)
{
charController.height = 1.0f;

}
else
charController.height = 2.0f;

}

private void ProneInput()
{
if (Input.GetKeyDown(proneKey))
{
if (prone)
{
prone = false;
}

else
prone = true;
}

if (prone)
{
charController.height = 0.5f;

}
else
charController.height = 2.0f;

}

First, Using code tags properly then State · Design Patterns Revisited · Game Programming Patterns

A bit hard to read, but I’ll guess that if you call both functions, one of them overwrites the value from the other one.

Post code like this, or people will have difficulty following along. On line 7 below, I think you meant to put “crouching = false” instead of “prone = false”. But I’m sure you need to set crouching to false whenever you go prone and set prone to false whenever you start crouching.

private void CrouchInput()
{
    if (Input.GetKeyDown(crouchKey))
    {
        if (crouching)
        {
            prone = false;
        }
        else
            crouching = true;
        }

        if (crouching)
        {
            charController.height = 1.0f;
        }
        else
            charController.height = 2.0f;
    }

private void ProneInput()
{
    if (Input.GetKeyDown(proneKey))
    {
        if (prone)
        {
            prone = false;
        }
        else
            prone = true;
    }

    if (prone)
    {
        charController.height = 0.5f;
    }
    else
        charController.height = 2.0f;
}

Actually I’d just change this whole thing since having separate bools for each is a bit silly, since you obviously can’t both prone and crouch at the same time. Something like below.

public Enum CharacterStance { Stand, Crouch, Prone };
private CharacterStance currentStance = CharacterStance.Stand;

private void CrouchInput()
{
    if (Input.GetKeyDown(crouchKey))
    {
        if (currentStance != CharacterStance.Crouch)
        {
            currentStance = CharacterStance.Crouch;
        }
        else
        {
            currentStance = CharacterStance.Stand;
        }

        updateHeight();
    }
}

private void ProneInput()
{
    if (Input.GetKeyDown(proneKey))
    {
        if (currentStance != CharacterStance.Prone)
        {
            currentStance = CharacterStance.Prone;
        }
        else
        {
            currentStance = CharacterStance.Stand;
        }
       
        updateHeight();
    }
}

private void updateHeight()
{
    switch(currentStance)
    {
        case CharacterStance.Stand:
            charController.height = 2.0f;
            break;
        case CharacterStance.Crouch:
            charController.height = 1.0f;
            break;
        case CharacterStance.Prone:
            charController.height = 0.5f;
            break;
    }
}

Thank you!

It works, perfect. Now my next step is to figure it out how to move the camera a little bit lower when the character goes to crouch and prone. The camera moves down a little bit when the character is crouching but not as much as i like to. :smile:

And sorry for not using code tag.

This is my full FP controller right now.

public class PlayerMove : MonoBehaviour
{
    [SerializeField] private string horizontalInputName;
    [SerializeField] private string verticalInputName;

    [SerializeField] private float walkSpeed, runSpeed;
    [SerializeField] private float runBuildUpSpeed;
    [SerializeField] private KeyCode runKey;

    private float movementSpeed;

    [SerializeField] private float slopeForce;
    [SerializeField] private float slopeForceRayLength;

    private CharacterController charController;

    [SerializeField] private AnimationCurve jumpFallOff;
    [SerializeField] private float jumpMultiplier;
    [SerializeField] private KeyCode jumpKey;

    [SerializeField] private KeyCode crouchKey;
    [SerializeField] private KeyCode proneKey;



    private bool isJumping;
    private bool crouching;
    private bool prone;

    private void Awake()
    {
        charController = GetComponent<CharacterController>();
        charController.height = 2.0f;
    }

    private void Update()
    {
        PlayerMovement();
    }

    private void PlayerMovement()
    {
        float horizInput = Input.GetAxis(horizontalInputName);
        float vertInput = Input.GetAxis(verticalInputName);

        Vector3 forwardMovement = transform.forward * vertInput;
        Vector3 rightMovement = transform.right * horizInput;

        charController.SimpleMove(Vector3.ClampMagnitude(forwardMovement + rightMovement, 1.0f) * movementSpeed);

        if ((vertInput != 0 || horizInput != 0) && OnSlope())
            charController.Move(Vector3.down * charController.height / 2 * slopeForce * Time.deltaTime);

    

        SetMovementSpeed();
        JumpInput();
        CrouchInput();
        ProneInput();

    }

    private void SetMovementSpeed()
    {
        if (Input.GetKey(runKey))
            movementSpeed = Mathf.Lerp(movementSpeed, runSpeed, Time.deltaTime * runBuildUpSpeed);
        else
            movementSpeed = Mathf.Lerp(movementSpeed, walkSpeed, Time.deltaTime * runBuildUpSpeed);
    }



    private bool OnSlope()
    {
        if (isJumping)
            return false;

        RaycastHit hit;

        if (Physics.Raycast(transform.position, Vector3.down, out hit, charController.height / 2 * slopeForceRayLength))
            if (hit.normal != Vector3.up)
                return true;
        return false;
    }


    private void JumpInput()
    {
        if (Input.GetKeyDown(jumpKey) && !isJumping)
        {
            isJumping = true;
            StartCoroutine(JumpEvent());
        }
    }

    private IEnumerator JumpEvent()
    {
        charController.slopeLimit = 90.0f;
        float timeInAir = 0.0f;


        do
        {
            float jumpForce = jumpFallOff.Evaluate(timeInAir);
            charController.Move(Vector3.up * jumpForce * jumpMultiplier * Time.deltaTime);
            timeInAir += Time.deltaTime;
            yield return null;
        } while (!charController.isGrounded && charController.collisionFlags != CollisionFlags.Above);

        charController.slopeLimit = 45.0f;

        isJumping = false;

    }



    public enum CharacterStance { Stand, Crouch, Prone };
    private CharacterStance currentStance = CharacterStance.Stand;

    private void CrouchInput()
    {
        if (Input.GetKeyDown(crouchKey))
        {
            if (currentStance != CharacterStance.Crouch)
            {
                currentStance = CharacterStance.Crouch;
            }
            else
            {
                currentStance = CharacterStance.Stand;
            }

            updateHeight();
        }
    }

    private void ProneInput()
    {
        if (Input.GetKeyDown(proneKey))
        {
            if (currentStance != CharacterStance.Prone)
            {
                currentStance = CharacterStance.Prone;
            }
            else
            {
                currentStance = CharacterStance.Stand;
            }

            updateHeight();
        }
    }

    private void updateHeight()
    {
        switch (currentStance)
        {
            case CharacterStance.Stand:
                charController.height = 2.0f;
                break;
            case CharacterStance.Crouch:
                charController.height = 1.5f;
                break;
            case CharacterStance.Prone:
                charController.height = 1.0f;
                break;
        }
    }


}

And the camera that is attached to the PlayerBody

public class PlayerLook : MonoBehaviour
{
    [SerializeField] private string mouseXInputName, mouseYInputName;
    [SerializeField] private float mouseSensitivity;

    [SerializeField] private Transform playerBody;

    private float xAxisClamp;

    private void Awake()
    {
        LockCursor();
        xAxisClamp = 0.0f;
    }



    private void LockCursor()
    {
        Cursor.lockState = CursorLockMode.Locked;
    }

    private void Update()
    {
        CameraRotation();
    }

    private void CameraRotation()
    {
        float mouseX = Input.GetAxis(mouseXInputName) * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis(mouseYInputName) * mouseSensitivity * Time.deltaTime;

        xAxisClamp += mouseY;

        if (xAxisClamp > 90.0f)
        {
            xAxisClamp = 90.0f;
            mouseY = 0.0f;
            ClampXAxisRotationToValue(270.0f);
        }

        else if (xAxisClamp < -90.0f)
        {
            xAxisClamp = -90.0f;
            mouseY = 0.0f;
            ClampXAxisRotationToValue(90.0f);
        }

        transform.Rotate(Vector3.left * mouseY);
        playerBody.Rotate(Vector3.up * mouseX);
    }

    private void ClampXAxisRotationToValue(float value)
    {
        Vector3 eulerRotation = transform.eulerAngles;
        eulerRotation.x = value;
        transform.eulerAngles = eulerRotation;
    }
   


}