Raising & Scheduling
At its core, the Game Event System is about sending signals. While the Inspector handles visual bindings, the Runtime API gives programmers precise control over when and how these signals are fired.
This guide covers immediate execution, time-based scheduling, and the cancellation of pending events.
π Immediate Execution (Raise)β
The Raise() method is the standard way to fire an event. It executes all listeners (Inspector, Code, Flow Graph) synchronously in the current frame.
1. Void Eventsβ
Events with no arguments.
[SerializeField] private GameEvent onPlayerJump;
void Update()
{
if (Input.GetButtonDown("Jump"))
{
// Fires immediately
onPlayerJump.Raise();
}
}
2. Single Argument Eventsβ
Events that carry a specific data payload (T).
[SerializeField] private GameEvent<float> onHealthChanged;
public void TakeDamage(float damage)
{
currentHealth -= damage;
// Type-safe invocation
onHealthChanged.Raise(currentHealth);
}
3. Sender + Argument Eventsβ
Events that verify the Source of the event (TSender) and carry data (TArgs).
// Define types: Sender is GameObject, Arg is DamageInfo
[SerializeField] private GameEvent<GameObject, DamageInfo> onActorDamaged;
public void Hit()
{
var info = new DamageInfo { amount = 50, type = DamageType.Fire };
// Passes 'this.gameObject' as the sender
onActorDamaged.Raise(this.gameObject, info);
}
If you have configured Action Delay or Repeat settings in the Inspector for a specific event asset, calling Raise() will automatically respect those settings (e.g., it might wait 2 seconds before actually firing). See Inspector Integration below.
β±οΈ Delayed Execution (RaiseDelayed)β
Sometimes you want to schedule an event for the future without using a Coroutine. The system provides a built-in scheduler.
All scheduling methods return a ScheduleHandle, which is crucial if you need to cancel the event before it fires.
[SerializeField] private GameEvent onBombExplode;
public void PlantBomb()
{
Debug.Log("Bomb Planted...");
// Fire event after 5.0 seconds
ScheduleHandle handle = onBombExplode.RaiseDelayed(5.0f);
}
Passing Arguments with Delayβ
The API fully supports generics for delayed calls.
// Wait 1.5s, then send the float value '100f'
onScoreAdded.RaiseDelayed(100f, 1.5f);
// Wait 0.5s, then pass Sender and Args
onItemPickup.RaiseDelayed(this, itemData, 0.5f);
π Repeating Execution (RaiseRepeating)β
Use this to create loops, timers, or polling mechanisms entirely within the event system.
| Parameter | Description |
|---|---|
| interval | Time (seconds) between each fire. |
| repeatCount | How many times to fire? Set to -1 for Infinite. |
Example: Poison Effectβ
Damage the player every 1 second, for 5 ticks.
[SerializeField] private GameEvent<int> onTakeDamage;
private void ApplyPoison()
{
// Fire immediately (optional), then repeat 5 times every 1s
// Note: RaiseRepeating waits for the interval before the FIRST fire by default
onTakeDamage.RaiseRepeating(10, interval: 1.0f, repeatCount: 5);
}
Example: Radar Scan (Infinite)β
Ping a radar event every 2 seconds forever.
private ScheduleHandle _radarHandle;
void Start()
{
// -1 means execute forever until cancelled
_radarHandle = onRadarPing.RaiseRepeating(2.0f, repeatCount: -1);
}
π Cancellationβ
Stopping pending events is just as important as starting them. There are two distinct ways to cancel events, depending on how they were started.
1. Canceling Manual Schedulesβ
If you used RaiseDelayed or RaiseRepeating, you received a ScheduleHandle. You must use this handle to stop that specific task.
Canceling a Delayed Callβ
public void DefuseBomb()
{
// Stop the pending delayed execution
if (_bombHandle != null)
{
// Returns true if successfully cancelled
bool success = onBombExplode.CancelDelayed(_bombHandle);
}
}
Canceling a Repeating Loopβ
public void StopRadar()
{
// Stop the manual loop
if (_radarHandle != null)
{
onRadarPing.CancelRepeating(_radarHandle);
}
}
2. Canceling Automatic (Inspector) Schedulesβ
If an event is looping or delaying because of its Inspector Configuration (Behavior Window), use the parameterless Cancel() method.
- Target: Stops the active auto-sequence (Delay or Loop) on this event asset.
- Safety: Raise() automatically calls Cancel() internally before starting a new auto-sequence to prevent overlapping loops.
// Stops the "Action Delay" or "Repeat" logic currently running
// that was triggered by a previous .Raise() call
onEvent.Cancel();
Cancel() does NOT remove listeners.
- Cancel(): Stops time-based execution (Pending timers/loops). The event acts as if it was never fired.
- RemoveAllListeners(): Unsubscribes all scripts so they no longer receive future events.
π Inspector Integrationβ
It is vital to understand how code interacts with the Visual Behavior Configuration.
When you call Raise() in code, the system checks the Schedule Configuration defined in the Behavior Window:
- Code: myEvent.Raise() called.
- System Check: Does this event have Action Delay > 0 in Inspector?
- Yes: The system implicitly converts this to a RaiseDelayed.
- No: It fires immediately.
- System Check: Does this event have Repeat Interval > 0?
- Yes: The system starts a loop automatically.
If you want pure code control, leave the Schedule settings in the Inspector at 0. If you want designers to tune timing, use Raise() and let the Inspector control the delay.
π Muting Visuals (SetInspectorListenersActive)β
In complex systems, you often want to separate Game Logic (Data) from Game Feel (Visuals/Sound).
Use SetInspectorListenersActive(false) to mute the "Visual/Scene" layer while keeping the "Logic/Code" layer running.
Use Case: Fast-Forwarding or Loadingβ
Imagine loading a save file. You need to fire OnItemAdded 100 times to populate the inventory, but you don't want to play 100 sound effects or spawn 100 UI popups.
public void LoadSaveData(List<Item> items)
{
// 1. Mute the "flashy" stuff (Inspector bindings)
onItemAdded.SetInspectorListenersActive(false);
// 2. Process logic (Data listeners still run!)
foreach(var item in items)
{
// This updates the backend inventory data
// BUT skips the UI/Sound configured in Editor
onItemAdded.Raise(item);
}
// 3. Re-enable visuals
onItemAdded.SetInspectorListenersActive(true);
// 4. Refresh UI once
onInventoryUpdated.Raise();
}
π API Summaryβ
| Method Signature | Returns | Description |
|---|---|---|
| Immediate Execution | ||
Raise() | void | Fires a Void event immediately. |
Raise(T argument) | void | Fires a Single-Argument event immediately. |
Raise(TSender sender, TArgs args) | void | Fires a Sender+Argument event immediately. |
| Delayed Execution | ||
RaiseDelayed(float delay) | ScheduleHandle | Schedules a Void event to fire after delay seconds. |
RaiseDelayed(T arg, float delay) | ScheduleHandle | Schedules a Typed event to fire after delay seconds. |
RaiseDelayed(TSender s, TArgs a, float delay) | ScheduleHandle | Schedules a Sender event to fire after delay seconds. |
| Repeating Execution | ||
RaiseRepeating(float interval, int count) | ScheduleHandle | Starts a repeating loop. Set count to -1 for infinite. |
RaiseRepeating(T arg, float interval, int count) | ScheduleHandle | Starts a repeating Typed loop. |
RaiseRepeating(TSender s, TArgs a, float interval, int count) | ScheduleHandle | Starts a repeating Sender loop. |
| Cancellation & Control | ||
Cancel() | void | Stops any Inspector-configured auto-loops/delays for this event. |
CancelDelayed(ScheduleHandle handle) | bool | Cancels a specific manual delayed task. Returns true if successful. |
CancelRepeating(ScheduleHandle handle) | bool | Cancels a specific manual repeating task. Returns true if successful. |
SetInspectorListenersActive(bool isActive) | void | Mutes or unmutes the scene-based UnityEvent listeners at runtime. |