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;
}
}
- 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.
- In the Inspector for the Dasher component, find the "Dash Damage Trigger" field and select the Damage Trigger from step 1.
- Add a Health component to the object that you want to damage.