Looking to Adjust My Dash Mechanic

I recently added in a very basic “dash” to my player character using the transform.Translate function, and I tried adjusting it because this function obviously makes the dash very rigid and quick. This is the current code:

private float horizontalInput;
private Rigidbody2D rigidbodyComponent;

private bool hasMoved;
private bool facingForward;

[SerializeField] private float dashDistance = 5f;

void Start()
{
      rigidbodyComponent = GetComponent<Rigidbody2D>();
      facingForward = true;
}

void Update()
{
      horizontalInput = Input.GetAxis("Horizontal");
   
      if (horizontalInput != 0)
      {
             hasMoved = true;
      }

      if (Input.GetKeyDown(KeyCode.LeftShift))
      {
             if (facingForward)
             {
                    rigidbodyComponent.velocity += Vector2.right * dashDistance;
                    //transform.Translate(Vector2.right * dashDistance);
             }
             else
             {
                    rigidbodyComponenet.velocity += -Vector2.right * dashDistance;
                    //transform.Translate(Vector2.left * dashDistance);
             }
      }
}

private void FixedUpdate()
{
     if (hasMoved)
     {
            if (horizontalInput > 0.0001)
            {
                facingForward = true;
            }

            if (horizontalInput < -0.0001)
            {
                facingForward = false;
            }
     }

The commented section of the LeftShift key press is the code I had that worked previously, but was very clunky (especially when checking the facingForward bool). With this new Rigidbody force adjustment, I’m getting very tiny results, as I jump around and move with my character, all the button press seems to do is delay my fall in the air for a moment.

Could this possibly be due to my horizontal player movement? It works like this:

 rigidbodyComponent.velocity = new Vector2(horizontalInput * moveSpeed, rigidbodyComponent.velocity.y);

If not, I’m unsure what might be causing this reduction in dash distance compared to my previous method.

I will gladly answer any clarification questions! Thank you for your time reading this post and any help is greatly appreciated!

If you are setting velocity once for the dash, and then setting it again for your movement control (or setting it in the immediate next frame), then the second time you set it will essentially overwrite the first. You might try setting a bool isDashing to true when you start dashing, and then do some kind of check to see if the dash is complete, and set it back to false if so (and only allow a dash to start if isDashing is false). And on your player movement input, only set rigidbodyComponent.velocity to a new value if isDashing is false. One possible way to do that might be to store your dash start x position in a float when you start the dash, then every frame while isDashing is true, check the absolute value difference between dash start x and current x, and if it is greater than or equal to dashDistance, the dash is complete so you set isDashing back to false.

One other note, if you are setting the velocity now instead of a translation distance, you will probably want to change your variable name appropriately, or have two variables, one for dashVelocity (which you set the velocity equal to) and one for dashDistance (used as mentioned above to see if the character has reached the full distance of their dash).

Hopefully all that made sense.

I understand the logic here, I’m just struggling to implement this into my program to net me the results I want. I adjusted my code to add in a bool isDashing, since this is the primary variable that can prevent this immediate override of the player’s velocity. The one part I haven’t tried incorporating is the dash check your talking about. My new code looks like this now:

private float horizontalInput;
private Rigidbody2D rigidbodyComponent;

private bool hasMoved;
private bool facingForward;
private bool isDashing;

[SerializeField] private float dashSpeed = 5f;

void Start()
{
      rigidbodyComponent = GetComponent<Rigidbody2D>();
      facingForward = true;
}

void Update()
{
      horizontalInput = Input.GetAxis("Horizontal");
 
      if (horizontalInput != 0)
      {
             hasMoved = true;
      }

      if (Input.GetKeyDown(KeyCode.LeftShift))
      {

             isDashing = true;

             if (facingForward)
             {
                    rigidbodyComponent.velocity = Vector2.right * dashSpeed;
                    isDashing = false;
             }
             else
             {
                    rigidbodyComponenet.velocity = Vector2.left * dashSpeed;
                    isDashing = false;
             }
      }
}

private void FixedUpdate()
{
     if (hasMoved)
     {
            if (horizontalInput > 0.0001)
            {
                facingForward = true;
            }

            if (horizontalInput < -0.0001)
            {
                facingForward = false;
            }

     if (!isDashing)
     {
            rigidbodyComponent.velocity = new Vector2(horizontalInput * moveSpeed, rigidbodyComponent.velocity.y);
     }

So in this scenario, I’m adjusting the isDashing based on a key-press. This sadly still gives me similar results to what I had before, even though the horizontal movement has now been adjusted to consider if the player isDashing. I feel like this is now a speed problem, as in terms of what code is being run through first. Is it possible that having code in the FixedUpdate() function is too slow to process the adjustments done in the Update() function?

Yeah, you can’t rely on Update and FixedUpdate running in a specific order relative to each other. I also wouldn’t put the velocity change in both Update and FixedUpdate, you probably want to only set it in one or the other, to keep things consistent. Check out the first two minutes of this video to get an idea of the difference between the two (and notice the comments in the code that mention examples of what you generally want to use the two for):

I believe the other part of the problem is that you are still setting the velocity again on the very next frame, because you are setting isDashing to false right away. I think it might be helpful to define conceptually how you want your dash to work and then try to put it into pseudocode, and work out in your mind how that would play out on a frame by frame basis. Once you figure that out, you can translate it into actual code. To kind of explain what I mean here (and point out what I think your current problem is), here is an example. Right now, and before, your code was doing something like the following:

Frame when Left Shift is pressed:
Set velocity to dashing velocity

Next frame:
Set velocity to normal velocity based on horizontal input

So your velocity is only being set to your dashing velocity for one single frame, before being set back to normal on the next frame. This is why you either need some sort of timer, or a distance check, to see if you should set isDashing back to false.

One potential problem if you use the distance check, is that if your game has obstacles like walls and you try dashing against one of them, you would continue dashing since you never get to the expected distance from your starting distance. So if you went that route you would need an additional check for that, to cancel it if you collide with something.

The “timer” route may be a better option for now. Here’s an example in English of what that might look like, which you can translate into actual code:

New Variables:
float fullDashTime for dash timer to be set to, maybe start it at something like 0.5f (half a second) and adjust from there based on how it feels
float currentDashTimer to track how long current dash has been going, set this to 0 to start with

Update method:
If currentDashTimer is greater than or equal to 0:
Subtract Time.deltaTime from currentDashTimer
Else:
Set isDashing to false

If left shift pressed and isDashing is false:
Set isDashing to true
Set currentDashTimer to fullDashTime

Fixed Update method:
If isDashing:
Set velocity to dashSpeed (like you already are, based on facing forward or back)
Else:
Set velocity as normal based on input