EventBus
Namespace:
namespace Lenga\Engine\Core;
final class EventBus
EventBus is the process-wide decoupled event system.
For gameplay events, start here when listeners should react without holding a reference to the dispatcher. Use Signal only when a specific owner instance intentionally exposes an owner-scoped callback surface.
Inside Behaviours, prefer the Behaviour helpers emitEvent(...), onEvent(...), and onceEvent(...) unless you specifically need the raw static API.
Constants
UI_SELECTION_CHANGED
public const UI_SELECTION_CHANGED = 'ui.selection_changed';
Emitted by the engine when UI selection changes through the built-in navigation system.
The payload is an array with:
name: the event name stringviaPointer: whether pointer input caused the selectioncanvas: native lookup data for the canvasprevious: native lookup data for the previously selected UI element, ornullcurrent: native lookup data for the selected UI element, ornull
Methods
on
public static function on(string $eventName, callable $listener): SignalSubscription
Subscribes a listener and returns a SignalSubscription.
The listener receives the payload first and the event name second:
EventBus::on('game.round_started', function (array $payload, string $eventName): void {
// ...
});
If you are inside a Behaviour, prefer onEvent(...) so lifecycle cleanup is automatic.
addListener
public static function addListener(string $eventName, callable $listener): SignalSubscription
Alias for on(...).
subscribe
public static function subscribe(string $eventName, callable $listener): SignalSubscription
Alias for on(...).
once
public static function once(string $eventName, callable $listener): SignalSubscription
Subscribes a listener that automatically removes itself after the first event.
onceListener
public static function onceListener(string $eventName, callable $listener): SignalSubscription
Alias for once(...).
off
public static function off(string $eventName, SignalSubscription|callable $listener): void
Removes a subscription or callable listener from the event.
removeListener
public static function removeListener(string $eventName, SignalSubscription|callable $listener): void
Alias for off(...).
emit
public static function emit(string $eventName, mixed $payload = null): void
Dispatches a global event with one payload value.
dispatch
public static function dispatch(string $eventName, mixed $payload = null): void
Alias for emit(...).
clear
public static function clear(?string $eventName = null): void
Clears listeners for one event. If no event name is provided, clears all global event listeners.
Use this carefully. Most gameplay code should dispose the specific SignalSubscription it owns instead.
hasListeners
public static function hasListeners(string $eventName): bool
Returns whether the event currently has listeners.
listenerCount
public static function listenerCount(string $eventName): int
Returns the number of listeners for the event.
Example
use Lenga\Engine\Core\Behaviour;
final class Health extends Behaviour
{
public int $current = 100;
public string $kind = 'enemy';
public function applyDamage(int $amount): void
{
$this->current -= $amount;
if ($this->current <= 0) {
$this->emitEvent('game.health.died', [
'source' => $this,
'kind' => $this->kind,
]);
}
}
}
use Lenga\Engine\Core\Behaviour;
final class GameManager extends Behaviour
{
public function onEnable(): void
{
$this->onEvent('game.health.died', function (?array $payload): void {
if (($payload['kind'] ?? null) === 'player') {
$this->beginGameOverFlow();
}
});
}
private function beginGameOverFlow(): void
{
}
}
This pattern lets unrelated systems react to the same event without first finding the dispatcher.