Event Manager Example

Hi!

I started playing with the Observable to send events to multiple classes to avoid any references between them. After all, the objective for each class is to be completely separated.

At the moment, Im doing something like this, which I think is not ideal.

Class A

// Define Events
private static onCharacterMove = new Observable();
public static addOnCharacterMoveObserver(callback) {
	Character.onCharacterMove.add(callback);
}

// Trigger event
Character.onCharacterMove.notifyObservers('');

Class B

// Listen to Events
Character.addOnCharacterMoveObserver(() => {
	// Do stuff
});

I was wondering if there was some kind of EventManager where I could simply define a string as the event. Something a bit like this:

public addOnEvent(eventName: string, callback: (data?: any) => void) {
	this.eventEmitter.addListener(eventName, callback);
}

public removeOnEvent(eventName: string, callback: (data?: any) => void) {
	this.eventEmitter.removeListener(eventName, callback);
}

I tried looking everywhere for an example but I dont see any.

Thanks

1 Like

Hey @Rangerz132!
With pure JS you can use CustomEvent but it requires the DOM element from which you dispatch the event and on which you’re listening.

So having eg. <div id="root"></div> you can then do things like

const rootEl = document.getElementById("root");

// to dispatch the event
const event = new CustomEvent("eventName", {
  detail: 'some data',
});

rootEl.dispatchEvent(event);

// to listen on that event
rootEl.addEventListener("eventName", (ev) => {
  console.log(ev.detail); // 'some data'
});
1 Like

Thanks for the quick response! It is really appreciated! :slight_smile: However, I was wondering if it was possible to use the built-in Observable from Babylon to create something similar.

I would have a Class called EventManager which would be a Singleton. This class would contained a method to add Events and another method to remove Events. The methods would contained a strings to define the Event.

Then, since the EventManager Class is a Singleton, any classes in my game would be able to access the EventManager Class to send messages.

I’m still a bit loss with all the javascript/typescript stuff. I usually work with Unity :yum:

Thanks

Okey :slight_smile:
It does sound totally possible.
You can find here how to create observables

Additionally, in the JS World the RXJS library is popular when talking about observables. So you might want to take a look at this

All of this is because the class syntax in the JS is just a syntact sugar and a lot of people prefer to write in a functional way.

Hi,

You could use for example one of the following packages :

So instead of

public addOnEvent(eventName: string, callback: (data?: any) => void) {
	this.eventEmitter.addListener(eventName, callback);
}

you write

#eventEmitter = new EventEmitter2()
public on(eventName : string, callback : (data?:any)=> void) {
	return this.#eventEmitter.on(eventName, callback)
}

trigger(eventName, data) {
    this.#eventEmitter.emit(eventName, data)
}

The main problem is types, for examples if the callback’s signature depends on the eventName.
One solution is function overloading

public on('custom-event-1', callback : (data : string) => void)
public on('custom-event-2', callback : (data : number) => void)
public on(eventName : string, callback : (data?:any)=> void) {
	this.#eventEmitter.on(eventName, callback)
}

It’s great but I think Observable are better because of the way you can unsubscribe

#observable = new Observable<string>()
get customEvent1() {
    return this.#observable
}

triggerCustomEvent1() {
   this.#observable.notifyObservers("hello world")
}

And in your other class

const observer = instance.customEvent1.add((data : string) => {

}

To stop listening

 instance.customEvent1.remove(observer)

Si I think you are trying to make something between the built-in Observable and eventEmitter, it’s still possible but I don’t think it’s a good pattern :slightly_smiling_face:

const eventObservableMap = new Map<string, Observable<any>>()

EventManager.addOnEvent = (eventName: string, callback: (data?: any) => void) => {
    if(eventObservableMap.has(eventName)) {
        eventObservableMap.get(eventName).add(callback)
    }
    else {
        eventObservableMap.set(eventName, new Observable<any>())
        eventObservableMap.get(eventName).add(callback)
    }
}

EventManager.triggerEvent = (eventName : string, data : any) {
   if(eventObservableMap.has(eventName)) {
        eventObservableMap.get(eventName).notifyObservers(data)
   }
}

Thanks @sharp !

a good old publish subscribe pattern still works great for me :wink: I wrote my own that does instance or global events , its actually pretty straight forward code. Can use it within any code environment or framework , babylon , vue … whatever… its just storing and calling functions :wink:

Arrays of functions mapped to keys.

1 Like