A powerful, type-safe event system for Unity with fluent interface design.
Overview
EventBus provides a robust, decoupled communication system for your Unity projects. Built with type safety and ease of use in mind, it offers a fluent interface for raising and listening to events, with or without payload data.
Key Features
Type-Safe Events: Uses interfaces for event definitions, ensuring compile-time type checking
Fluent Interface: Intuitive builder pattern for clear and concise event handling
Payload Support: Handle events with or without custom data payloads
Event Caching: Optional kick-start feature to receive the last event upon subscription
Zero Dependencies: Works right out of the box with no external dependencies
Why Use It?
Type-Safe Communication
No more string-based events or manual delegate management. Our EventBus ensures all event communications are type-safe and verified at compile time, eliminating runtime errors from typos or wrong event types.
Clean Architecture
Decoupled Systems: Services and components can communicate without direct references
Modular Design: Add or remove features without changing existing code
Easy Maintenance: Change internal logic without affecting other systems
Clear Dependencies: Easily track event flows through your application
Developer Experience
Intuitive API: Simple, fluent interface that's easy to understand and use
IDE Friendly: Full auto-completion support for better productivity
Reduced Boilerplate: No need to write custom event systems or manager classes
Quick Integration: Start using in minutes with minimal setup
Powerful Features
Event Caching: New subscribers can automatically receive the most recent event
Payload Support: Send any type of data with your events
Sender Tracking: Always know which component triggered an event
Flexible Subscription: Subscribe and unsubscribe at any time
Perfect For
Service Architecture: Connect independent services without tight coupling
UI Updates: Keep UI in sync with game state changes
Cross-Scene Communication: Share data between different scenes
State Management: Handle game state changes efficiently
Analytics Integration: Track game events without modifying core systems
Production Ready
Performance Optimized: Efficient event dispatching with minimal overhead
Memory Conscious: Small memory footprint with proper cleanup
Battle Tested: Reliable in production environments
Unity Friendly: Designed specifically for Unity projects
This lightweight yet powerful event system will help you build more maintainable and scalable Unity applications while reducing development time and potential bugs.
Quick Start
Define Your Event
// all event must be interface
public interface IGameStartEvent : IEvent { }
public interface IScoreUpdateEvent : IEvent { }
Listen to Events (subscribe)
// Event listener without payload
EventBus.Event<IGameStartEvent>() // set Event
.WithListener(OnGameStart) // set Listener
.Listen(); // subscribe
// Event listener with payload
EventBus.Event<IScoreUpdateEvent>() // set Event
.WithListener<int>(OnScoreUpdate) // set Listener with payload
.Listen(); // start listen
// Listener Methods
// all listener will receive sender as first parameter
// there is no limit on type of payload
private void OnGameStart(object sender) { }
private void OnScoreUpdate(object sender, int data) { }
// Event listener without payload
EventBus.Event<IGameStartEvent>() // set Event
.Unlisten(OnGameStart); // unsubscribe
// Event listener with payload
EventBus.Event<IScoreUpdateEvent>() // set Event
.Unlisten<int>(OnScoreUpdate); // unsubscribe
Event Caching
Use WithKickStart() when subscribing to automatically receive the most recent event data:
EventBus.Event<IScoreUpdateEvent>()
.WithListener<int>(OnScoreUpdate)
.WithKickStart() // Will immediately receive last score update
.Listen();
Advanced Usage
The following example demonstrates how EventBus can elegantly connect services and UI layers without direct references, using a weather monitoring system.
Adding listener method in Event Interface can confirm correct listener method in obsersers.
using System;
public interface IWeatherUpdateEvent : IEvent
{
// constrait observers to create listener with data type
OnWeatherUpdate(object sender, WeatherData data);
}
public struct WeatherData
{
public float Temperature;
public float Humidity;
public DateTime Timestamp;
}
using System;
using System.Collections;
using System.Threading.Tasks;
using AceLand.EventDriven.Bus;
using AceLand.TaskUtils;
using UnityEngine;
public class WeatherService : MonoBehaviour
{
[SerializeField] private float updateInterval = 300f; // 5 minutes
private void Start()
{
StartCoroutine(WeatherUpdateRoutine());
}
private IEnumerator WeatherUpdateRoutine()
{
while (true)
{
yield return new WaitForSeconds(updateInterval);
yield return FetchAndBroadcastWeather();
}
}
private Task FetchAndBroadcastWeather()
{
return Task.Run(async () =>
{
// Simulate web service call
var data = await FetchWeatherData();
// Broadcast to all listeners
// raise event in main thread
Promise.EnqueueToDispatcher(() =>
EventBus.Event<IWeatherUpdateEvent>()
.WithSender(this)
.WithData(data)
.Raise()
);
},
Promise.ApplicationAliveToken
);
}
// Simulate web service call
private Task<WeatherData> FetchWeatherData()
{
return Task.Run(() => new WeatherData
{
Temperature = 25.5f,
Humidity = 60f,
Timestamp = DateTime.Now
},
Promise.ApplicationAliveToken
);
}
}
using AceLand.EventDriven.Bus;
using AceLand.Test;
using TMPro;
using UnityEngine;
// add the event interface to confirm correct observer listener
public class WeatherUIController : MonoBehaviour, IWeatherUpdateEvent
{
[SerializeField] private TextMeshProUGUI temperatureText;
[SerializeField] private TextMeshProUGUI humidityText;
[SerializeField] private TextMeshProUGUI timestampText;
private void OnEnable()
{
// Subscribe with kick-start to get latest data immediately
EventBus.Event<IWeatherUpdateEvent>()
.WithListener<WeatherData>(OnWeatherUpdate)
.WithKickStart()
.Listen();
}
private void OnDisable()
{
EventBus.Event<IWeatherUpdateEvent>()
.Unlisten<WeatherData>(OnWeatherUpdate);
}
// promised correct listener
public void OnWeatherUpdate(object sender, WeatherData data)
{
// Update UI elements
temperatureText.text = $"{data.Temperature:F1}°C";
humidityText.text = $"{data.Humidity:F0}%";
timestampText.text = data.Timestamp.ToString("HH:mm:ss");
}
}
using System.Collections.Generic;
using AceLand.EventDriven.Bus;
using AceLand.Test;
using UnityEngine;
// add the event interface to confirm correct observer listener
public class WeatherAnalytics : MonoBehaviour, IWeatherUpdateEven
{
private List<WeatherData> weatherHistory = new List<WeatherData>();
private void OnEnable()
{
EventBus.Event<IWeatherUpdateEvent>()
.WithListener<WeatherData>(OnWeatherUpdate)
.Listen();
}
private void OnDisable()
{
EventBus.Event<IWeatherUpdateEvent>()
.Unlisten<WeatherData>(OnWeatherUpdate);
}
// promised correct listener
public void OnWeatherUpdate(object sender, WeatherData data)
{
// Store historical data
weatherHistory.Add(data);
// Analyze trends
AnalyzeWeatherTrends();
// Update analysis visualization
UpdateWeatherGraph();
}
private void AnalyzeWeatherTrends()
{
// Implement weather trend analysis
}
private void UpdateWeatherGraph()
{
// Update weather history visualization
}
}
This example demonstrates several powerful features of EventBus:
Service Decoupling: Services can communicate without direct references
Multiple Listeners: Both UI and Analytics respond to the same event
Automatic Updates: UI receives updates as soon as new data arrives
Clean Architecture: Clear separation between data providers and consumers
Best Practices
Define events as empty interfaces
Use meaningful interface names (e.g., IGameStartEvent, IPlayerDeathEvent)
Keep event payloads simple and serializable
Always unsubscribe when destroying objects to prevent memory leaks
Consider using WithKickStart() for state-based events
Comfirm correct listener method by adding method in Event interface