Crouch and Run Booleans cancelling each other out

I am making a 2D game and ran into a problem where if I try to setup parameters for my isRunning to make my character run, it seems to stop the crouch from changing the speed of my character but lets my crouch input disable my collider still. If I disable or take out the code for my isRunning so that he cannot run, my crouch speed works just fine and vice versa. Most likely a problem with my code as I am very new but any tips or solutions is greatly appreciated :slight_smile:

lines to look at would be around 71-139

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    //The speed our player will move
    [SerializeField] private float _speed = 3f;
    [SerializeField] private float _jumpSpeed = 15f;
    [SerializeField] private float _airborneSpeed = 0.25f;
    [SerializeField] private float _runSpeed = 5f;
    [SerializeField] private float _defaultSpeed = 3f;

   [Header("Ground Check Values")]
    [SerializeField] private float _groundCheckDistance = 0.15f;
    [SerializeField] private float _verticalOffsetModifier = -1.75f;
    [SerializeField] private float _horizontalOffset = 0.1f;
    [SerializeField] private LayerMask _layerMask;
   
   
    private void Awake()
    {
       
    }
    //the attatced Rigidbody2D on our gameobject
    private Rigidbody2D _rigidbody2D;
    private SpriteRenderer _spriteRenderer;
    public Animator _animator;
    [SerializeField] Collider2D standingcollider;
   

    //Read input from our keyboard on the X, Y Axis
    private float _input;
    private bool _isJumping;
    public bool _isGrounded;
    private bool _isFlipped;
    private bool isRunning;
    private bool crouch;
    public Transform attackPointTransform;
    private void Start()
    {
   GameObject attackpoint = AttackPoint.attackpoint;
        _rigidbody2D = GetComponent<Rigidbody2D>();
        _spriteRenderer = GetComponentInChildren<SpriteRenderer>();
        _animator = GetComponentInChildren<Animator>();
    }

    private void Update()
    { 
        HandleInput();

        _animator.SetFloat("Speed", Mathf.Abs(_input));
        _animator.SetBool("Jump", _isGrounded);

        // store movement from horizontal axis of controller
        Vector2 move = Vector2.zero;
        move.x = Input.GetAxis("Horizontal");

 
        if(_input > 0)
        {
            _isFlipped = false;
        }
        else if(_input < 0)
        {
           _isFlipped = true;
        }

        _spriteRenderer.flipX = _isFlipped;

        if (Input.GetKeyDown(KeyCode.S) && _isGrounded)
        {
            crouch = true;

        }
        else if (Input.GetKeyUp(KeyCode.S))
        {
            crouch = false;
        }

        if (Input.GetKeyDown(KeyCode.LeftShift) && _isGrounded)
        {
                isRunning = true;   
        }else if (Input.GetKeyUp(KeyCode.LeftShift ))
       {
            isRunning = false;
        }

    }

    // determine direction of character



    private void FixedUpdate()
    {
        _isGrounded = Checkgrounded(_horizontalOffset) || Checkgrounded(-_horizontalOffset);
        HandlePhysics();

        _isJumping = false;

    }


private void HandleInput()
    {
        _input = Input.GetAxis("Horizontal");

        //An "if" checks the brackets beside it and, if true, executes the code within its scope
        if (Input.GetButtonDown("Jump") && _isGrounded)
        {
            //As long as you make a new variable as a part of an equation, you can auto generate it with CTRL + Period
            _isJumping = true;
        }

        if(_isGrounded && crouch)
        {
            standingcollider.enabled = false;
        }else
        {
            standingcollider.enabled = true;
        }

        if (crouch)
        {
            _speed = 1.5f;
        }
        else
        {
            _speed = _defaultSpeed;
        }
      if (isRunning)
        {
            _speed = _runSpeed;
        }
        else
        {
            _speed = _defaultSpeed;
        }
    }


    /// <summary>
    /// Sets the player xVelocity based on _input,
    /// and sets the player yVelocity based on _isJumping
    /// </summary>
    private void HandlePhysics()
    {

        float speed = _isGrounded ? _speed : _speed * _airborneSpeed;

       // if(_isGrounded = false)
       // {
        //    _speed = _airborneSpeed;
       // }
       // else
       // {
       //     _speed = 8f;
        //}

        //Add force adds force each time it's called to the referenced rigidbody
        //_rigidbody2D.AddForce(new Vector2(_input * _speed, 0f));
        float xVelocity = _input * speed;

        //A ?' used as part of an equation, acts as an if/else statement
        // where if the equation/bool to the left of the ? is true
        //the value is set to what's written in the left of the ':', else it'll
        //use whats written to the right of the ':'
        float yVelocity = _isJumping ? _jumpSpeed : _rigidbody2D.velocity.y;

        //if (_isJumping == true)
        //{
        //    yVelocity = _jumpSpeed;
        //}
        ////An else is executed only when the above "if" is false
        //else
        //{
        //    yVelocity = _rigidbody2D.velocity.y;
        //}

        //A Vector2 is a type that contains 2 floats. A x value and a y value
        Vector2 newVelocity = new Vector2(xVelocity, yVelocity);

        //Velocity directly refertences the current velocity of the rigidbody
        // using = you can directly change the current velocity of the rigidbody
        _rigidbody2D.velocity = newVelocity;


        if (_isFlipped == true)
        {
            //attackPointTransform.transform.position = new Vector3(transform.position.x * -1, transform.position.y, transform.position.z);
            // AttackPoint.Getcomponent<AttackPoint>().Positionconstraint = enabled;
            attackPointTransform.transform.eulerAngles = new Vector3(0, 180, 0);
           
           
        }
        if (_isFlipped != true)
        {
            attackPointTransform.transform.eulerAngles = new Vector3(0, 0, 0);
        }
       
       
    }

    private bool Checkgrounded(float groundCheckOffset)
    {
        Vector2 offset = new Vector2(groundCheckOffset, _groundCheckDistance * _verticalOffsetModifier);

        Vector2 origin = offset + (Vector2)transform.position;

        if(Physics2D.Raycast(origin, Vector2.down, _groundCheckDistance, _layerMask))
        {
            Debug.DrawRay(origin, Vector2.down * _groundCheckDistance, Color.green);
           
            return true;
        }
        else
        { 
            Debug.DrawRay(origin, Vector2.down * _groundCheckDistance, Color.red);
            return false;
        }
    }

   
}

Here is how you can find out what those lines are actually doing in your actual project. This approach is almost always more successful than staring at a wall of code.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

You must find a way to get the information you need in order to reason about what the problem is.

If you just want an FPS controller, here is a super-basic starter prototype FPS based on Character Controller (BasicFPCC):

https://discussions.unity.com/t/855344

Notably it does crouch and run so you can see how it is deconflicted.

Thank you so much! that is great information and I am grateful for what you do for the community :slight_smile:

1 Like