◀ 2.63.13.2 ▶

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.

In this lesson you will be able to answer“how do I make a turret notice the player?”Outline only
Break It Down~10 minOutline only

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.

  1. 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.
  2. 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.
  3. 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.

In the Editor ~15 min
  1. 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 as PlayerController in Unit 1.
  2. 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.
  3. 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.
In the Code ~30 min
APIWhat it isWhat you getWhat 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.
Architectural specification for 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

  1. If you use GameObject.FindWithTag(String tag), why call it once in Start() and store the result, rather than calling it every frame in Update()?
  2. The squared comparison tests a magnitude against range * range rather than against range. What would go wrong if you compared it to plain range?
  3. 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:

Reference Docs

Need a deeper explanation? These pages cover the same concepts:

Next: 3.2 — Projectiles: Instantiate, Fire, Destroy, where the turret finally shoots.

0/5 answered

Answers save on this device as you type. At the end of class, click Download and upload the file to the Canvas assignment.

Saved on this device only — the Dashboard tracks your progress.