Events¶
Events connect moments - a button press, a timer, a collision - to actions. Wire any trigger to any behavior in the Inspector, and swap triggers without touching code.
The pattern is simple: something happens, and something responds. A mouse click starts a transfer. A timer fires and plays a sound. A collision triggers a visual effect. You pick the trigger and the response separately, so either one can change independently.
The Standard Trigger Pattern¶
The most common setup follows a three-part chain:
flowchart LR
E["Trigger"] -->|fires| L["Launcher"]
L -->|runs| P["Operation"]
- Trigger - Detects that something happened (input, timer, collision)
- Launcher - Listens for the trigger and starts an operation when it fires
- Operation - The process or command that executes in response
This decouples what triggers behavior from what the behavior does. You can swap the trigger (mouse click to touch input) or the operation (play animation to spawn particles) independently.
Built-in Event Types¶
Input Events¶
| Event | Trigger |
|---|---|
| InputButtonEvent | Legacy Input Manager button press/release/hold |
| KeyCodeEvent | Raw keyboard key press/release/hold (no Input Manager setup) |
| InputSystemActionEvent | New Input System action performed |
| MouseButtonEvent | Mouse button press/release/hold |
| RewiredButtonEvent | Rewired input button (requires Rewired package) |
Timing Events¶
| Event | Trigger |
|---|---|
| DurationEvent | After a specified number of seconds |
| NextFrameEvent | On the next frame after registration |
UI Events¶
| Event | Trigger |
|---|---|
| ButtonClickEvent | UI Button click |
| ToggleChangedEvent | UI Toggle value changed |
| SliderChangedEvent | UI Slider value changed |
Scene Events¶
| Event | Trigger |
|---|---|
| GameObjectEvent | GameObject lifecycle events (enable, disable, destroy) |
| PhysicsEvent | Collision or trigger enter/exit/stay (from jungle.physics) |
| VideoStartedEvent | Video player starts playback |
| VideoFinishedEvent | Video player finishes playback |
Asset Events¶
| Event | Trigger |
|---|---|
| EventFromAsset | Delegates to a ScriptableObject-based event asset — useful for cross-scene or global events |
| SignalEventFromHub | Subscribes/raises a SignalType on a specific LocalSignalTransmitter — per-GameObject pub/sub |
Value Events¶
| Event | Trigger |
|---|---|
| OnValueChangedEvent | Raises whenever an IObservableValue<T> transitions to a new value |
Technical API¶
IEvent¶
The core interface for events:
public interface IEvent
{
void Register(Action listener);
void Unregister(Action listener);
void Raise();
}
| Method | Purpose |
|---|---|
Register(Action) |
Subscribe a callback that fires when the event is raised |
Unregister(Action) |
Remove a previously registered callback |
Raise() |
Fire the event, invoking all registered listeners |
Events are serialized with [SerializeReference] and [JungleClassSelection], so the event source is fully configurable in the Inspector.
Reactive Event Listening¶
For persistent, Inspector-configured event responses, use a Reactor component with an event target. The Reactor manages subscription lifecycle automatically (subscribes on Begin, unsubscribes on End), and each (trigger, body) entry can run a process list when its trigger fires.
For signal-based events, add a signal target to the Reactor — signals are pushed via Reactor.Receive(SignalType). For per-GameObject pub/sub without going through a Reactor, use a LocalSignalTransmitter: drop a SignalEventFromHub into any IEvent slot to subscribe, or a RaiseSignalOnTransmitter operation to raise.
See Data — Reactive System for full details on Reactor targets and triggers.
Event Operations¶
Standalone operations let you raise events from any operation list — drop them into a Setter's ScheduledOperationEntry, a Sequence, a Reactor body, or any other slot that takes an IOperation:
| Operation | Purpose |
|---|---|
| RaiseEventOperation | Calls Raise() on an EventAsset reference. |
| InvokeUnityEventOperation | Invokes a standard UnityEvent configured inline. |
| RaiseSignalOnTransmitterOperation | Raises a SignalType on a referenced LocalSignalTransmitter. |
| RaiseSignalOnOwnerTransmitterOperation | Raises a SignalType on the LocalSignalTransmitter attached to a chosen owner GameObject — convenience for the "broadcast on this object" case. |
Wiring Events in the Inspector¶
Events appear as TypeSelectableFields on launcher components. A typical setup looks like:
- Add a launcher component (e.g., ProcessLauncher) to a GameObject
- In the Event field, click the type selector and choose an event source (e.g., InputButtonEvent)
- Configure the event's properties (e.g., which button, press vs. release)
- In the Process field, choose the process to run when the event fires
- Configure the process
Testing events
Enter Play mode and trigger the event source. The launcher's process should start immediately. If nothing happens, check that the event type matches your input method and that the process is configured correctly.
Octoputs Event Usage¶
Octoputs defines event types that surface attachable / attachment-point lifecycle moments:
| Event | Fires When |
|---|---|
| AttachableObjectStatusEvent | An AttachableObject changes status (held / attached / dropped) |
| AttachmentPointStatusEvent | An AttachmentPoint changes status (free / holding / target-of-grab) |
For "object entered/left a detector" hooks, configure UnityEvents directly on the Detector (onNewAvailable, onNotAvailableAnymore) or wire a Reactor signal target.
Practical Example¶
Goal: When the player presses a button, run an attach command on a specific AttachableObject.
InputButtonEvent ("Fire1", On Press)
→ ProcessComponent
→ AttachableObjectCommand
├─ Subject: SmartAttachableObject (Dynamic: held by agent)
└─ Operations:
└─ Detach Attachable Operation
Setup:
- Create a GameObject with a
ProcessComponent. - Set the Begin trigger to an
InputButtonEventconfigured for "Fire1" on press. - Set the Process field to an
AttachableObjectCommandwith aDetachAttachableOperation(or whatever attachable-side operation you need). - Configure the command's subject — a
SmartAttachableObjectresolving to the agent's currently-held object, an explicit reference, or a detector pick. - Press Play and hit Fire1 — the operation runs.
Creating Custom Events¶
Implement IEvent and add [JungleClassInfo]:
[Serializable]
[JungleClassInfo("Fires when a score threshold is reached", "Icons/score", "Gameplay")]
public class ScoreThresholdEvent : IEvent
{
[SerializeField] private int threshold = 100;
private Action listener;
private bool fired;
public void Register(Action callback)
{
listener += callback;
fired = false;
}
public void Unregister(Action callback)
{
listener -= callback;
}
public void Raise()
{
if (!fired)
{
fired = true;
listener?.Invoke();
}
}
// Call this from your score system when the score changes
public void CheckScore(int currentScore)
{
if (currentScore >= threshold)
Raise();
}
}
Event vs. polling
Events are reactive — they fire when something happens. If you need to check a condition continuously, use a process that evaluates conditions each frame instead. Events are best for discrete moments: a click, a collision, a threshold crossing.
Signal Type vs. Event Asset¶
| Surface | Routing scope | Picker shape | Typical use |
|---|---|---|---|
EventAsset |
Global — anything that references the asset hears it | IEvent slot (configure via EventFromAsset) |
Cross-scene events, UI clicks shared by many systems |
SignalType |
Per-LocalSignalTransmitter instance |
IEvent slot (configure via SignalEventFromHub) |
Per-prefab/per-instance broadcasts — every prefab instance gets its own routing scope |
SignalType into a Reactor |
Per-Reactor; pushed via Reactor.Receive |
Reactor target | Signals that should fan into typed reactions on a single Reactor |
EventAsset is the right pick when many systems share one event globally. SignalType is the right pick when every prefab instance needs its own routing scope and shouldn't share listeners with siblings.