3.1 — The Turret: Distance & the Detection Radius
Coins wait to be collected; spikes wait to be bumped into. The turret is the first thing in this
game that decides. Build TurretController.cs from scratch: find the
player, measure the distance, compare it against a range a designer can tune.
The turret notices me. That is the whole feature, and "how does a turret notice me" has no answer a computer can act on.
First, before any code: cut that into parts small enough that you could look each one up on its own.
- Who is my target, and where is it?what does this part do?Read: GameObject.FindWithTag(String tag) against a [SerializeField] reference, both in the quick reference, and priced against each other in the table below.
- How far away is it right now?what does this part do?Read: Vector3.Distance(a, b) and a sqrMagnitude comparison — quick reference, and the table below.
- Is that distance inside my danger zone?what does this part do?Read: the [SerializeField] tuning knob you have used since 1.4, and the comparison operators you met in 2.2.
"Notice the player" is not something you can write. Each of these three is — and none of them is about turrets. Finding a tagged object, measuring a distance and comparing a number are ordinary tools you will reach for all year; the turret is just where they happen to combine.
The test for a finished split: could you look this part up on its own, right now, in one search? "Make the turret shoot" cannot be. "Get the distance between two objects" can.
Your turn
Pick two of the parts above and say in one line what each one actually does.
The table below prices two ways to acquire the target and two ways to measure distance. Say which you picked for each, and what your choice costs you.
-
Hierarchy → the Overworld scene, which holds two
Turret instances. Then Project window →
Assets/Prefabs/Turret→ Inspector → an empty Turret Controller component is already attached: the script exists, it is wired up, and it does nothing — the same situation asPlayerControllerin Unit 1. -
Project window →
Assets/Prefabs/Player, then Inspector → Tag: confirm the exact spelling your script will ask for, on the object carrying the collider. A tag that does not match is not an error, it is silence. - Once the code half is done — Inspector → Turret Controller → your range field (it appears in the Inspector as soon as you declare it). Give the two instances different values, then Game view → press Play and walk slowly toward one: quiet outside the radius, a Console line every frame inside it, quiet again as you walk back out.
| API | What it is | What you get | What it costs |
|---|---|---|---|
GameObject.FindWithTag(String tag) |
A scene-wide search for an object carrying that tag. | A reference with nothing wired by hand — it finds things you never set up. | It walks the whole scene, so it has no business in Update(), and it
returns null when nothing matches: hand that to the next line and it
throws three methods from the failure. |
[SerializeField] private Transform playerTransform; |
A slot in the Inspector holding the player's transform. | Zero search cost, and you can see what it points at. | Wired by hand, and it breaks for anything that spawns at runtime. |
Vector3.Distance(a, b) |
The straight-line distance between two points. | A real distance in world units — the number you can print, and the unit a designer's tuning value is measured in. | A square root every call. Irrelevant for two turrets; not irrelevant when hundreds of enemies ask at once. |
(b - a).sqrMagnitude, tested against range * range |
The same comparison with the square root skipped. | Cheaper, and it answers the question you are asking — inside, or outside. | You get the distance squared and never the distance, so it is useless to
display, and testing it against plain range gives the wrong radius. The
radius you are standing in is range * range. |
[SerializeField] private float range = 6f; |
The tuning knob, in the class body above Start() with your other
fields. |
How far this turret can see, settable per instance without touching your code. | Choosing the default is design work: too big and the player is shot at from off-screen, too small and these two turrets never react to anything. |
TurretController.cs:
- Which component holds a GameObject's coordinates in world space, and which lifecycle method runs the target lookup exactly once? What does
GameObject.FindWithTag(String tag)return when nothing matches, and what check must follow it? - How do you measure the distance between turret and player every frame, and which of the two distance tools did you choose? What guard clause keeps the rest of
Update()from running when there is no target? - What condition says the player has entered the danger zone, and which comparison operator? You are about to test the exact boundary, so decide whether the edge of the circle counts as inside. What do you print so you can watch detection happen with no UI at all?
Choosing a Targeting Approach
- If you use
GameObject.FindWithTag(String tag), why call it once inStart()and store the result, rather than calling it every frame inUpdate()? - The squared comparison tests a magnitude against
range * rangerather than againstrange. What would go wrong if you compared it to plainrange? - You have two turrets in this scene and one player. Which targeting approach would you choose, and what does your choice cost you?
Checkpoint — before moving on, you must be able to:
- Break "the turret notices you" into target acquisition, distance measurement, and a selection condition
- Say, for each of those parts, where you would look it up without asking a person
- Explain why you cache the target once in
Start()instead of searching every frame, and whatGameObject.FindWithTag(String tag)hands back when it finds nothing - Compare
Vector3.Distance(a, b)against asqrMagnitudetest, and say why the squared version testsrange * range - Name the one value in your file a designer can retune from the Inspector, say what your default costs you, then commit and push
Reference Docs
Need a deeper explanation? These pages cover the same concepts:
- Unit 3: The Turret — distance, targeting, and the projectile lifecycle
- Unity + C# Quick Reference —
Vector3.Distance(a, b),GameObject.FindWithTag(String tag)and the Transform API - How do I…? index — find this lesson again by the question you were asking
Next: 3.2 — Projectiles: Instantiate, Fire, Destroy, where the turret finally shoots.
Saved on this device only — the Dashboard tracks your progress.