Stage 7: Arrows That Hit
arrows that damage slimes, and slimes that die at zero health
2D trigger collisions and a health variable
real combat — towers kill the wave
The big idea
Your arrows fly right through slimes like ghosts. This stage makes them connect. For two objects to notice each other touching, Unity needs to detect overlap, and that's the job of a Collider2D — an invisible shape around an object. When we tick a collider's Is Trigger box, it stops blocking movement and instead just reports overlaps. Perfect for an arrow: we don't want it to bump a slime aside, we want it to register a hit. Your tiles already carried a Collider2D so Unity could catch a click back in Stage 3 — a collider does that same detection job here, except we switch on Is Trigger so it reports an overlap instead of a click.
Detecting overlap also needs motion that the physics system can see. So one of the two objects also needs a Rigidbody2D — the component that hands an object to Unity's physics. We'll set it to Kinematic, which means "I move it by script, not by gravity," so nothing falls or bounces. The rule to remember: a 2D trigger only fires if at least one of the two objects has a Rigidbody2D, and both have a Collider2D with Is Trigger on.
Finally, the arrow has to tell a slime from a tile from another arrow. We label slimes with a Tag — the exact text "Enemy" — and the arrow checks that tag with CompareTag before doing damage. When the overlap happens, Unity calls a special method, OnTriggerEnter2D, and hands us the other collider.
- Collider2D
- An invisible 2D shape that lets Unity detect when objects touch or overlap.
- Is Trigger
- A collider setting that makes it report overlaps instead of physically blocking — used for hits and pickups.
- Rigidbody2D
- The component that hands an object to the physics system. Required on at least one object for triggers to fire.
- Kinematic
- A Rigidbody2D mode meaning 'moved by script, not by gravity' — no falling, no bouncing.
- Tag
- A short text label on a GameObject. Here we tag slimes 'Enemy' so arrows know what they hit.
- OnTriggerEnter2D
- A method Unity calls automatically the moment two trigger colliders start overlapping.
- CompareTag
- Checks whether a GameObject has a given tag — safer than comparing the tag text by hand.
Finish Stage 6: Towers That Fire — you need towers that auto-fire Arrow projectiles, and the slimes from Stage 1.
Build it
Step 1 — Give the slime health
Open Enemy.cs. We add health in two passes; press Play after each.
Pass 1 — track health and react to a hit. Add a health field and a TakeDamage method that just logs for now:
public int health = 3;
public void TakeDamage(int amount)
{
health -= amount;
Debug.Log("Slime hit! Health now " + health);
}
Add those inside the existing Enemy class, alongside speed and gateX. You can't trigger a hit yet, but the code compiles and the slime now carries health. Press Play to confirm no red errors. Stop.
Pass 2 — die at zero. A slime with no health should disappear. Add the check:
The full script, line by line
The Stage 7 additions to Enemy.cs: the slime carries health and removes itself when that health runs out.
public int health = 3;
public void TakeDamage(int amount)
{
health -= amount;
if (health <= 0)
{
Destroy(gameObject);
}
}
Line 1Health is public and tunable
health starts at 3, so it takes three arrows of 1 damage to fall. Being public, you can make tougher slimes by raising it in the Inspector.
Lines 3–5TakeDamage is called from outside
It's public so the arrow can call it. Each call subtracts amount from health — the arrow decides how much damage that is.
Lines 6–9Remove the slime at zero
Once health drops to zero or below, Destroy(gameObject) removes the whole slime from the Scene. We check <= 0, not == 0, in case a big hit overshoots past zero.
These lines go inside Enemy, which still has its Stage 1 Update that walks the slime left toward gateX. We're adding to the class, not replacing it.
The slime can take damage now, but nothing calls TakeDamage yet — for an arrow and a slime to notice each other, we need a little physics setup.
Step 2 — Set up the colliders and tag
This is the physics plumbing that makes hits possible. Do all three pieces, then test.
First, create the Enemy tag — it doesn't exist yet. Select the Slime, click the Tag dropdown at the very top of the Inspector, choose Add Tag…, press the +, type Enemy, and save. That only creates the tag. Now reselect the Slime, open the Tag dropdown again, and pick Enemy to actually assign it. (Because the Slime is a prefab, every spawned slime is tagged too.)
Build this GameObjectSlime (combat setup)
2D Sprite (existing)Open recipe
Slime (combat setup)
2D Sprite (existing)- Sprite
- the green slime from your sliced tilemap
- Tag
- "Enemy" — create it via Add Tag… first, then pick it from the dropdown
- Collider2D → Is Trigger
- checked
- Rigidbody2D → Body Type
- Kinematic
- Rigidbody2D → Gravity Scale
- 0 (so it never falls)
- Sprite Renderer
- Enemy.cs
- Collider2D (Is Trigger ON)
- Rigidbody2D (Body Type = Kinematic)
The Rigidbody2D is what makes triggers actually fire. Kinematic means the slime keeps moving by your Update script, with no gravity or bouncing. Set the Tag to Enemy on the Slime prefab so every spawned slime is tagged.
Build this GameObjectArrow (combat setup)
2D Sprite (existing)Open recipe
Arrow (combat setup)
2D Sprite (existing)- Sprite
- an arrow sprite from your sliced tilemap
- Collider2D → Is Trigger
- checked
- Sprite Renderer
- Projectile.cs
- Collider2D (Is Trigger ON)
The arrow needs a trigger collider too. It doesn't need its own Rigidbody2D — the slime's covers the pair. Add the collider to the Arrow prefab so every fired arrow has it.
Step 3 — Make the arrow deal damage
Now the payoff. Add OnTriggerEnter2D to Projectile.cs — this is the method that ties towers to slimes. You've seen all the pieces by now, so write it yourself before you peek.
Your turn — write it first
Write OnTriggerEnter2D(Collider2D other). When the arrow overlaps something tagged 'Enemy', reach into it for its Enemy script and call TakeDamage(damage), then destroy the arrow so it can't hit twice.
Need a nudge?
other.CompareTag("Enemy") to check the tag, other.GetComponent<Enemy>() to grab the script, and an if (enemy != null) null-check before you call TakeDamage. Finish with Destroy(gameObject).Reveal the answer
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Enemy"))
{
Enemy enemy = other.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
}
}
Once you've tried it, here's the finished method with notes:
The full script, line by line
The Stage 7 addition to Projectile.cs: when an arrow overlaps something tagged Enemy, it damages that slime and removes itself.
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Enemy"))
{
Enemy enemy = other.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
}
}
Line 1Unity hands us the other collider
OnTriggerEnter2D runs automatically the instant the arrow's trigger overlaps another trigger. 'other' is whatever the arrow touched.
Line 3Only react to slimes
CompareTag('Enemy') checks the other object's tag. If the arrow grazes a tile or another arrow, the tag won't match and we ignore it.
Lines 5–9Find the Enemy script and hurt it
GetComponent<Enemy>() reaches into the slime for its Enemy script, then calls TakeDamage with the arrow's damage value. The null check guards against an object tagged Enemy that somehow lacks the script.
Line 10The arrow is spent
An arrow hits once. Destroy(gameObject) removes it so a single arrow can't damage two slimes.
This method goes inside Projectile, next to the Stage 6 Update that flies the arrow right and destroys it off-screen.
Predict first: with health = 3 and damage = 1, how many arrows does it take to drop one slime? Decide, then play.
Press Play, place a tower, and let a slime walk into the lane. Three arrows should drop one slime.
Understand it
Triggers are the right tool here, not solid collisions. A solid collision would make the arrow shove the slime or stop dead against it — wrong for a projectile. A trigger lets the arrow pass into the slime's space and simply report the touch, so we decide what a "hit" means in code: subtract health, destroy the arrow. That separation — physics detects, your script decides — is the whole point of triggers.
The single most confusing rule in 2D combat is the Rigidbody2D requirement. It feels like two colliders should be enough, but Unity's physics only watches objects that have a Rigidbody2D. We put a Kinematic one on the slime so it's "in the physics world" without falling, and that one body covers every arrow that hits it. Tagging is the other half: CompareTag("Enemy") keeps arrows from reacting to tiles, towers, or each other, and it's safer than typing the tag string into an if by hand, where a typo would silently never match.
Try this
Try this
Three short experiments. Predict before you run, then test your guess.
Set a slime's health to 1 in the Inspector. Before you press Play, decide how many arrows it takes to drop it now, and whether the rest of the arrows in flight still matter. Run it and watch.
Uncheck Is Trigger on the Arrow's collider and run it. Arrows now bump or pass slimes without ever dealing damage, because OnTriggerEnter2D only fires for triggers. Re-check it. Triggers, not solid colliders, are what make hits work here.
Right now your only income is the slow gold trickle from Stage 4. In Stage 8 you'll add a Gold Mine that pays out over time and a second kind of tower — with almost no new code. Look at how your Archer Tower is built from a few small scripts. Which of those scripts could a different tower reuse with just different numbers?
Test your stage
- An arrow that overlaps a slime makes the slime lose health (watch the Console or the
healthfield). - A slime disappears after taking enough hits (three arrows of 1 damage by default).
- Each arrow is destroyed on its first hit and never damages two slimes.
- Arrows ignore tiles, towers, and other arrows — only slimes take damage.
- Design check. Watch a tower fight a slime. Do three hits feel like a fair trade for the gold the tower cost, or does the slime die too easily / shrug off arrows? Tune
healthanddamageuntil a kill feels earned but achievable. - From memory. Without looking, write the line that checks the other collider is an enemy before dealing damage. Compare — did you reach for
if (other.CompareTag("Enemy"))?
If it breaks
- Arrows pass straight through slimes, no damage. This is the classic 2D-trigger trap. Check all three: the slime has a Rigidbody2D (Kinematic), and both the slime and the arrow have a Collider2D with Is Trigger checked. Without a Rigidbody2D on at least one of them, triggers never fire.
OnTriggerEnter2Dnever runs. Same cause as above, plus make sure the method name is spelled exactlyOnTriggerEnter2D(notOnTriggerEnter, which is the 3D version).- Arrows hit, but slimes never lose health. The slime's Tag isn't exactly
"Enemy", soCompareTagreturns false. The tag is case-sensitive and must match character for character. - A red
NullReferenceExceptionwhen an arrow hits. Something tagged"Enemy"doesn't actually have theEnemyscript. The null check guards the damage call, so confirm your Slime prefab hasEnemy.csattached. - The slime falls or drifts. Its Rigidbody2D isn't Kinematic, or Gravity Scale isn't
0. Set Body Type to Kinematic so yourUpdateis the only thing moving it.