0
\$\begingroup\$
[SerializeField]float dashingSpeed = 25f;
[SerializeField]float dashingTime = 0.2f;
float dashingCoolDown = 1f;
bool candash = true;
bool IsDashing;
[SerializeField]float MovingSpeed = 10f;
Rigidbody rb;

 void dashing()
{
    if (Input.GetKeyDown(KeyCode.W) && candash)
    {
        StartCoroutine(Dashing());
    }
}

   IEnumerator Dashing()
    {
        candash = false;
        IsDashing = true;
        rb.velocity = transform.right * dashingSpeed;
        transform.gameObject.tag = "dashes";
        yield return new WaitForSeconds(dashingTime);
        IsDashing = false;
        transform.gameObject.tag = "Player";
        yield return new WaitForSeconds(dashingCoolDown);
        candash = true;
    }

Hi, i was thinking of changing a gameobject tag during the dash but sometimes it didn't work, like my game object remains under "Player" instead of changing sometimes. Which is weird. why? oh i do this because like once it change during that "dashing" duration, the other game object will take damage when got hit by that tag. So it will feel like that object take damage during the dashes

\$\endgroup\$
1
  • 1
    \$\begingroup\$ One pattern I like to use is the concept of "hurtboxes" and "hitboxes". A "hurtbox" is a gameobject with a collider and a "Hurtbox" component that detects other colliders with the "Hitbox" component. The hitbox component then relies the damage taken to the object it belongs to. With that pattern, every gameObject can have any number of "hurtbox" and "hitbox" children which you can activate and deactivate on demand. Hurtboxes can often come in several flavors, like one that only hits each object once (clearing that list when enabled) or one that damages continuously. \$\endgroup\$
    – Philipp
    Oct 4, 2022 at 15:54

1 Answer 1

7
\$\begingroup\$

Using tags is a very messy way to do this. Unity is designed around the concept of reusable components. Let's create and use a reusable component instead.

First, we need a component to represent health. You might already have something like this, but here's a simple example:

[System.Serializable] public class HealthEvent : UnityEvent<Health>{}

//Attach to objects that should have HP
[RequireComponent(typeof(Collider))]
public class Health : MonoBehaviour {
    [SerializeField] private float maxHP;
    [SerializeField] private float currentHP;
    [SerializeField] private HealthEvent healthChangedEvent = new HealthEvent();
    [SerializeField] private HealthEvent diedEvent = new HealthEvent();
    
    public float CurrentHP {
        get => currentHP;
        set {
            currentHP = Mathf.Clamp(value, 0, maxHP);
            healthChangedEvent.Invoke(this);
            if (currentHP == 0) {
                diedEvent.Invoke(this);
            }
        }
    }

    public HealthEvent HealthChangedEvent => healthChangedEvent;
    public HealthEvent DiedEvent => diedEvent;

}

Then we need a component to deal damage. This is a very simple example of a damage trigger, which applies damage to any object with a Health that enters the trigger. We would attach this component to a GameObject with a Collider with the "Trigger" box checked:

//Attach to objects that should deal damage.
//This example only works with trigger colliders, but you can modify it to work with 
//regular colliders by adding the OnCollisionEnter() event
[RequireComponent(typeof(Collider))]
public class DamageTrigger : MonoBehaviour {
    [SerializeField] private float damage;

    private void Awake() {
        Collider collider = GetComponent<Collider>();
        Assert.IsNotNull(collider);
        Assert.IsTrue(collider.isTrigger, "Damage Trigger only works with Trigger colliders");
    }

    private void OnTriggerEnter(Collider other) {
        Health health = other.GetComponent<Health>();
        if (health != null) health.CurrentHP -= damage;
    }
}

This is a great example of a highly reusable component. We can put DamageTrigger on projectiles, environmental hazards (e.g. fire, spikes), AOE effects, or anything else that deals damage to any objects within its volume.

Finally, we reference a damage trigger from our Dasher component. Rather than messing with tags, we turn the damage trigger on when we start dashing and off when we stop dashing:

public class Dasher : MonoBehaviour {
    [SerializeField] private DamageTrigger dashDamageTrigger;
    [SerializeField] float dashingSpeed = 25f;
    [SerializeField] float dashingTime = 0.2f;
    float dashingCoolDown = 1f;
    bool canDash = true;
    bool isDashing;
    [SerializeField]float movingSpeed = 10f;
    Rigidbody rb;

    void Awake() {
        rb = GetComponent<Rigidbody>();
        Assert.IsNotNull(dashDamageTrigger);
        dashDamageTrigger.gameObject.SetActive(false);
    }

    void Update() {
        if (Input.GetKeyDown(KeyCode.W) && canDash && !isDashing) {
            StartCoroutine(Dashing());
        }
    }

    IEnumerator Dashing() {
        Assert.IsTrue(canDash, "Started dashing while dashing is disabled!");
        canDash = false;
        isDashing = true;
        rb.velocity = transform.right * dashingSpeed;
        dashDamageTrigger.gameObject.SetActive(true);
        yield return new WaitForSeconds(dashingTime);
        isDashing = false;
        dashDamageTrigger.gameObject.SetActive(false);
        yield return new WaitForSeconds(dashingCoolDown);
        canDash = true;
    }
}
  1. Add a new GameObject as a child of the Player and give it a Collider with "Trigger" checked and the DamageTrigger component. Make sure it's on the same Layer as the player, and make sure that layer can't collide with itself in the project Physics settings' layer collision matrix. Otherwise, the player may be hurt by the damage trigger when performing a dash.
  2. In the Inspector for the Dasher component, find the "Dash Damage Trigger" field and select the Damage Trigger from step 1.
  3. Add a Health component to the object that you want to damage.
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .