Skip to content

Tutorial: Sourcing GameObjects with Detector

Find GameObjects in the scene through triggers, raycasts, proxy lists — anything — and expose them through a single uniform interface (IItemSource<GameObject>). Hook the results into agents, reactors, transforms, UI. One picker, one selection step, one event surface, every detection strategy.

By the end of this tutorial you'll have:

  • A trigger-volume Detector that finds Attachables in a zone.
  • A raycast-under-mouse Detector that picks whatever's under the cursor.
  • A Reactor that fires every time the detector gains its first item.

Prerequisites: Basic Unity scene with at least one GameObject you want to find.


What a Detector Is

A Detector is a ControllableComponent that exposes IItemSource<GameObject>. Three pluggable pieces:

  1. Detection Strategy — how candidates are found (trigger collider, raycast, proxy, reference list, …).
  2. Selection — a single IObjectSelection step that transforms each raw candidate. Filters, redirects (e.g. a child collider redirects to its parent's AttachableObject), or expands. Use a Sequence or Union composite to chain multiple steps. Leave empty to track every raw detection.
  3. Reactive surface — UnityEvents (onNewAvailable, onNotAvailableAnymore, onNoMoreAvailable) and lifecycle processes (anyAvailableProcess, noneAvailableProcess, onAddedProcess, onRemovedProcess).

Detectors are pure read-only sources — they never mutate other containers as a side effect. To mirror detection into a container, put a Reactor next to it with a Detector Membership cycle reaction: its On Begin process runs a ContainerCommand with a StoreValueOperation, its On End process a RemoveValueOperation. The detector stays pure; the reaction does the side effect.


1. Trigger Volume Detector

Goal: detect every Attachable that enters a tagged trigger.

  1. Create a GameObject named PickupZone. Add a Box Collider, check Is Trigger, and scale it to the area you want to cover.
  2. Add a Detector component (Add Component → Jungle → Reactions → Detector).
  3. Detection Strategy — pick Trigger Detection Strategy (or whatever the trigger-volume option is called). It reads from the colliders that enter/leave this GameObject's triggers.
  4. Selection Strategy — pick Is Attachable (or whatever filter limits to Attachables). To combine multiple checks, pick a Sequence and add steps inside it.

Press Play and drag an AttachableObject into the trigger area. The detector's Available list now contains it. Move it out — the list empties.

Selection redirects

A typed selection step (e.g. AttachmentPointFilterGroup) that finds the AttachmentPoint on a parent of the raw hit can redirect the detected GameObject to the parent. The detector keeps the resolved GameObject — so consumers see the owner of the AttachmentPoint, not the child collider that triggered detection. The step's lookup field controls this (Self / Parents / Children).


2. Raycast Under Mouse Detector

Goal: detect whichever Attachable is under the mouse cursor.

  1. Create a GameObject named CursorDetector (or use one of your existing agent objects).
  2. Add a Detector component.
  3. Detection Strategy — pick Raycast Detection Strategy (or the camera-mouse-raycast variant). Configure the camera reference and the layer mask.
  4. Selection Strategy — Is Attachable, same as before.

The detector now reports the current "thing under cursor" attachable as long as the strategy keeps casting (typically every frame).


3. Wire the Detector to a Consumer

A detector by itself just sits there reporting. To use it:

Feed an AttachingAgent

On an AttachingAgent, the Grab Source is a SmartAttachableObject. Set its mode to Dynamic and pick GameObject From Detector as the source object. Drag your Detector in. The agent now grabs whatever the detector reports.

Feed a Reactor

Add a Reactor. Pick a target that watches an IGameObjectValue source — set the source to GameObjectFromDetector(detector). The reactor fires when the detector gains its first item, runs while the detector is non-empty, completes when it becomes empty. Wire the process to whatever response you need.

Feed a UI element

A GameObjectFromDetector is also an IObservableGameObjectValue — bind a UI label to its current item, set a glow effect on the resolved GameObject's renderer, anything that takes a typed value source.


4. Detector Lifecycle Processes

The Detector has four optional processes that begin/end on detection edges:

Process Begins Ends
onAddedProcess Every add. Self-completes.
onRemovedProcess Every remove. Self-completes.
anyAvailableProcess Transition from 0 → 1 detected. When count drops back to 0.
noneAvailableProcess Transition from N → 0 detected. When a new item arrives.

Use anyAvailableProcess / noneAvailableProcess for "while items are present" / "while items are absent" effects (e.g. highlight a UI badge while the detector has something to pick up).

Use onAddedProcess / onRemovedProcess for "fire-and-forget on each edge" (e.g. a quick particle puff when an item enters).


5. Ignore-Until-Lost

A Detector exposes a useful tactical operation:

  • IgnoreUntilLost(GameObject) — marks an item as ignored. It's removed from the public available list (raising OnItemRemoved) and won't be re-surfaced until the detection strategy reports it has physically left detection range.

Used internally by Octoputs's transfer logic ("don't re-grab the thing I just dropped while it's still in my zone"). Wire it from your own logic if you need similar "lock this one out" behaviour.


6. Composing Selection Steps

A Detector's selection is a single IObjectSelection step. For multi-step logic, pick a Sequence (AND — each step narrows the set) or Union (OR — any branch can contribute). Order matters in a Sequence — a redirect happens at the step that performs it, so later steps see the redirected candidate.

Example using a Sequence:

Detector
├─ Strategy: Trigger
└─ Selection: Sequence
   ├─ Is Attachable                  (also redirects to Attachable's GameObject)
   ├─ Attachable Tag Filter (Red)
   └─ Attachable Eligibility Filter

This detector accepts only red-tagged Attachables that are currently eligible (not already attached somewhere blocking) and resolves the resulting GameObject to the Attachable owner.


7. Mirror to a Container

If you need a stateful container (an inventory list, a UI-bound list), Put a Reactor next to it with a Detector Membership cycle reaction: its On Begin process runs a ContainerCommand with a StoreValueOperation, its On End process a RemoveValueOperation. The detector stays pure; the reaction does the side effect.


8. Detector vs Container vs Item Source

Three roles in the GameObject-routing world:

Role Read Write Lifecycle
Detector Yes (via IItemSource<GameObject>) No (pure source). Adds/removes driven by strategy.
Container (IItemContainer<GameObject>) Yes Yes (Take, Store, Remove). Adds/removes driven by callers.
Item Source (IItemSource<GameObject>) Yes No (read-only interface). Generic.

A Detector is an IItemSource. A container is both IItemSource and IItemContainer. Consumers that only need to read can target the source interface and accept either.


Next Steps