# Event Queue
## Pattern Scope
**Event Queues** are a powerful tool that help make executions **synchronized** and ensure the user **perceives visual feedback in order**..
The main idea is to create a **linear execution** of elements **based on their order of entrance**.
Patterns like:
- [[00-bytecode]]
- [[02-finite_state_machine]]
- [[00-double_buffer]]
- [[00-data_locality]]
- [[00-command]]
share similar concepts or **fit very well** with the _event queue_ approach.
A practical example of applying this pattern would be an **in-game shop**.
A player's **speed of interaction** (e.g., buying multiple items) is usually _faster_ than the **visual feedbacks** attached to each action.
So, if the player buys _five items in less than three seconds_, and each feedback takes _one second_ to display, we can use an **event queue** to:
- Avoid triggering multiple feedbacks simultaneously (if one is already playing).
- **Enqueue** all feedbacks and **execute them linearly**.
When working with **visual feedback**, it’s important to **maintain consistency** with the approach used throughout the game, this preserves **visual coherence**..
Another example is **server requests**, an event queue helps to prevent sending _100 new requests before the first one finishes_.
### <img src="00-assets/01-images/02-icons/code-icon-36x36.png" align="left" width="24px" height ="24px" style="margin:2px" /> Pattern Application
Let’s use the **shop item** example. We can:
- Make a **direct call** from the _shop controller_ to the _UI_ (using an **OOP**[^1] and **controller-view**[^2] approach).
- Use **event notifications** to communicate between systems (**EOP**[^1]), letting the UI know when something is bought.
- Use a **looping system** to check data changes in each item and decide when to update the UI and logic controllers (a **DOP**[^1] and **ECS**[^3] approach).
These are just examples, _choose what best fits your architecture._
```csharp
public void BuyItem(ShopItem item)
{
//Code
//Notify element to be bought
this.notifyBoughtItemEvent?.Invoke(this, item);
}
```
> [!CAUTION]
> This feedback is **conceptual and oversimplified**.
```csharp
public class UIFeedbackCommand : ISimpleCommand, ICommandData, ICommandEvents<object>
{
private readonly Sprite sprite;
private readonly GameObject targetFeedbackGO;
private Coroutine feedbackCoroutine;
#region ICommandData_Values
public bool IsCommandRunning => this.feedbackCoroutine != null;
#endregion
#region ICommandEvents_Values
public event Action<Coroutine> CommandStarted;
public event Action<Coroutine> CommandEnded;
#endregion
public UIFeedbackCommand(Sprite sprite, GameObject targetFeedbackGO)
{
this.sprite = sprite;
this.targetFeedbackGO = targetFeedbackGO;
}
//A punch animation on the sprite can be a good feedback
private IEnumerator PunchFeedback()
{
CommandStarted?.Invoke(this, this.feedbackCoroutine);
//Execute & wait the visuals
var currentCoroutine = this.feedbackCoroutine;
this.feedbackCoroutine = null;
CommandEnded?.Invoke(this, currentCoroutine);
}
#region ISimpleCommand_Methods
public void Execute()
{
if(IsCommandRunning)
return;
this.feedbackCoroutine = targetFeedbackGO.StartCoroutine(PunchFeedback());
}
#endregion
}
```
```csharp
private readonly Queue<UIFeedbackCommand> feedbackQueue = new();
public void OnItemBoughResponse(object sender, ShopItem item)
{
var feedbackCommand = new UIFeedbackCommand(item.sprite, item.gameObject);
this.feedbackQueue.Enqueue(feedbackCommand);
if(this.feedbackQueue.Count == 1)
this.feedbackQueue[0].Execute();
}
private void OnFeedbackCommandEndsResponse(object sender, Coroutine args)
{
//Run next command and unsubcribe of the command
(UIFeedbackCommand)sender.CommandEnded -= OnFeedbackCommandEndsResponse;
this.feedbackQueue.Dequeue();
if(this.feedbackQueue.Count > 0)
this.feedbackQueue[0].Execute();
}
```
As you can see, the **feedbacks are stacked**, and they’re **executed linearly** until the queue is empty.
Even though these examples are conceptual, the **core idea** is clearly represented.
### <img src="100-assets/01-images/02-icons/info-icon-36x36.png" align="left" width="24px" height ="24px" style="margin:2px" /> Considerations
> [!WARNING]
> If you are using **events** to trigger the next element, be **careful to unsubscribe** from all of them if the flow is **interrupted**.
# References
- [Game Programming Patterns by Robert Nystrom](https://gameprogrammingpatterns.com/event-queue.html)
[^1]: [[01-programming_paradigms]]
[^2]: [[04-controller_view]]
[^3]: [[03-ecs_architecture]]