Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Multi-Input UnityEvent

Discussion in 'Scripting' started by Tidvis_Martin, Mar 20, 2019.

  1. Tidvis_Martin

    Tidvis_Martin

    Joined:
    Mar 12, 2019
    Posts:
    24
    Heyo Unity forum!
    I'm working on a type of trigger zone/trigger object script using the unity event system and trying to make the script as versatile as possible. Currently, I am trying to make it update a playerpref when either clicked or entered, however I am having some issues with this as by default the event system does not seem to like having to deal with two inputs and when specifying for it to use two inputs I have to specify the type, IE int, float, string, however specifying these would mean that if I have a string pref and an int pref I'd need to make several events just for the different types of prefs which I'd like to avoid.

    Does anyone know of a way to make the type that I feed the unity event be variable so I can use floats, string, ints etc as I choose?

    And also as a side note, I'm having some issues even getting the two input unity event to work properly since while I can deduce what line does what I am kinda out of my depth of understanding with this. Does if the above request is not possible could someone help me nudge the code to where it needs to be to make it run and allow me to input a string and an int into my unity event?

    Thanks so much for the read!

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using UnityEngine.Events;
    5. using UnityEngine.EventSystems;
    6.  
    7. public class ZoneTrigger_T2 : MonoBehaviour, IPointerClickHandler
    8. {
    9.  
    10.     public void OnPointerClick(PointerEventData eventData)
    11.     {
    12.         ClickEventTriggered(string, int);
    13.     }
    14.  
    15.     public void OnTriggerEnter(Collider other)
    16.     {
    17.         if (other.tag == "Player")
    18.         {
    19.             EnterEventTriggered(string, int);
    20.         }
    21.     }
    22.  
    23.     [Serializable]
    24.     public class ClickEvent : UnityEvent <string, int> {}
    25.  
    26.     [SerializeField]
    27.     private ClickEvent clickEvent = new ClickEvent();
    28.     public ClickEvent onClickEvent { get { return clickEvent; } set { clickEvent = value; } }
    29.  
    30.     public void ClickEventTriggered(string s, int i)
    31.     {
    32.         onClickEvent.Invoke(s,i);
    33.     }
    34.  
    35.     [Serializable]
    36.     public class EnterEvent : UnityEvent <string, int> {}
    37.  
    38.     [SerializeField]
    39.     private EnterEvent enterEvent = new EnterEvent();
    40.     public EnterEvent onEnterEvent { get { return enterEvent; } set { enterEvent = value; } }
    41.  
    42.     public void EnterEventTriggered(string s, int i)
    43.     {
    44.         onEnterEvent.Invoke(s,i);
    45.     }
    46. }
    47.  
     
  2. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    never tried this, but cant you just say T as the type and have a bit of logic seeing whats the type in runtime?
     
  3. WarmedxMints

    WarmedxMints

    Joined:
    Feb 6, 2017
    Posts:
    1,035
    As it is a MonoBehaviour and you have a collider on it, you can just use OnMouseDown which will be called when the mouse if clicked when over the object. There is also no need to create the same event type twice.

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using UnityEngine.Events;
    4.  
    5. public class ZoneTrigger_T2 : MonoBehaviour
    6. {
    7.     [Serializable]
    8.     public class StringIntEvent : UnityEvent<string, int> { }
    9.  
    10.     public StringIntEvent onClickEvent;
    11.     public StringIntEvent onEnterEvent;
    12.  
    13.     public void OnMouseDown()
    14.     {
    15.         ClickEventTriggered("Mouse Down", 0);
    16.     }
    17.  
    18.     public void OnTriggerEnter(Collider other)
    19.     {
    20.         if (other.tag == "Player")
    21.         {
    22.             EnterEventTriggered("Player", 1);
    23.         }
    24.     }
    25.  
    26.     public void ClickEventTriggered(string s, int i)
    27.     {
    28.         onClickEvent.Invoke(s, i);
    29.     }
    30.  
    31.     public void EnterEventTriggered(string s, int i)
    32.     {
    33.         onEnterEvent.Invoke(s, i);
    34.     }
    35. }
    As for a generic event which you can send anything over. Rather than convert back and forth, you could create a class which contains everything you may want to send in the event and create an event for that.

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using UnityEngine.Events;
    4.  
    5. public class ZoneTrigger_T2 : MonoBehaviour
    6. {
    7.     [Serializable]
    8.     public class MyEvent : UnityEvent<MyEventArgs> { }
    9.  
    10.     public MyEvent onClickEvent;
    11.     public MyEvent onEnterEvent;
    12. }
    13.  
    14. public class MyEventArgs
    15. {
    16.     public string s;
    17.     public int i;
    18.     public float f;
    19.     public GameObject go;
    20.     public Transform t;
    21.     //And so on
    22. }
     
  4. Tidvis_Martin

    Tidvis_Martin

    Joined:
    Mar 12, 2019
    Posts:
    24
    Thanks for the reply and code @WarmedxMints !

    I've had a poke around with it and tried to mash the two snippets you provided together, let me also preface this by reiterating from the original post, I am out of my league of understanding what I am actually doing and only getting by with base knowledge of c# and attempted logical thinking so there may be things about this that are really basic but that I don't really understand.

    Anyways, here's my result of trying to mash the two snippets together, my main problem is that it still only allows me to add voids that take one argument and not the ones that allow for multiple:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using UnityEngine.Events;
    4.  
    5. public class ZoneTrigger_T2 : MonoBehaviour
    6. {
    7.     [Serializable]
    8.     public class MyEvent : UnityEvent<MyEventArgs, MyEventArgs> { }
    9.  
    10.     public bool clickTrigger;
    11.     public bool enterTrigger;
    12.  
    13.     public MyEvent onClickEvent;
    14.     public MyEvent onEnterEvent;
    15.  
    16.     public MyEventArgs myarg0;
    17.     public MyEventArgs myarg1;
    18.  
    19.     public void OnMouseDown()
    20.     {
    21.         if (clickTrigger)
    22.         {
    23.             ClickEventTriggered(myarg0, myarg1);
    24.         }
    25.     }
    26.  
    27.     public void OnTriggerEnter(Collider other)
    28.     {
    29.         if (other.tag == "Player" && enterTrigger == true)
    30.         {
    31.             EnterEventTriggered(myarg0, myarg1);
    32.         }
    33.     }
    34.  
    35.     public void ClickEventTriggered(MyEventArgs arg0, MyEventArgs arg1)
    36.     {
    37.         onClickEvent.Invoke(arg0,arg1);
    38.     }
    39.  
    40.     public void EnterEventTriggered(MyEventArgs arg0, MyEventArgs arg1)
    41.     {
    42.         onEnterEvent.Invoke(arg0,arg1);
    43.     }
    44. }
    45.  
    46. public class MyEventArgs
    47. {
    48.     public string s;
    49.     public int i;
    50.     public float f;
    51.     public bool b;
    52. }
    And the code I'm trying to have the unity event run:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class SetPref : MonoBehaviour
    6. {
    7.     public void SetIntPref (string s, int i) //These ones does not currently work with the zonetrigger unity event
    8.     {
    9.         PlayerPrefs.SetInt(s, i);
    10.     }
    11.  
    12.     public void SetFloatPref(string s, float f)
    13.     {
    14.         PlayerPrefs.SetFloat(s, f);
    15.     }
    16.  
    17.     public void SetStringPref(string s, string s2)
    18.     {
    19.         PlayerPrefs.SetString(s, s2);
    20.     }
    21.  
    22.     public void myTest (string s) //This bit however does work.
    23.     {
    24.         Debug.Log(s);
    25.     }
    26. }
    27.  
    Thanks for the help so far!
     
  5. WarmedxMints

    WarmedxMints

    Joined:
    Feb 6, 2017
    Posts:
    1,035
    There is no need to have two MyEventArgs in the unity event.

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using UnityEngine.Events;
    4.  
    5. public class ZoneTrigger_T2 : MonoBehaviour
    6. {
    7.     [Serializable]
    8.     public class MyEvent : UnityEvent<MyEventArgs> { }
    9.  
    10.     public bool clickTrigger;
    11.     public bool enterTrigger;
    12.  
    13.     public MyEvent onClickEvent;
    14.     public MyEvent onEnterEvent;
    15.  
    16.     public MyEventArgs myarg0;
    17.  
    18.     public void OnMouseDown()
    19.     {
    20.         if (clickTrigger)
    21.         {
    22.             ClickEventTriggered(myarg0);
    23.         }
    24.     }
    25.  
    26.     public void OnTriggerEnter(Collider other)
    27.     {
    28.         if (other.tag == "Player" && enterTrigger == true)
    29.         {
    30.             EnterEventTriggered(myarg0);
    31.         }
    32.     }
    33.  
    34.     public void ClickEventTriggered(MyEventArgs arg0)
    35.     {
    36.         onClickEvent.Invoke(arg0);
    37.     }
    38.  
    39.     public void EnterEventTriggered(MyEventArgs arg0)
    40.     {
    41.         onEnterEvent.Invoke(arg0);
    42.     }
    43. }
    44.  
    45. public class MyEventArgs
    46. {
    47.     public string s;
    48.     public string s2;
    49.     public int i;
    50.     public float f;
    51.     public bool b;
    52. }
    You would send what you want to save in the event args and then just call a method to save it all;

    Code (CSharp):
    1.  
    2. public class SetPref : MonoBehaviour
    3. {
    4.  
    5.     public void SetPrefs(MyEventArgs eventArgs)
    6.     {
    7.         SetIntPref(eventArgs.s, eventArgs.i);
    8.         SetFloatPref(eventArgs.s, eventArgs.f);
    9.         SetStringPref(eventArgs.s, eventArgs.s2);
    10.         myTest(eventArgs.s);
    11.     }
    12.  
    13.     public void SetIntPref(string s, int i) //These ones does not currently work with the zonetrigger unity event
    14.     {
    15.         PlayerPrefs.SetInt(s, i);
    16.     }
    17.  
    18.     public void SetFloatPref(string s, float f)
    19.     {
    20.         PlayerPrefs.SetFloat(s, f);
    21.     }
    22.  
    23.     public void SetStringPref(string s, string s2)
    24.     {
    25.         PlayerPrefs.SetString(s, s2);
    26.     }
    27.  
    28.     public void myTest(string s) //This bit however does work.
    29.     {
    30.         Debug.Log(s);
    31.     }
    32. }
     
  6. Tidvis_Martin

    Tidvis_Martin

    Joined:
    Mar 12, 2019
    Posts:
    24
    @WarmedxMints Thanks for all the replies! I think I'm at the final hurdle now where everything seems to work, I can actually select the custom class in the event etc but I don't get two input fields, I get none. I tried with another "simpler" test with an event that just took two strings and the same result, I can select it but I don't have any option to give any input. Is there something I've still not caught on to? Is this an error on my part or a limitation of the unity event system? Or am I just simply trying to do something this system was never meant for?
     

    Attached Files:

  7. WarmedxMints

    WarmedxMints

    Joined:
    Feb 6, 2017
    Posts:
    1,035
    Add System.Serializable to the MyEventArgs class and you can set the value in the inspector of the zone trigger class;

    Code (CSharp):
    1. [System.Serializable]
    2. public class MyEventArgs
    3. {
    4.     public string s;
    5.     public string s2;
    6.     public int i;
    7.     public float f;
    8.     public bool b;
    9. }
    10.  
    or set the args before you send them in the event

    Code (CSharp):
    1.     public void OnMouseDown()
    2.     {
    3.         if (clickTrigger)
    4.         {
    5.             var args = new MyEventArgs
    6.             {
    7.                 s = "Hello",
    8.                 s2 = "Bye,",
    9.                 i = 2,
    10.                 f = 1.5f,
    11.                 b = true
    12.             };
    13.  
    14.             ClickEventTriggered(args);
    15.         }
    16.     }
     
  8. Tidvis_Martin

    Tidvis_Martin

    Joined:
    Mar 12, 2019
    Posts:
    24