Home > Net >  How do I improve my dash in unity and not throw elements of the code around all the functions?
How do I improve my dash in unity and not throw elements of the code around all the functions?

Time:11-10

So, I'm fairly new to unity and coding. I'm currently coding a top down 2d game and wanted to add a dash mechanic. Couldn't find a tutorial that really suited me, so I decided to code it myself. And well.. it didn't go too well for such an easy mechanic. So here I come asking for help to improve the shitcode I have produced. I feel like there's a much easier way to do it, but my lack of experience doesn't allow me to notice it. The code works just as I want it to now, but I'm looking to simplify my code with the same output.

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

public class PlayerController : MonoBehaviour
{
    //run variables
    Rigidbody2D rb;
    float horizontal, vertical;
    public float runSpeed;

    //dash variables
    public float dashSpeed;
    public float startDashTime;
    public float currentDashTimer;
    public int dashDir;
    bool isDashing;
    bool shiftReplacement;
    float shiftHolder;




    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckIfShifted(); 
    }

    void FixedUpdate()
    {
        Dash();
    }

    public void CheckIfShifted()
    {
        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            shiftReplacement = true;
            shiftHolder = 0.08f;
        }
        else if(shiftHolder <= 0)
        {
            shiftReplacement = false;
        }
        shiftHolder -= Time.deltaTime;
    }
    public void Dash()
    {
            //check ín which direction player should dash
            if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
            {
                dashDir = 1;
            }
            else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
            {
                dashDir = 2;
            }
            else if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
            {
                dashDir = 3;
            }
            else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
            {
                dashDir = 4;
            }

            //check if player has pressed dash button and initiate dash
            if (shiftReplacement)
            {
                isDashing = true; //initiate dash
                currentDashTimer = startDashTime;
                rb.velocity = Vector2.zero;

            }

            //check if dash was initiated
            if (isDashing == true)
            {
                if (dashDir == 1)
                {
                    rb.velocity = transform.right * dashSpeed; //dash properties
                }
                else if (dashDir == 2)
                {
                    rb.velocity = transform.right * -1 * dashSpeed; //dash properties
                }
                else if (dashDir == 3)
                {
                    rb.velocity = transform.up * dashSpeed; //dash properties
                }
                else if (dashDir == 4)
                {
                    rb.velocity = transform.up * dashSpeed * -1; //dash properties
                }
                Debug.Log("bich Im dashin'");

                currentDashTimer -= Time.deltaTime;
            }
        if (currentDashTimer <= 0)
        {
            isDashing = false;
        }
    }

I've run into a variety of problems. For example like shift input not registering on time for the fixedupdate() to pick it up and or not registering at all. Or when I put everything inside the update() function my player didn't move. Any advice?

CodePudding user response:

  1. Why use an int and not simply directly store the desired vector in a

    private Vector2 dashDir;
    

    and then

    if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
    {
        dashDir = transform.right; 
    }
    else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
    {
        dashDir = -transform.right;
    }
    ...
    

    etc and later only use

    if(isDashing)
    {
        rb.velocity = dashDir * dashSpeed; 
    }
    
  2. Also by configuring your axis you could probably use

    var dashDir = Vector2.ClampMagnitude(new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")), 1f);
    

    instead of all the repeated Input checks.

    Per default the Horizontal axis refers to either the left/right keys or a/d and the Vertical refers to either up/down keys or w/s.

    enter image description here

So you could actually simply do

Vector2 dashDir;

private void Update()
{
    if (Input.GetKeyDown(KeyCode.LeftShift))
    {
        shiftReplacement = true;
    }
    // the resetting of this flag is handled by the Dash itself see below
}

private void FixedUpdate()
{
    Dash();
}

private void Dash()
{
    // ignore the input if you already are dashing
    if (!isDashing)
    {
        if(shiftReplacement)
        {
            isDashing = true; //initiate dash
            currentDashTimer = startDashTime;
            rb.velocity = Vector2.zero;

            // according to your Input settings this can already cover both arrow keys and WASD, by default that is the case
            var input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
            // you want to limit the vector to a maximum magnitude of 1 so diagonal movement is not faster than movement on a single axis
            dashDir = Vector2.ClampMagnitude(input, 1f);
        }
    }
    else
    {
        rb.velocity = dashDir * dashSpeed; 

        // in general avoid logging too often
        //Debug.Log("bich Im dashin'");

        currentDashTimer -= Time.deltaTime;

        if (currentDashTimer <= 0)
        {
            isDashing = false;
        }
    }  

    // you probably want to handle this only exactly once
    // => instead of resetting this time based in Update rather do it right after eventually handling it here
    shiftReplacement = false;
}

I would btw then also change your Shift input and rather use a Coroutine using WaitForFixedUpdate like this

bool isDashing;

private void Update()
{
    // Ignore input when already dashing
    if (!isDashing && Input.GetKeyDown(KeyCode.LeftShift))
    {
        // Get the dash direction ONCE
        var input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
        var direction = Vector2.ClampMagnitude(input, 1f);
        
        // start a coroutine for dashing into this direction
        // => direction can't be changed until dashing has finished
        StartCoroutine(DashRoutine(direction));
    }
}

private void DashRoutine(Vector2 direction)
{
    // just in case if we already are dashing do nothing
    if(isDashing) yield break;

    // set dashing flag so no other concurrent routine can be started
    isDashing = true;

    // This is handy way for writing a while loop with a timer
    // basically this is executed every fixeUpdate for startDashTime seconds
    for(var timePassed = 0f; timePassed < startDashTime; timePassed  = Time.deltaTime)
    {
        // wait for the next FixedUpdate call
        yield return new WaitForFixedUpdate();

        rb.velocity = direction * dashSpeed;
    }

    // finally release the flag so the next dashing can be triggered
    isDashing = false;
}

this gets rid of all your timer and direction fields entirely and bundles the behavior and variables together. Also this way you don't all the time get the FixedUpdate and Dash all even though most of time it isn't used anyway. The Coroutine only gets invoked when actually needed.

CodePudding user response:

I fixed a couple of complier errors unity gave me and this is what I have now. But the code still doesn't make the player dash. What's wrong with the code? Here's the code as it is now @derHugo:

public class AltDashScript : MonoBehaviour
{
    Rigidbody2D rb;

    Vector2 dashDir;

    public float dashSpeed;
    bool isDashing;
    public float startDashTime;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        isDashing = false;
    }

    private void Update()
    {
        // Ignore input when already dashing
        if (!isDashing && Input.GetKeyDown(KeyCode.LeftShift))
        {
            // Get the dash direction ONCE
            var input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
            var direction = Vector2.ClampMagnitude(input, 1f);

            // start a coroutine for dashing into this direction
            // => direction can't be changed until dashing has finished
            StartCoroutine(DashRoutine(direction));
        }
    }
    private IEnumerator DashRoutine(Vector2 direction)
    {
        // just in case if we already are dashing do nothing
        if (isDashing) yield break;

        // set dashing flag so no other concurrent routine can be started
        isDashing = true;

        // This is handy way for writing a while loop with a timer
        // basically this is executed every fixeUpdate for startDashTime seconds
        for (var timePassed = 0f; timePassed < startDashTime; timePassed  = Time.deltaTime)
        {
            // wait for the next FixedUpdate call
            yield return new WaitForFixedUpdate();

            rb.velocity = direction * dashSpeed;
        }
        Debug.Log("I should dash");

        // finally release the flag so the next dashing can be triggered
        isDashing = false;
    }
}

Thanks again for your help.

  • Related