Home > Enterprise >  make player slow down when turning mid air
make player slow down when turning mid air

Time:04-26

I wanted to do a jump similar to super mario bros meaning you can move mid air but if you move in the opposite direction that you started your jump in you will slow down. For example if u jump in the right direction but move to the left midair u can move to the left but very slowly. I tried doing it by adding a if clause that checks if the player is moving to the left and then half the player speed but for some reason that didn't work. Thanks in advance! Here's my code:

private Rigidbody rb;
[SerializeField] private float jumpForce;
[SerializeField] private float playerSpeed;
private float distToGround = 0.0051904f;
public bool isGrounded = false;
private bool _jump;
private float _horizontal;
private bool _movingLeft;
private bool _movingRight;
private bool _turnedLeft;
private bool _turnedRight;
private BoxCollider playerFeet;

private void Awake()
{
    rb = gameObject.GetComponent<Rigidbody>();
}

private void Start()
{

}

private void Update()
{
    GetInputs();
}

private void FixedUpdate()
{
    //PlayerJump
    if (_jump && _turnedRight == true)
    {
        transform.rotation = Quaternion.Euler(0, 0, 0);
        rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
        _jump = false;
    }
    else if (_jump && _turnedLeft == true)
    {
        transform.rotation = Quaternion.Euler(0, -180, 0);
        rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
        _jump = false;
    }

    //RotatePlayerDependingWhereHeMoves
    if(_movingLeft == true && isGrounded)
    {
        gameObject.transform.rotation = Quaternion.Euler(0f, 180f, 0f);
        _movingLeft = false;
    }

    if (_movingRight == true && isGrounded)
    {
        gameObject.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
        _movingRight = false;
    }

    //MovePlayer
    rb.velocity = new Vector3(rb.velocity.x, rb.velocity.y, _horizontal * -playerSpeed);

    //ChecksIfGrounded
    GroundCheck();
}

void GetInputs()
{
    _horizontal = Input.GetAxisRaw(Tags.HORIZONTAL_AXIS);

    if(isGrounded && Input.GetKeyDown(KeyCode.Space))
    {
        Debug.Log("Player pressed Jump");
        _jump = true;
    }

    if(_horizontal == -1)
    {
        _movingLeft = true;
    }
    else if(_horizontal == 1)
    {
        _movingRight = true;
    }

    if(transform.rotation.y == 0)
    {
        _turnedRight = true;
    }
    else if(transform.rotation.y == -180)
    {
        _turnedLeft = true;
    }
}


void GroundCheck()
{
    if(Physics.Raycast(transform.position, Vector3.down, distToGround   0.1f))
    {
        isGrounded = true;
    }
    else
    {
        isGrounded = false;
    }
}

CodePudding user response:

Compare the input to the current direction the rigidbody is moving when mid-air. Then, chip away at the speed at a desired rate. You can do this inside a different method.

private void FixedUpdate()
{
    //PlayerJump
    if (_jump && _turnedRight == true)
    {
        transform.rotation = Quaternion.Euler(0, 0, 0);
        rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
        _jump = false;
    }
    else if (_jump && _turnedLeft == true)
    {
        transform.rotation = Quaternion.Euler(0, -180, 0);
        rb.AddForce(new Vector3(0, jumpForce), ForceMode.Impulse);
        _jump = false;
    }

    //RotatePlayerDependingWhereHeMoves
    if(_movingLeft == true && isGrounded)
    {
        gameObject.transform.rotation = Quaternion.Euler(0f, 180f, 0f);
        _movingLeft = false;
    }

    if (_movingRight == true && isGrounded)
    {
        gameObject.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
        _movingRight = false;
    }

    //MovePlayer
    if (!isGrounded)
    {
        //since the player is not touching the ground, modify speed in here
        ModifyMidAirSpeed();
    }
    else
    {
        //move player normally...
        rb.velocity = new Vector3(rb.velocity.x, rb.velocity.y, _horizontal * -playerSpeed);
    }

    //ChecksIfGrounded
    GroundCheck();
}

float air_speed_acceleration = 1.0f; //use this to change the rate at which speed is modified mid-air
void ModifyMidAirSpeed()
{
    Vector3 new_velocity = rb.velocity;
    //check if the rb's is moving on the horizontal axis
    if (rb.velocity.x != 0)
    {
        //is the moving direction the same as the input?
        bool isRBMovingRight = rb.velocity.x > 0;
        if (isRBMovingRight && _movingRight)
        {
            //yes it is
            //accelerate mid-air?
            new_velocity.x = Mathf.Lerp(new_velocity.x, _horizontal * -playerSpeed, air_speed_acceleration * Time.fixedDeltaTime);
            rb.velocity = new_velocity;
            return;
        }
        //no it is not!
        //slow down mid-air
        new_velocity.x = Mathf.Lerp(0, new_velocity.x, air_speed_acceleration * Time.fixedDeltaTime);
        rb.velocity = new_velocity;
        return;
    }
    //the player jumped while standing still
    //move towards desired direction mid-air?
    new_velocity.x = Mathf.Lerp(0, _horizontal * -playerSpeed, air_speed_acceleration * Time.fixedDeltaTime);
    rb.velocity = new_velocity;
}

Above, I wrote an example which should allow you to reduce the player's velocity mid-air. You can use the method ModifyMidAirSpeed when the player is not touching the ground to handle mid-air movement and keep your code separated and tidy.

I would also recommend storing input as a Vector2. This will allow you to use fewer variables (I'm talking about _movingLeft and _movingRight) and should prove helpful in the future.

CodePudding user response:

  public class PlayMovement : MonoBehaviour
  {
  //Character's blood volume
   public int Hp = 1;
  // is it on the ground
   private bool isGround = false;
   //rigid body
   private Rigidbody2D rBody;
 //animation
   private Animator ani;
 //Get the sprite image (in order to flip the image later)
   private SpriteRenderer sr;

   void Start () {
    //Get these two components here
    rBody = GetComponent<Rigidbody2D>();
    ani = GetComponent<Animator>();
    sr = GetComponent<SpriteRenderer>();
   }


   void Update() {
      if (Hp <= 0)
      {
           return;
      }
      //Because the character just runs left and right, take the horizontal axis
      float horizontal = Input.GetAxis("Horizontal");
      //if the horizontal axis is not 0
      if (horizontal != 0)
      {
        //go ahead
        transform.Translate(transform.right * Time.deltaTime * 1 * horizontal);
        //Flip the picture (simulate turning the head)
        if (horizontal > 0)
        {
            //The description is to go to the right, so it does not flip
            sr.flipX = false;
        }
        if (horizontal < 0)
        {
            sr.flipX = true;
        }
        //move animation
        ani.SetBool("Run", true);
      }
      else
      {
        ani.SetBool("Run", false);
      }
      //jump. The I key is pressed, and the character is standing on the ground.
      if (Input.GetKeyDown(KeyCode.I) && isGround == true)
      {
        //Jump force (up, acting on rigid body)
        rBody.AddForce(Vector2.up * 200);
        //Play the jump sound
        AudioManager.Instance.PlaySound("jump");
      }
   
      //Use the ray to detect whether it touches the ground (method 1)
      //Draw the ray. Starting from the center point, go down *0.1 meters.
      Debug.DrawRay(transform.position, Vector2.down * 0.1f);
       /* Create 2d rays. Features: You can return directly. 3d returns a boolean value, hit is on it, and out is used to give the hit value.
        And in the brackets, you can directly fill in the starting point, direction, distance, and detection layer of the ray (here is the 8th layer). */
    
      RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, 0.1f, 1<<8);
     if(hit.collider != null)
     {
       //Indicate that it hit the ground
       isGround = true;
       //Turn off the jump animation
       ani.SetBool("Jump", false);
     }
     else
     {
       // did not touch the ground (in the air)
       isGround = false;
       ani.SetBool("Jump", true);
     }
  }

  //The player's death method, because it is called in the enemy's code, is public here
   public void Die()
   {
      Hp--;
       if (Hp <= 0)
      {
        //die
        ani.SetTrigger("Die");
        // delete the collider. (Because when the player dies, it is dropped from the scene, so just delete the collider, not the rigid body).
        Destroy(GetComponent<Collider2D>());
        //stop playing background music
        AudioManager.Instance.StopMusic();
        //play death music
        AudioManager.Instance.PlaySound("death");
        // make the player still
        rBody.velocity = Vector2.zero;
        // Make the player still, i.e. set its speed to 0. In order to prevent the player from dying in different situations, the height of the upward jump is different)
        rBody.velocity = Vector2.zero;
        //jump. give an upward force
        rBody.AddForce(Vector2.up * 150f);
        // Delay. Play after 1 second
        Invoke("Die2", 1f);
      }
   }
      void Die2()
      {
       AudioManager.Instance.PlaySound("Death 2");
      }
  }

Here's the script code for Mario PlayControl, hope it helps, as you provide the code to test it's hard

  • Related