English | 한국어
A lightweight publish/subscribe (observer) message bus for Unity. Broadcast a notification from anywhere and let any number of receivers handle it, without direct references between them.
- No dependencies, no
MonoBehaviour, no scene object required - Observers are held by
WeakReference, so a destroyed receiver never keeps the bus alive - Optional object pooling for
Notificationinstances (NOTIFICATION_USE_POOL)
- Unity 2019.3 or later (required for installing packages via git URL)
Edit Packages/manifest.json in your Unity project and add this repository as a dependency:
{
"dependencies": {
"com.ez.notification-center": "https://github.com/ez8801/notification-center.git"
}
}Or in the Unity Editor: Window > Package Manager > + > Add package from git URL... and paste:
https://github.com/ez8801/notification-center.git
All types live in the Foundation.Notifications namespace.
A NotificationName is implicitly convertible to and from string. Collecting the names in one place avoids typos.
using Foundation.Notifications;
namespace R
{
public class Id
{
public static readonly NotificationName OnHpChanged = nameof(OnHpChanged);
public static readonly NotificationName OnMpChanged = nameof(OnMpChanged);
}
}Implement INotificationReceiver and register the receiver with the notification center.
using UnityEngine;
using UnityEngine.UI;
using Foundation.Notifications;
public class HpBar : MonoBehaviour, INotificationReceiver
{
[SerializeField]
private Slider _slider;
private void Awake()
{
// Start receiving OnHpChanged notifications.
NotificationCenter.Instance.AddObserver(this, R.Id.OnHpChanged);
}
public void HandleNotification(Notification notification)
{
if (notification.Name == R.Id.OnHpChanged)
{
_slider.value = notification.IntExtra / 100f;
}
}
private void OnDestroy()
{
NotificationCenter.Instance.RemoveObserver(this, R.Id.OnHpChanged);
}
}using Foundation.Notifications;
public class Player : MonoBehaviour
{
public int Hp
{
get => _hp;
set
{
_hp = value;
// Post a notification with a payload.
NotificationCenter.Post(R.Id.OnHpChanged, _hp);
}
}
private int _hp;
private void Pause()
{
// Post with no payload.
NotificationCenter.Post("OnPaused");
// Or build the notification yourself.
Notification notification = Notification.Create("OnPaused", true);
NotificationCenter.Post(notification);
}
}Posting is synchronous: Post returns after every registered receiver has handled the notification.
| Method | Behavior |
|---|---|
AddObserver(observer, name) |
Receives every notification posted under name until removed. |
AddDisposableObserver(observer, name) |
Receives name once; all disposable observers of that name are dropped after the post. |
AddUniversalObserver(observer) |
Receives every notification, regardless of name. |
| Member | Description |
|---|---|
NotificationCenter.Instance |
Lazily created singleton instance. |
AddObserver(INotificationReceiver, NotificationName) |
Register an observer for one notification name. Duplicate registrations are ignored. |
AddDisposableObserver(INotificationReceiver, NotificationName) |
Register a one-shot observer. |
AddUniversalObserver(INotificationReceiver) |
Register an observer for all notifications. |
RemoveObserver(INotificationReceiver, NotificationName) |
Unregister from one notification name. |
RemoveObserver(INotificationReceiver) |
Unregister from all notification names and from the universal list. |
RemoveAll() |
Clear every registered observer. |
static Post(Notification) |
Post a prebuilt notification. |
static Post(NotificationName) |
Post with no payload. |
static Post(NotificationName, T) |
Post with an int, float, long, string, bool, or object payload. |
A notification carries a name plus a fixed set of payload slots. Use the slot matching the type you posted.
| Member | Description |
|---|---|
Name |
The NotificationName this notification was posted under. |
IntExtra |
int payload. Backed by LongExtra — the two share one slot. |
LongExtra |
long payload. |
FloatExtra |
float payload. |
StringExtra |
string payload. |
BoolExtra |
bool payload. |
DataExtra |
object payload, for anything else. |
static Create(...) |
Create (or reuse, when pooled) a notification with an optional payload. |
Clear() |
Reset the name and every payload slot. |
- Always unregister. Observers are stored as weak references, so a dead receiver is skipped and pruned on the next post — but a receiver that outlives its usefulness keeps receiving. Pair
AddObserverinAwake/StartwithRemoveObserverinOnDestroy. RemoveObserver(observer, name)only removes named observers. To detach a universal or disposable observer, useRemoveObserver(observer)orRemoveAll().- Not thread-safe. Post and register from the main thread only.
- Pooling.
Notificationrecycles instances through a finalizer-backed pool (up to 512). Comment out#define NOTIFICATION_USE_POOLat the top ofRuntime/Notification.csto allocate a fresh instance every time. Because pooled instances are reused, do not hold on to aNotificationafterHandleNotificationreturns — copy out what you need.
A runnable Unity project lives in Sample~. It wires a Player that ticks HP/MP to an HpBar, MpBar, and an AbilityButton, all driven entirely by notifications. Open the folder as a Unity project and load Assets/Example/Scenes/ExampleScene.unity.
Distributed under the MIT License. See LICENSE for more information.