Home > front end >  Player Jumping Twice On Lower Framerate When Mashing Space
Player Jumping Twice On Lower Framerate When Mashing Space

Time:02-16

First of all I want to apologise for my English cause I come from Poland and I'm still learning. I'm a beginner C#/Unity programmer and I have a pretty stupid/noob question/issue where player jumps twice when mashing the space. When the framerate is low for ex. 30, the problem occurs almost everytime and when framerate is for ex. 144 - hardly ever. I did some research and tried different methods. Firstly I checked whether I have all my inputs in Update and not FixedUpdate. That wasn't the problem at all. Then I tried replacing Input.GetKey to Input.GetKeyDown and GetKeyUp in Update as to ensure I have my boolean _spacePressed checked or not. That wasn't the solution too. The third thing I tried was to use Raycasting to check whether the player is grounded. With that I also checked whether when I jump, ray doesn't get checked twice. To make things clear I'm currently trying to make a 2.5D platformer. So to sum up I'm asking what could be the main issue (with input probably) where player jumps twice or even three times in a single frame when mashing space. Here's also my prototype code. I used enums to make a simple state "machine". If you have also any advice for me and my code to make things better apart from my question I would love to hear them. Thank you in advance!

using UnityEngine;

public class Movement : MonoBehaviour
{
    [Header("Start Properties")]
    [SerializeField] private Transform _playerTransform;
    [SerializeField] private Rigidbody _playerRigidbody;

    private enum MovementStates { reset, idle, walking, walkingInAir, sprinting, jumping };
    private MovementStates _currentState;

    [Header("Player Height Adjustables")]
    [SerializeField] CapsuleCollider _playerCollider;
    [SerializeField] private float _reducedHeight;
    private float _originalHeight;

    [Header("Player Rotation Adjustables")]
    [SerializeField] private float _rotationSpeed;
    Quaternion _from;
    Quaternion _to;

    [Header("Input Properties")]
    private float _xAxis;
    private bool _rightLook, _leftLook;
    private bool _idle, _walking, _walkingInAir, _sprinting, _reset;
    private bool _leftShiftPressed;
    private bool _spacePressed;

    [Header("Player Movement Adjustables")]
    [SerializeField] private float _walkingSpeedMultiplier;
    [SerializeField] private float _maximumWalkingSpeed;
    [SerializeField] private float _walkingInAirSpeedMultiplier;
    [SerializeField] private float _maximumWalkingInAirSpeed;
    [SerializeField] private float _sprintingSpeedMultiplier;
    [SerializeField] private float _maximumSprintingSpeed;
    [SerializeField] private float _deaccelerationMultiplier;

    [Header("Smooth Damp Adjustables")]
    [SerializeField] private float _smoothTime;
    private Vector3 _currentVelocity;
    private Vector3 _smoothAxis;

    [Header("Player Jump Adjustables")]
    [SerializeField] private float _jumpMultiplier;
    private bool _jumping;

    [Header("Ground Check Adjustables")]
    [SerializeField] private LayerMask _groundCheck_Layer;
    [SerializeField] private float _distanceGroundCheck;
    private Ray _groundCheck_Ray;
    private RaycastHit _groundCheck_HitInfo;
    private bool _grounded;

    private void Awake()
    {
        _originalHeight = _playerCollider.height;
    }

    // input and ground checks
    private void Update()
    {
        Process_Input();
        Process_Rotation();
        GroundRay_Check();
    }
    private void Process_Input()
    {
        _xAxis = Input.GetAxisRaw("Horizontal");
        _rightLook = (_xAxis > 0) ? _rightLook = true : _rightLook = false;
        _leftLook = (_xAxis < 0) ? _leftLook = true : _leftLook = false;

        if (Input.GetKeyDown(KeyCode.LeftShift)) _leftShiftPressed = true;
        if (Input.GetKeyUp(KeyCode.LeftShift)) _leftShiftPressed = false;
        if (Input.GetButtonDown("Jump")) _spacePressed = true;
        if (Input.GetButtonUp("Jump")) _spacePressed = false;

        _idle = (_xAxis == 0 && _grounded) ? _idle = true : _idle = false;
        _walking = (_xAxis != 0 && !_leftShiftPressed && _grounded) ? _walking = true : _walking = false;
        _walkingInAir = (_xAxis != 0 && !_grounded) ? _walkingInAir = true : _walkingInAir = false;
        _sprinting = (_xAxis != 0 && _leftShiftPressed && _grounded) ? _sprinting = true : _sprinting = false;
        _jumping = (_spacePressed && _grounded) ? _jumping = true : _jumping = false;
        _reset = (!_idle && !_walking && !_walkingInAir && !_sprinting && !_jumping) ? _reset = true : _reset = false;

        if (Input.GetKeyDown(KeyCode.Alpha1)) Application.targetFrameRate = 30;
        if (Input.GetKeyDown(KeyCode.Alpha2)) Application.targetFrameRate = 60;
        if (Input.GetKeyDown(KeyCode.Alpha3)) Application.targetFrameRate = 120;
        if (Input.GetKeyDown(KeyCode.Alpha4)) Application.targetFrameRate = 144;
    }
    private void Process_Rotation()
    {
        if (_rightLook)
        {
            _from = _playerTransform.rotation;
            _to = Quaternion.Euler(0f, 0f, 0f);
            _playerTransform.rotation = Quaternion.Lerp(_from, _to, _rotationSpeed * Time.deltaTime);
        }
        else if (_leftLook)
        {
            _from = _playerTransform.rotation;
            _to = Quaternion.Euler(0f, 180f, 0f);
            _playerTransform.rotation = Quaternion.Lerp(_from, _to, _rotationSpeed * Time.deltaTime);
        }
    }
    private void GroundRay_Check()
    {
        _groundCheck_Ray.origin = _playerTransform.position;
        _groundCheck_Ray.direction = Vector2.down;

        Debug.DrawRay(_playerTransform.position, Vector2.down * _distanceGroundCheck, Color.green);
        _grounded = Physics.Raycast(_groundCheck_Ray, out _groundCheck_HitInfo, _distanceGroundCheck, _groundCheck_Layer, QueryTriggerInteraction.Ignore);
    }

    // movement by states
    private void FixedUpdate()
    {
        Process_States();
    }
    private void Process_States()
    {
        if (_idle) _currentState = MovementStates.idle;
        if (_walking) _currentState = MovementStates.walking;
        if (_walkingInAir) _currentState = MovementStates.walkingInAir;
        if (_sprinting) _currentState = MovementStates.sprinting;
        if (_jumping) _currentState = MovementStates.jumping;
        if (_reset) _currentState = MovementStates.reset;

        switch (_currentState)
        {
            case MovementStates.idle:
                Process_Idle();
                break;
            case MovementStates.walking:
                Process_Walking();
                break;
            case MovementStates.walkingInAir:
                Process_WalkingInAir();
                break;
            case MovementStates.sprinting:
                Process_Sprinting();
                break;
            case MovementStates.jumping:
                Process_Jumping();
                break;
            case MovementStates.reset:
                print("resetting");
                return;
        }
    }
    private void Process_Idle()
    {
        print("currently idle");
        _playerCollider.height = _originalHeight;
        Deaccelerate(_deaccelerationMultiplier);
    }
    private void Process_Walking()
    {
        print("currently walking");
        Move(_walkingSpeedMultiplier, _maximumWalkingSpeed, ForceMode.Force);
    }
    private void Process_WalkingInAir()
    {
        print("currently walking in air");
        Move(_walkingInAirSpeedMultiplier, _maximumWalkingInAirSpeed, ForceMode.Force);
    }
    private void Process_Sprinting()
    {
        print("currently sprinting");
        Move(_sprintingSpeedMultiplier, _maximumSprintingSpeed, ForceMode.Force);
    }
    private void Process_Jumping()
    {
        print("currently jumping");
        Jump(_jumpMultiplier, ForceMode.VelocityChange);
        _spacePressed = false;
    }


    // movement functions
    private void Move(float _speedMultiplier, float _maximumSpeed, ForceMode _forceMode)
    {
        CapMaximumSpeed(_maximumSpeed);
        Vector2 _getAxisDirection = _xAxis * Vector2.right;
        Vector2 _normalizeAxis = _getAxisDirection.normalized;
        Vector2 _multiplyAxis = _normalizeAxis * _speedMultiplier * Time.deltaTime;
        _smoothAxis = Vector3.SmoothDamp(_multiplyAxis, _smoothAxis, ref _currentVelocity, _smoothTime);
        _playerRigidbody.AddForce(_smoothAxis, _forceMode);
    }
    private void CapMaximumSpeed(float _maximumSpeed)
    {
        float _cappedXVelocity = Mathf.Min(Mathf.Abs(_playerRigidbody.velocity.x), _maximumSpeed) * Mathf.Sign(_playerRigidbody.velocity.x);
        float _cappedYVelocity = _playerRigidbody.velocity.y;

        _playerRigidbody.velocity = new Vector3(_cappedXVelocity, _cappedYVelocity, 0);
    }
    private void Deaccelerate(float _deaccelerationMultiplier)
    {
        float _currentSpeed = _playerRigidbody.velocity.magnitude;
        float _newSpeed = _currentSpeed - _deaccelerationMultiplier;
        if (_newSpeed < 0) _newSpeed = 0;
        _playerRigidbody.velocity = _playerRigidbody.velocity.normalized * _newSpeed;
    }
    private void Jump(float _jumpMultiplier, ForceMode _forceMode)
    {
        Vector2 _direction = Vector2.up;
        Vector2 _multiplyDirection = _direction * _jumpMultiplier;
        _playerRigidbody.AddForce(_multiplyDirection, _forceMode);
    }
}

CodePudding user response:

Keep in mind that FixedUpdate() can happen a few times within a single frame. Check if _spacePressed == true in the beginning of your Process_Jumping().

  • Related