Editorial illustration: Events between logic and presentation

Events between logic and presentation

The problem I needed to solve

When audio, interface and logging all react to gameplay, directly attaching them to every rule creates many dependencies. I needed a simple event boundary.

Implementation in this snapshot

GameEventBus exposes typed CardPlayed, RoundStarted, RoundEnded, GameStarted and GameEnded events. Its Publish methods pass their data to current subscribers.

The design decision and its cost

Typed events give consumers a specific contract. The tradeoff is that this is not a distributed messaging system; subscribers run within the same execution path.

Current boundaries

The bus does not isolate each subscriber’s exceptions. Subscription lifetime also belongs to the consumer. An event keyword alone does not prevent leaks or remove every dependency.

Is a card event a result or a request?

Suppose a player touches an illegal card and the interface wants to start its sound and movement. Publishing CardPlayed before validation would make listeners treat an unaccepted action as real. GameEventBus.PublishCardPlayed checks neither ownership, suit nor turn; it only forwards eventData. Its timing contract therefore matters: the game flow must establish validity and the intended state change before announcing the event. The bus cannot enforce the order of outside calls.

CardPlayedEvent carries the player, card instance, table-card count and play order. A listener can identify the card without interpreting button text. Read-only properties do not mean RuntimePlayer was copied, however. A listener consulting that reference later may see updated state. Historical logging needs an explicit distinction between values captured at publication and live references. The word Event does not settle that distinction.

Publish methods invoke delegates directly; they create no queue, separate scheduling or background processing. Heavy listeners extend the publication path, and the bus has no protected loop to continue through other listeners after an exception. This argues for small reactions and deliberate subscription lifetimes. Unity components can accumulate duplicate subscriptions across activation cycles. Consumers must pair registration with removal rather than assume that the bus manages their lifetime.

What this stage taught me

For me, events describe something that happened. Rules should establish a valid action first, and presentation and sound should react afterward; publishing does not replace gameplay validation.

Explore Dalo

Latest devlogs

Editorial illustration: Pasur launch and telemetry in the shared structure

Pasur launch and telemetry in the shared structure

Adding Pasur needs both a correct mode handoff and valid public telemetry.

Read article
Editorial illustration: Presenting selection and captures in Pasur

Presenting selection and captures in Pasur

Pasur motion should explain which hand card was played and which table cards were captured.

Read article
Editorial illustration: Pasur bot decisions from capture options

Pasur bot decisions from capture options

My teammate’s Pasur bot chooses among legal options without inspecting hidden opposing cards.

Read article
Dalo