When events can be based on distance or collisions, we can use OnTrigger
methods as described in the preceding recipe. When events are based on time periods, we can use coroutines, as described in a later recipe in this chapter. When there are other kinds of events, we can use C# delegates and events, as described in this recipe. These work in a similar way to SendMessage()
, but are much more efficient, since Unity has a defined list of the objects "listening" to the broadcast events. SendMessage()
should be avoided, since it means Unity has to analyze each scripted object ("reflect over" the object) to see whether there is a public method corresponding to the message that has been sent—this is much slower than using delegates and events.
Delegates and events implement the publish-subscribe (pubsub) design pattern. Objects can subscribe one of their methods to receive a particular type of event message from a particular publisher. In this recipe, we'll have a manager class displaying some color change buttons and publishing a new event for each button clicked; we'll also have a cube and a sphere that subscribe to the color change events, so each time a color change event is published, both the cube and the sphere should receive the event message and change their color accordingly. Publishers don't have to worry about how many objects subscribe to them at any point in time (it could be none, or 1000!), this is known as "loose coupling", since it allows different code components to be written (and maintained) independently, and this is a desirable feature of object-oriented code.
To implement delegates and events, perform the following steps:
ColorManager
to the Main Camera:// file: ColorManager.cs using UnityEngine; using System.Collections; public class ColorManager : MonoBehaviour { public delegate void ColorChangeHandler(Color newColor); public static event ColorChangeHandler changeColorEvent; void OnGUI(){ bool makeGreenButtonClicked = GUILayout.Button("make things GREEN"); bool makeBlueButtonClicked = GUILayout.Button("make things BLUE"); bool makeRedButtonClicked = GUILayout.Button("make things RED"); if(makeGreenButtonClicked) PublishColorChangeEvent( Color.green ); if(makeBlueButtonClicked) PublishColorChangeEvent( Color.blue ); if(makeRedButtonClicked) PublishColorChangeEvent( Color.red ); } private void PublishColorChangeEvent(Color newColor){ // if there is at least one listener to this event if(changeColorEvent != null){ // broadcast change color event changeColorEvent( newColor ); } } }
ColorChangeListener
to it:// file: ColorChangeListener.cs using UnityEngine; using System.Collections; public class ColorChangeListener : MonoBehaviour { void OnEnable() { ColorManager.changeColorEvent += OnChangeColor; } private void OnDisable(){ ColorManager.changeColorEvent -= OnChangeColor; } void OnChangeColor(Color newColor){ renderer.sharedMaterial.color = newColor; } }
m_cube
and add this to your cube.ColorChangeListener
component to it.m_sphere
and add this to your sphere.First let's consider what we want to happen—we want the cube and sphere to both change their color when they receive an event message OnChangeColor()
with a new color argument.
This is achieved by each object instance of the ColorChangeListener
class (there is one present as a component of the cube and one of the sphere), subscribing their OnChangeColor()
methods to listen for color change events published from the ColorManager
class. Since our scripted objects may be disabled and enabled at different times, each time a scripted ColorChangeListener
object is enabled (such as when its GameObject parent is instantiated), its OnChangeColor()
method is added (+=
) to the list of those subscribed to listen for color change events. Then each time ColorChangeListener
objects are disabled, those methods are removed (-=
) from the list of event subscribers.
When a ColorChangeListener
object receives a color change message, its subscribed OnChangeColor()
method is executed, and the color of the shared materials of the renderer component is changed to the received Color
value (green
/red
/blue
).
The ColorManager
class has a public class (static) variable changeColorEvent
, which defines an event to which Unity maintains a dynamic list of all the subscribed object methods. It is to this event that ColorChangeListener
objects register or deregister their methods.
The ColorManager
class displays three buttons to the user to make things green, red, and blue. When a button is clicked, the changeColorEvent
is told to publish a new event, passing a corresponding Color
argument to all subscribed object methods (that is, the cube and sphere).
The ColorManager
class declares a delegate named ColorChangeHandler
. Delegates define the return type (in this case void
) and argument "signature" of methods that can be delegated (subscribed) to an event. In this case, methods must have the argument signature of a single parameter of type Color
. Our OnChangeColor()
method in the ColorChangeListener
class matches this argument signature, and so it is permitted to subscribe to the changeColorEvent
in class ColorManager
.
An easy-to-understand video about Unity delegates and events can be found at http://www.youtube.com/watch?v=N2zdwKIsXJs.
3.129.72.176