Start

Theory

Reference

Examples

Events & signals

Decoupled communication lets one part of the program announce that something happened without knowing who cares.

The concept

Two common patterns: an event stream, where the platform produces a sequence of typed messages that code polls or receives, and signals and slots, where a producer exposes a typed signal and any number of listeners (slots) connect callbacks to it. Both remove direct dependencies between the sender and its receivers.

Why decouple?

If the player code calls the HUD directly, the player depends on the HUD, and the HUD cannot be removed or tested without it. With an announcement instead ("score changed"), the producer neither knows nor cares who listens: the HUD, an achievement tracker and a sound effect can all react, and none of them is named in the player code.

Polling versus callbacks

An event stream is usually pulled: the loop drains a queue once per frame and handles each message in order, so all reactions happen at a predictable point. A signal is pushed: the slots run immediately, inside the call that emitted it. Push is convenient but means arbitrary code runs in the middle of the emitter's work, so a slot that modifies the very collection being iterated can cause trouble.

Lifetimes

The classic bug of callbacks is the dangling listener: an object is destroyed but its callback is still registered, and the next emit calls into freed memory. Any signal design therefore needs a way to disconnect, either explicitly or automatically when the listener goes away.

How ASGE does it

System events

SDL events are translated once, in event::_internal::ProcessEvent, into asge::event::SystemEvent: a std::variant over QuitEvent, WindowEvent, KeyboardEvent, MouseMotionEvent, MouseButtonEvent, MouseWheelEvent and UnknownEvent. Game code never sees SDL types; it asks for the case it cares about with TryGet<EventT>(), which returns a pointer or null. Application forwards each event to the input system and then to Game::OnSystemEvent.

state.cpp
void OnSystemEvent( asge::event::SystemEvent const& inSysEvent ) override
{
    if ( auto const* key = inSysEvent.TryGet<asge::event::KeyboardEvent>() )
    {
        // react to the key press
    }
}

Signals

asge::signals::Signal<Args...> is a thread-safe, type-checked signal: every slot must have the signature of the signal. Connect() returns a Connection. A connection ends when you call Disconnect() or when the optional lifetime token (a weak pointer you pass to Connect()) expires. Dead connections are pruned automatically on the next Emit().

signals.cpp
asge::signals::Signal<int> onScore;

// Slot signature must match the signal's: void(int)
auto connection = onScore.Connect( []( int points ) { /* update HUD */ } );

onScore.Emit( 10 );        // runs every connected slot
connection.Disconnect();   // or pass a lifetime token to Connect() for automatic cleanup

Choosing

System events carry what the OS reports; signals are for your own code, for example a gameplay system announcing a score change to the HUD.

See also

Source: Events/Events.hpp, Core/Patterns/Signal.hpp. Input demo