Events: Creating a simple messaging system

Checked with version: 5

-

Difficulty: Intermediate

As an introduction to UnityActions and UnityEvents, we will create a simple messaging system which will allow items in our projects to subscribe to events, and have events trigger actions in our games. This will reduce dependencies and allow easier maintenance of our projects. Tutor - Adam Buckner

Events: Creating a simple messaging system

Intermediate Scripting

Download the project audio files (including Character Scream and Pop sounds) HERE.

EventManager

Code snippet

using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;

public class EventManager : MonoBehaviour {

    private Dictionary <string, UnityEvent> eventDictionary;

    private static EventManager eventManager;

    public static EventManager instance
    {
        get
        {
            if (!eventManager)
            {
                eventManager = FindObjectOfType (typeof (EventManager)) as EventManager;

                if (!eventManager)
                {
                    Debug.LogError ("There needs to be one active EventManger script on a GameObject in your scene.");
                }
                else
                {
                    eventManager.Init (); 
                }
            }

            return eventManager;
        }
    }

    void Init ()
    {
        if (eventDictionary == null)
        {
            eventDictionary = new Dictionary<string, UnityEvent>();
        }
    }

    public static void StartListening (string eventName, UnityAction listener)
    {
        UnityEvent thisEvent = null;
        if (instance.eventDictionary.TryGetValue (eventName, out thisEvent))
        {
            thisEvent.AddListener (listener);
        } 
        else
        {
            thisEvent = new UnityEvent ();
            thisEvent.AddListener (listener);
            instance.eventDictionary.Add (eventName, thisEvent);
        }
    }

    public static void StopListening (string eventName, UnityAction listener)
    {
        if (eventManager == null) return;
        UnityEvent thisEvent = null;
        if (instance.eventDictionary.TryGetValue (eventName, out thisEvent))
        {
            thisEvent.RemoveListener (listener);
        }
    }

    public static void TriggerEvent (string eventName)
    {
        UnityEvent thisEvent = null;
        if (instance.eventDictionary.TryGetValue (eventName, out thisEvent))
        {
            thisEvent.Invoke ();
        }
    }
}

EventTest

Code snippet

using UnityEngine;
using UnityEngine.Events;
using System.Collections;

public class EventTest : MonoBehaviour {

    private UnityAction someListener;

    void Awake ()
    {
        someListener = new UnityAction (SomeFunction);
    }

    void OnEnable ()
    {
        EventManager.StartListening ("test", someListener);
        EventManager.StartListening ("Spawn", SomeOtherFunction);
        EventManager.StartListening ("Destroy", SomeThirdFunction);
    }

    void OnDisable ()
    {
        EventManager.StopListening ("test", someListener);
        EventManager.StopListening ("Spawn", SomeOtherFunction);
        EventManager.StopListening ("Destroy", SomeThirdFunction);
    }

    void SomeFunction ()
    {
        Debug.Log ("Some Function was called!");
    }
    
    void SomeOtherFunction ()
    {
        Debug.Log ("Some Other Function was called!");
    }
    
    void SomeThirdFunction ()
    {
        Debug.Log ("Some Third Function was called!");
    }
}

EventTriggerTest

Code snippet

using UnityEngine;
using System.Collections;

public class EventTriggerTest : MonoBehaviour {


    void Update () {
        if (Input.GetKeyDown ("q"))
        {
            EventManager.TriggerEvent ("test");
        }

        if (Input.GetKeyDown ("o"))
        {
            EventManager.TriggerEvent ("Spawn");
        }

        if (Input.GetKeyDown ("p"))
        {
            EventManager.TriggerEvent ("Destroy");
        }

        if (Input.GetKeyDown ("x"))
        {
            EventManager.TriggerEvent ("Junk");
        }
    }
}

DestroyByTimeExtended

Code snippet

using UnityEngine;
using System.Collections;

public class DestroyByTimeExtended : MonoBehaviour {

    public float lifeTime;
    // Use this for initialization
    void Start () {
        Destroy (gameObject, lifeTime);
        GetComponent <AudioSource>().pitch = Random.Range (0.75f, 1.25f);
    }
}

SelfDestruct

Code snippet

using UnityEngine;
using UnityEngine.Events;
using System.Collections;

public class SelfDestruct : MonoBehaviour {

    public GameObject explosion;

    private float shake = 0.2f;
    private AudioSource audioSource;
        
    void Awake () 
    {
        audioSource = GetComponent <AudioSource>();
    }
    
    void OnEnable () 
    {
        EventManager.StartListening ("Destroy", Destroy);
    }
    
    void OnDisable () 
    {
        EventManager.StopListening ("Destroy", Destroy);
    }
    
    void Destroy () 
    {
        EventManager.StopListening ("Destroy", Destroy);
        StartCoroutine (DestroyNow());
    }

    IEnumerator DestroyNow() 
    {
        yield return new WaitForSeconds (Random.Range (0.0f, 1.0f));
        audioSource.pitch = Random.Range (0.75f, 1.75f);
        audioSource.Play ();
        float startTime = 0;
        float shakeTime = Random.Range (1.0f, 3.0f);
        while (startTime < shakeTime) 
        {
            transform.Translate (Random.Range (-shake, shake), 0.0f, Random.Range (-shake, shake));
            transform.Rotate ( 0.0f, Random.Range (-shake * 100, shake * 100), 0.0f);
            startTime += Time.deltaTime;
            yield return null;
        }
        Instantiate (explosion, transform.position, transform.rotation);
        Destroy (gameObject);
    }
}

Spawner

Code snippet

using UnityEngine;
using UnityEngine.Events;
using System.Collections;

public class Spawner : MonoBehaviour {

    public int spawnCount;
    [Range (1,100)]
    public int spawnSize = 1;
    public float minionOffset = 1;
    public GameObject minion;

//  private UnityAction spawnListener;
//
//  void Awake () {
//      spawnListener = new UnityAction (Spawn);
//  }

    void OnEnable () {
//      EventManager.StartListening ("Spawn", spawnListener);
        EventManager.StartListening ("Spawn", Spawn);
    }

    void OnDisable () {
//      EventManager.StopListening ("Spawn", spawnListener);
        EventManager.StopListening ("Spawn", Spawn);
    }

    void Spawn () {
        for (int i = 0; i < spawnCount; i++) {
            Vector3 spawnPosition = GetSpawnPosition ();

            Quaternion spawnRotation = new Quaternion ();
            spawnRotation.eulerAngles = new Vector3 (0.0f, Random.Range (0.0f, 360.0f));
            if (spawnPosition != Vector3.zero) {
                Instantiate (minion, spawnPosition, spawnRotation);
            }
        }
    }

    Vector3 GetSpawnPosition () {
        Vector3 spawnPosition = new Vector3 ();
        float startTime = Time.realtimeSinceStartup;
        bool test = false;
        while (test == false) {
            Vector2 spawnPositionRaw = Random.insideUnitCircle * spawnSize;
            spawnPosition = new Vector3 (spawnPositionRaw.x, minionOffset, spawnPositionRaw.y);
            test = !Physics.CheckSphere (spawnPosition, 0.75f);
            if (Time.realtimeSinceStartup - startTime > 0.5f) {
                Debug.Log ("Time out placing Minion!");
                return Vector3.zero;
            }
        }
        return spawnPosition;
    }
}

Scripting

  1. Scripts as Behaviour Components
  2. Variables and Functions
  3. Conventions and Syntax
  4. C# vs JS syntax
  5. IF Statements
  6. Loops
  7. Scope and Access Modifiers
  8. Awake and Start
  9. Update and FixedUpdate
  10. Vector Maths
  11. Enabling and Disabling Components
  12. Activating GameObjects
  13. Translate and Rotate
  14. Look At
  15. Linear Interpolation
  16. Destroy
  17. GetButton and GetKey
  18. GetAxis
  19. OnMouseDown
  20. GetComponent
  21. Delta Time
  22. Data Types
  23. Classes
  24. Instantiate
  25. Arrays
  26. Invoke
  27. Enumerations
  28. Switch Statements
  1. Properties
  2. Ternary Operator
  3. Statics
  4. Method Overloading
  5. Generics
  6. Inheritance
  7. Polymorphism
  8. Member Hiding
  9. Overriding
  10. Interfaces
  11. Extension Methods
  12. Namespaces
  13. Lists and Dictionaries
  14. Coroutines
  15. Quaternions
  16. Delegates
  17. Attributes
  18. Events
  1. Building a Custom Inspector
  2. The DrawDefaultInspector Function
  3. Adding Buttons to a Custom Inspector
  1. MonoDevelop's Debugger
  2. Good Coding Practices in Unity
  3. Unity Editor Extensions – Menu Items
  4. Creating Meshes
  1. AssetBundles and the AssetBundle Manager
  2. Mastering Unity Project Folder Structure - Version Control Systems
  1. Installing Tools for Unity Development
  2. Building your first Unity Game with Visual Studio
  3. Editing Unity games in Visual Studio
  4. Debugging Unity games in Visual Studio
  5. Graphics debugging Unity games in Visual Studio
  6. Taking Unity games to Universal Windows Platform
  7. Testing Unity games on Android in Visual Studio
  1. Scripting Primer and Q&A
  2. Scripting Primer and Q&A - Continued
  3. Scripting Primer and Q&A - Continued (Again)
  4. Persistence - Saving and Loading Data
  5. Object Pooling
  6. Introduction to Scriptable Objects
  7. How to communicate between Scripts and GameObjects
  8. Coding in Unity for the Absolute Beginner
  9. Sound Effects & Scripting
  10. Editor Scripting Intro
  11. Writing Plugins
  12. Property Drawers & Custom Inspectors
  13. Events: Creating a simple messaging system
  14. Ability System with Scriptable Objects
  15. Character Select System with Scriptable Objects
  1. Intro and Setup
  2. Data Classes
  3. Menu Screen
  4. Game UI
  5. Answer Button
  6. Displaying Questions
  7. Click To Answer
  8. Ending The Game and Q&A
  1. Intro To Part Two
  2. High Score with PlayerPrefs
  3. Serialization and Game Data
  4. Loading Game Data via JSON
  5. Loading and Saving via Editor Script
  6. Game Data Editor GUI
  7. Question and Answer
  1. Overview and Goals
  2. Localization Data
  3. Dictionary, JSON and Streaming Assets
  4. Localization Manager
  5. Startup Manager
  6. Localized Text Component
  7. Localized Text Editor Script
  8. Localization Q&A
  1. Introduction and Session Goals
  2. Particle Launcher
  3. Particle Collisions
  4. ParticleLauncher Script
  5. Particle Collisions and Scripting
  6. Random Particle Colors
  7. Drawing Decals with Particles
  8. Collecting Particle Information For Display
  9. Displaying Particles Via Script
  10. Droplet Decals
  11. Questions and Answers