Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only. On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live. Read our full announcement for more information and let us know if you have any questions.

Resolved Smash and Dive Issues

Discussion in '2D' started by Ehchdhqwagads, May 28, 2024.

  1. Ehchdhqwagads

    Ehchdhqwagads

    Joined:
    Mar 16, 2024
    Posts:
    5
    I'm making a 2D platformer, and this is the player script:
    Code (CSharp):
    1. public float moveSpeed;
    2. public float accelerationMod;
    3. public float jumpForce;
    4. public float smashForce;
    5. public float diveForce;
    6. public LayerMask ground;
    7.  
    8. private Rigidbody2D Rigidbody;
    9.  
    10. private float horizontalInput;
    11. private Vector2 direction;
    12.  
    13. private bool onGround;
    14. private bool ignoreHorizontalInput;
    15. private bool diving;
    16.  
    17. void Start()
    18. {
    19.     Rigidbody = GetComponent<Rigidbody2D>();
    20. }
    21.  
    22. void Update()
    23. {
    24.     if (!ignoreHorizontalInput)
    25.     {
    26.         horizontalInput = Input.GetAxisRaw("Horizontal");
    27.     }
    28.     else
    29.     {
    30.         horizontalInput = 0;
    31.     }
    32.  
    33.     if (horizontalInput != 0)
    34.     {
    35.         direction = new Vector2(horizontalInput, 0);
    36.     }
    37. }
    38.  
    39. void FixedUpdate()
    40. {
    41.     Rigidbody.AddForce(Vector2.right * moveSpeed * horizontalInput * accelerationMod);
    42.     if (Mathf.Abs(Rigidbody.velocity.x) > moveSpeed)
    43.     {
    44.         Rigidbody.velocity = new Vector2(Mathf.Sign(Rigidbody.velocity.x) * moveSpeed, Rigidbody.velocity.y);
    45.     }
    46.  
    47.     onGround = Physics2D.Raycast(transform.position, Vector2.down, 1.05f, ground);
    48.  
    49.     if (onGround)
    50.     {
    51.         ignoreHorizontalInput = false;
    52.         diving = false;
    53.     }
    54.  
    55.     if ((Input.GetKey(KeyCode.Space) || Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) && onGround)
    56.     {
    57.         Rigidbody.velocity = new Vector2(Rigidbody.velocity.x, 0);
    58.         Rigidbody.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
    59.     }
    60.  
    61.     if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.S))
    62.     {
    63.         if (onGround)
    64.         {
    65.             // Slide script to be added.
    66.         }
    67.         else
    68.         {
    69.             if (horizontalInput == 0 || diving)
    70.             {
    71.                 Rigidbody.velocity = Vector2.zero;
    72.                 Rigidbody.AddForce(Vector2.down * smashForce, ForceMode2D.Impulse);
    73.                 ignoreHorizontalInput = true;
    74.                 diving = false;
    75.             }
    76.             else
    77.             {
    78.                 Rigidbody.velocity = Vector2.zero;
    79.                 Rigidbody.AddForce(direction * diveForce, ForceMode2D.Impulse);
    80.                 ignoreHorizontalInput = true;
    81.                 diving = true;
    82.             }
    83.         }
    84.     }
    85. }
    The two main issues are the smash and dive. The smash works sometimes, but most of the time it doesn't register the input. I suspect that it's because of the way
    FixedUpdate()
    and
    Update()
    work. The dive has the same issue.
     
    Last edited: May 28, 2024
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,761
    This isn't a 2D or physics thing; input is updated per-frame and you're only checking it per fixed-update which clearly doesn't run per-frame. That'll likely be why your input isn't consistent. You could easily debug this yourself though which is where you should always start.

    https://docs.unity3d.com/Manual/ManagedCodeDebugging.html
     
  3. dstears

    dstears

    Joined:
    Sep 6, 2021
    Posts:
    241
    GetKeyDown is only valid on the frame that the key is pressed. Therefore, it can only be reliably read during Update(). When using physics to move the character, it is common to split up the reading of inputs and the change in velocity. Read the inputs in Update and apply the changes in FixedUpdate.

    For example:
    Code (CSharp):
    1.     [SerializeField] private Rigidbody2D myBody;
    2.     [SerializeField] private float jumpVelocity;
    3.     [SerializeField] private float maxSpeed;
    4.  
    5.     private Vector2 currentDirection = Vector2.zero;
    6.     private bool jumpRequested = false;
    7.     private bool isGrounded = true;
    8.  
    9.     // Input-reading functions like GetKeyDown are only valid on the frame
    10.     // that the key is pressed, so these need to be checked in Update.
    11.     void Update()
    12.     {
    13.         if(Input.GetKeyDown(KeyCode.Space))
    14.         {
    15.             jumpRequested = true;
    16.         }
    17.         currentDirection.x = Input.GetAxis("Horizontal");
    18.         currentDirection.y = Input.GetAxis("Vertical");
    19.     }
    20.  
    21.     //Changes to physics of the Rigidbody should be done in FixedUpdate
    22.     private void FixedUpdate()
    23.     {
    24.         isGrounded = CheckGrounded();
    25.         Vector2 targetVelocity = myBody.velocity;
    26.  
    27.         if(jumpRequested)
    28.         {
    29.             if(isGrounded)
    30.             {
    31.                 targetVelocity.y = jumpVelocity;
    32.             }
    33.             //You can optionally implement jump buffering here so that jump
    34.             //can be pressed just before landing, but this example is the simplest
    35.             //approach
    36.             jumpRequested = false;
    37.         }
    38.  
    39.         targetVelocity.x = currentDirection.x * maxSpeed;
    40.  
    41.         myBody.velocity = targetVelocity;
    42.     }
     
    Ehchdhqwagads and Kurt-Dekker like this.
  4. Ehchdhqwagads

    Ehchdhqwagads

    Joined:
    Mar 16, 2024
    Posts:
    5
    Thanks, but now that I can properly test the dive mechanic, it travels much too quickly and although it travels fast, it doesn't travel far. And if I try to increase the force, it's almost instantaneous:
    Code (CSharp):
    1. Rigidbody.velocity = Vector2.zero;
    2. Rigidbody.AddForce(direction * diveForce, ForceMode2D.Impulse);
    direction
    is a vector set by the last horizontal input:
    Code (CSharp):
    1. if (horizontalInput != 0)
    2. {
    3.     direction = new Vector2(horizontalInput, 0);
    4. }
     
    Last edited: May 31, 2024
  5. dstears

    dstears

    Joined:
    Sep 6, 2021
    Posts:
    241
    Since you are setting the velocity directly anyway, could you just set the exact velocity you want in the direction of the diveForce rather than using AddForce? Also, do you have a non-zero Linear Drag on your object which may reduce velocity over time?
     
  6. Ehchdhqwagads

    Ehchdhqwagads

    Joined:
    Mar 16, 2024
    Posts:
    5
    Ohhhhhhh wait there was an if statement that limited your x velocity so you didn't go too fast when moving but it still did so when diving:
    Code (CSharp):
    1. if (Mathf.Abs(Rigidbody.velocity.x) > moveSpeed)
    2. {
    3.     Rigidbody.velocity = new Vector2(Mathf.Sign(Rigidbody.velocity.x) * moveSpeed, Rigidbody.velocity.y);
    4. }
    So I changed it to:
    Code (CSharp):
    1. if (Mathf.Abs(Rigidbody.velocity.x) > moveSpeed && !diving)
    2. {
    3.     Rigidbody.velocity = new Vector2(Mathf.Sign(Rigidbody.velocity.x) * moveSpeed, Rigidbody.velocity.y);
    4. }
    And now it works.

    Thanks BTW