Simple Event System in Unity

Simple event system in Unity

You must use UnityEvent.

public UnityEvent whoa;

It is dead easy.

Make a script BigScript.cs

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

public class BigScript:MonoBehaviour
{
[Header("Here's a cool event! Drag anything here!")]
public UnityEvent whoa;
}

Put it on a game object. Now look at it in the Inspector.

You will see the "whoa" event.

Simply drag your other scripts to there, to make something happen, on those other scripts, when "whoa" happens.

Sample Image

It's that simple. To call the event in BigScript, it is just

    [Header("Here's a cool event! Drag anything here!")]
public UnityEvent whoa;

private void YourFunction()
{
whoa.Invoke();
}

In rare cases you may need to add a listener via code rather than simply dragging it in the Editor. This is trivial:

whoa.AddListener(ScreenMaybeChanged);

(Normally you should never have to do that. Simply drag to connect. I only mention this for completeness.)


That's all there is to it.

Be aware of out of date example code regarding this topic on the internet.


The above shows how to connect simple functions that have no argument.

If you do need an argument:

Here is an example where the function has ONE FLOAT argument:

Simply add THIS CODE at the top of the file:

[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}

then proceed as normal. It's that easy.

// ...
using UnityEngine.Events;

// add this magic line of code up top...
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}

public class SomeThingHappens : MonoBehaviour
{
// now proceed as usual:
public _UnityEventFloat changedLength;

void ProcessValues(float v)
{
// ...
changedLength.Invoke(1.4455f);
}
}

When you drag from your other function to the Editor slot on this function:

Be certain to use the section - "Dynamic float".

Sample Image

(Confusingly your function will also be listed in the "Static Parameters" section! That is a huge gotchya in Unity!)

How to use C# events in Unity3D

First of all check this tutorial : https://unity3d.com/learn/tutorials/topics/scripting/events

I would recommend using event Action. It is easier to use for beginners.

Example :

Class containing events:

public class EventContainer : MonoBehaviour
{
public event Action<string> OnShow;
public event Action<string,float> OnHide;
public event Action<float> OnClose;

void Show()
{
Debug.Log("Time to fire OnShow event");
if(OnShow != null)
{
OnShow("This string will be received by listener as arg");
}
}

void Hide()
{
Debug.Log("Time to fire OnHide event");
if(OnHide != null)
{
OnHide ("This string will be received by listener as arg", Time.time);
}
}



void Close()
{
Debug.Log("Time to fire OnClose event");
if(OnClose!= null)
{
OnClose(Time.time); // passing float value.
}
}
}

Class which handles events of EventContainer class:

public class Listener : MonoBehaviour
{
public EventContainer containor; // may assign from inspector


void Awake()
{
containor.OnShow += Containor_OnShow;
containor.OnHide += Containor_OnHide;
containor.OnClose += Containor_OnClose;
}

void Containor_OnShow (string obj)
{
Debug.Log("Args from Show : " + obj);
}

void Containor_OnHide (string arg1, float arg2)
{
Debug.Log("Args from Hide : " + arg1);
Debug.Log("Container's Hide called at " + arg2);
}

void Containor_OnClose (float obj)
{
Debug.Log("Container Closed called at : " + obj);
}

}

Unity how does event system know if i implement IDragHandler

The GetComponent function is the answer. It implements the interface if it does not return null. If it returns null, the interface is not implemented.

For example:

The interface:

public interface IDrag { }

The script that implements it:

public class MyScript : MonoBehaviour, IDrag{ }

To check if the MyScript script implements the IDrag interface, use the GetComponent function.

IDrag idrag = gameObject.GetComponent<IDrag>();
if (idrag != null)
Debug.Log("Implemeted IDrag");
else
Debug.Log("DID NOT Implement IDrag");

Use EventSystem for key-pressing events


Is there a way to do the following, using Unity's EventSystem? In other words, is there an implementation of an interface like IPointerClickHandler,

No. The EventSystem is mostly used for raycasting and dispatching events. This is not used to detect keyboard events. The only component from the EventSystem that can detect keyboard events is the InputField component. That's it and it can't be used for anything else.

Check whether a button is pressed, without doing so in an Update()
function?

Yes, there is a way with Event.KeyboardEvent and this requires the OnGUI function.

void OnGUI()
{
if (Event.current.Equals(Event.KeyboardEvent("W")))
{
print("W pressed!");
}
}

This is worse than using the Input.GetKeyDown function with the Update function. I encourage you to stick with Input.GetKeyDown. There is nothing wrong with it.


If you are looking for event type InputSystem without Input.GetKeyDown then use Unity's new Input API and subscribe to the InputSystem.onEvent event.

If you are looking for feature similar to the IPointerClickHandler interface you can implement it on top of Input.GetKeyDown.

1.First, get all the KeyCode enum with System.Enum.GetValues(typeof(KeyCode)); and store it in an array.

2.Create an interface "IKeyboardEvent" and add functions such as OnKeyDown just like OnPointerClick in the IPointerClickHandler interface.

3.Loop through the KeyCode from #1 and check if each key in the array is pressed, released or held down.

4.Get all the components in the scene and check if they implemented the IKeyboardEvent interface. If they do, invoke the proper function in the interface based on the key status from #3.

Here is a functional example that can still be extended or improved:

Attach to an empty GameObject.

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class KeyboardEventSystem : MonoBehaviour
{
Array allKeyCodes;

private static List<Transform> allTransforms = new List<Transform>();
private static List<GameObject> rootGameObjects = new List<GameObject>();

void Awake()
{
allKeyCodes = System.Enum.GetValues(typeof(KeyCode));
}

void Update()
{
//Loop over all the keycodes
foreach (KeyCode tempKey in allKeyCodes)
{
//Send event to key down
if (Input.GetKeyDown(tempKey))
senEvent(tempKey, KeybrdEventType.keyDown);

//Send event to key up
if (Input.GetKeyUp(tempKey))
senEvent(tempKey, KeybrdEventType.KeyUp);

//Send event to while key is held down
if (Input.GetKey(tempKey))
senEvent(tempKey, KeybrdEventType.down);

}
}


void senEvent(KeyCode keycode, KeybrdEventType evType)
{
GetAllRootObject();
GetAllComponents();

//Loop over all the interfaces and callthe appropriate function
for (int i = 0; i < allTransforms.Count; i++)
{
GameObject obj = allTransforms[i].gameObject;

//Invoke the appropriate interface function if not null
IKeyboardEvent itfc = obj.GetComponent<IKeyboardEvent>();
if (itfc != null)
{
if (evType == KeybrdEventType.keyDown)
itfc.OnKeyDown(keycode);
if (evType == KeybrdEventType.KeyUp)
itfc.OnKeyUP(keycode);
if (evType == KeybrdEventType.down)
itfc.OnKey(keycode);
}
}
}

private static void GetAllRootObject()
{
rootGameObjects.Clear();

Scene activeScene = SceneManager.GetActiveScene();
activeScene.GetRootGameObjects(rootGameObjects);
}


private static void GetAllComponents()
{
allTransforms.Clear();

for (int i = 0; i < rootGameObjects.Count; ++i)
{
GameObject obj = rootGameObjects[i];

//Get all child Transforms attached to this GameObject
obj.GetComponentsInChildren<Transform>(true, allTransforms);
}
}

}

public enum KeybrdEventType
{
keyDown,
KeyUp,
down
}

public interface IKeyboardEvent
{
void OnKeyDown(KeyCode keycode);
void OnKeyUP(KeyCode keycode);
void OnKey(KeyCode keycode);
}

Usage:

Implement the IKeyboardEvent interface and the functions from it in your script just like you would with IPointerClickHandler.

public class test : MonoBehaviour, IKeyboardEvent
{
public void OnKey(KeyCode keycode)
{
Debug.Log("Key held down: " + keycode);
}

public void OnKeyDown(KeyCode keycode)
{
Debug.Log("Key pressed: " + keycode);
}

public void OnKeyUP(KeyCode keycode)
{
Debug.Log("Key released: " + keycode);
}
}

Subscribe event Unity VR

What this error is saying is that when you subscribe to the "OnButtonSelected" event, the method you target (in your case, "Teleport") must accept a parameter of type VRStandardAssets.Menu.MenuButton.

This is how the event system tells your listener which button was selected.

So, you could use something like this:

void Teleport(VRStandardAssets.Menu.MenuButton buttonPressed)
{
// if you care which button, access buttonPressed parameter here..
Debug.Log("Hello");
}

(Note: for good programming practice though I would suggest naming this something other than "Teleport" - calling it something like "HandleMenuButton" or "MenuButtonPressed" keeps its intent clear; then inside that method you can call a separate "Teleport" function. In the future if you need to change the interaction, it will be easier to update the code if you maintain that level of separation.)



Related Topics



Leave a reply



Submit