Skip to content

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"]
  1. Trigger - Detects that something happened (input, timer, collision)
  2. Launcher - Listens for the trigger and starts an operation when it fires
  3. 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:

  1. Add a launcher component (e.g., ProcessLauncher) to a GameObject
  2. In the Event field, click the type selector and choose an event source (e.g., InputButtonEvent)
  3. Configure the event's properties (e.g., which button, press vs. release)
  4. In the Process field, choose the process to run when the event fires
  5. 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:

  1. Create a GameObject with a ProcessComponent.
  2. Set the Begin trigger to an InputButtonEvent configured for "Fire1" on press.
  3. Set the Process field to an AttachableObjectCommand with a DetachAttachableOperation (or whatever attachable-side operation you need).
  4. Configure the command's subject — a SmartAttachableObject resolving to the agent's currently-held object, an explicit reference, or a detector pick.
  5. 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.