Giter Club home page Giter Club logo

sharphooks's Introduction

Event Bus System for Unity

Provides support for indirectly passing custom messages between objects, making event-driven architecture easy, safe, and decoupled. Minimal setup, similar in syntax to the builtin OnPointerClick or OnCollisionEnter.

Getting Started

  1. Create a data type for your custom message
  2. Receiver must inherit from ScopedListener, which will automatically manage registration in the MonoBehaviour lifecycle
  3. Create a function in the receiver to receive the event
  4. Fire the event!
//Step 1
public class InteractEvent : Event
{
	public Player player;
	public Interactable interactedObject;
}

//Step 2
public class LightSwitch : ScopedListener
{
	//Step 3
	[EventHandler]
	void HandleLightsToggle(InteractEvent e) //This function can be named anything
	{
		if(e.interactedObject == this) connectedLight.enabled = !connectedLight.enabled;
	}
}

//Step 4 - Player.cs
InteractEvent e = new InteractEvent { player = this, interactedObject = objectUnderCursor };
EventBus.Main.Dispatch(e);

More advanced use

Event handling functions can be named anything, so long as the parameter type matches and the function is marked EventHandler. This also means that multiple EventHandlers can be defined in the same script for the same type, allowing easy processing of events.

ScopedListener is a convenience, but the IListener interface allows for finer control over registration, or a listener that isn't a unity object. By default ScopedListener registers the whole class using EventBus.Main.RegisterStaticHandlers / EventBus.Main.UnregisterAllHandlers. Managing specifically callbacks dynamically (not on enable/disable) is also possible, and supports lambdas and local functions as well.

Applications

No matter where an event is fired from, it will reach all valid listeners. This makes it useful for decoupling. For example, an achievement for "Deal at least 100 damage in a single hit" or "Harvest 30 rutabaga" would listen for a DamageEvent or CropHarvestEvent. This also helps maintainability, as putting achievement code in the combat system or interaction controller would make reading difficult. Robert Nystrom explains this application in detail: https://gameprogrammingpatterns.com/event-queue.html

This implementation can also be used like a query, or like the Builder pattern, with the message object treated as an accumulator. To implement an equippable trinket that grants +25 fire damage on attacks and -12% resistance to water damage, the item can listen for a DamageEvent and modify the damage value before it is applied. Priority.Final is equivalent to Builder.Build().

The query approach includes consuming and cancelling events. Consuming can be useful for inputs that should only reach one target. Cancelling can be useful for status effects and abilities, such as blocking the first projectile from a direction and reducing all further damage from that direction by 10%.

However, events should NOT be used as a replacement for Update, since the indirection layers have an overhead. They are intended for relatively infrequent, unpredictable inversion of control.

Inspiration

Messaging use inspired by patterns such as Observer, Event Bus, and Pub/Sub. Query use with mutable events inspired by the event buses of MinecraftForge and Bukkit. Unintentionally similar to Guava's EventBus.

sharphooks's People

Contributors

rmminusr avatar

Stargazers

Sebastien Vermeille avatar Alexandre Tolstenko avatar  avatar

Watchers

 avatar  avatar

sharphooks's Issues

Upcasting events handles them out of order

Steps to reproduce:

Implement handler function 1A for an event type, set to execute first
Implement handler function 1B for an event type, set to execute last
Implement handler function 2A for the event's parent type, set to execute first
Implement handler function 2B for the event's parent type, set to execute last
Trigger event

Result: Inconsistent, depending on dictionary key hashing. Might execute as 1A 1B 2A 2B, or 2A 2B 1A 1B.
Intended result: 1A 2A 1B 2B

Cannot add/remove listeners while an event is being dispatched

While an event is being dispatched, attempting to subscribe or unsubscribe listeners will raise a "collection has changed" exception.

To fix this, there would need to be a buffer of items to add or remove, and applied after the event has finished dispatching. For safety, the event should not reach the new listeners.

Static scanning can't find EventHandler annotation on inherited methods

Steps to replicate:

Write class as IListener
Add virtual or abstract method
Tag with EventHandler
Write new class, inherit from first class
Override method, but DO NOT tag new method with EventHandler
Trigger event

Result: Event does not reach method
Intended result: Event reaches method

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.