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. In a project set to the Input System package only, just the default buttons work (Fire1-3, Jump, Submit, Cancel) |
| 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 signal Key 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, process) 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(Key). For per-GameObject pub/sub without going through a Reactor, use a LocalSignalTransmitter: drop a SignalEventFromHub into any IEvent slot to subscribe, or a RaiseSignalOnHubOperation 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 Sequence, a Reactor's process, or any other slot that takes an IOperation:
| Operation | Purpose |
|---|---|
| RaiseEventOperation | Calls Raise() on an EventAsset reference. |
| InvokeUnityEventOperation | Invokes a standard UnityEvent configured inline, like a UI Button's On Click. Use this to trigger your own scripts without writing Jungle-specific code. Runs instantly. |
Invoke Unity Event (Object) (InvokeUnityEventWithObjectOperation) |
Same, but hands each wired method a GameObject, by default the object the run is about. |
Raise Signal On Transmitter (RaiseSignalOnHubOperation) |
Raises a signal Key on a referenced LocalSignalTransmitter. |
Raise Signal On Owner Transmitter (RaiseSignalOnOwnerHubOperation) |
Raises a signal Key on the LocalSignalTransmitter attached to a chosen owner GameObject -- convenience for the "broadcast on this object" case. |
To call a UnityEvent from a process slot, use Unity Event Invoke Command (UnityEventInvokeCommand), which holds these two operations.
Wiring Events in the Inspector¶
Events appear as TypeSelectableFields wherever an IEvent slot exists. The usual host is a ProcessComponent, whose Execution Frame decides what starts it:
- Add a ProcessComponent to a GameObject
- Open its Start & Stop tab and set Execution Frame to Event Pair
- In Begin Event, click the type selector and choose an event source (e.g., Input Button Event), then configure it (which button, press vs. release)
- On the Process tab, choose the process to run when the event fires
- Configure the process
Use a Reactor instead when the trigger is a value changing rather than an event firing, or when one object needs many independent reactions.
- The frame decides what starts and stops the component.
- The event that starts it.
- The process, here a Debug Command that logs a line.
Testing events
Enter Play mode and trigger the event source. The 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 Key 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 |
signal Key |
Per-LocalSignalTransmitter instance |
IEvent slot (configure via SignalEventFromHub) |
Per-prefab/per-instance broadcasts — every prefab instance gets its own routing scope |
Signal Key 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. signal Key is the right pick when every prefab instance needs its own routing scope and shouldn't share listeners with siblings.