Enum as a function param in a button OnClick
Hi,
I have several buttons calling a function which parameter is an enum.
I can't display the enum parameter in the OnClick() field, because my function appears missing.
Trying to serialize the enum doesn't work.
Here is what I'm trying to obtain :
And here is my code :
[System.Serializable]
public enum Things { Thingie, Stuff, Whatever }
public void MyFunction(Things someThing)
{
Debug.Log("Passed the parameter : " + someThing);
}
Thanx in advance !
Hi,
See this (see comments too): https://feedback.unity3d.com/suggestions/allow-enums-with-onclick-buttons
...one way to go around this:
Assign a method that does not take parameters (or takes some parameter) and then calls some other method with enum, so assign to your OnClick your $$anonymous$$ethods like $$anonymous$$yFunctionThingie or $$anonymous$$yFunctionStuff and so on... use your methods as sort of in-between methods.
Thanx for your quick answer !
Alternately, as enums work like arrays in some way (each element is indexed with an integer), I assume there should be a way to pass an int param and turn this into the corresponding enum.
Something like this (but I can't find the correct syntax):
public void $$anonymous$$yFunction(int anInt)
{
Things someThing = Things[anInt]; // not the right syntax
Debug.Log("The parameter is now: " + someThing);
}
@$$anonymous$$oyemsi
I'm not sure about the best method, at least you can cast int to enum, as it doesn't have manual numbering defined, the numbers from 0 and upwards will match. (Thingie = 0, Stuff = 1...)
public void $$anonymous$$yFunction(int someThing)
{
var value = (Things)someThing;
Debug.Log("Passed the parameter : " + value);
}
BTW - this enum thing has been discussed in UI area of the forum. There's pretty long thread IIRC.
Answer by Any3Develop · Jan 10, 2020 at 07:15 AM
Use upcast. @Koyemsi
public enum YourEnum { first = 0, second = 1, etc }
public void ButtonActionOnClick (int someValue)
{
switch( (YourEnum)someValue ) // use upcast, where 0 - first, 1 - second...
{
case(YourEnum.first):
break;
}
}
Yes, that's what I finally did. Thansl for your answer @Any3Develop
Note that what you did is an explicit downcast. At the "top" is the base class. Below are derived classes. Upcasting is always possible implicitly and can never fail. Downcasting has to be explicit and can fail. Though in the case of int and an enum type it's more a conversion than an actual cast since value types do not support polymorphism at all.
This is a bad practice. Enums can change values, and unless you specify values for each of your enums(which is actually suggested) things will break without you realizing. Also you are forcing anyone/yourself when you forget each value to have to look them up again.
Bad solution. The answer by MrLucid72 should have been the accepted one. Using ints is a horrible practice and it will backfire for sure.
Answer by MrLucid72 · Aug 01, 2020 at 09:12 AM
The modern way is to set a class with a public enum. Pass along the class! This way also supports multiple parameters.
EDIT: I think enum may require [Serializable] attribute - forgot!
@$$anonymous$$rLucid72 Interesting. This is something I've never done before but seems a good solution and powerful as well since as you said, it could support multiple parameters.
@Bunny83 Curious what you think of this solution.
Just as and Example: For anybody that wondered how this converts to a switch statement, in my project I just created this as my component:
using UnityEngine;
public class PanelsComponent : $$anonymous$$onoBehaviour
{
public Panels Panels;
}
and this is the method OnClick() will trigger:
public void SelectPanel(PanelsComponent panel)
{
foreach (PanelGameObjects p in panelGameObjects)
{
p.Panel.SetActive(false);
}
switch (panel.Panels)
{
case Panels.$$anonymous$$apSettings:
panelGameObjects.Find(x => x.PanelType == Panels.$$anonymous$$apSettings).Panel.SetActive(true);
break;
case Panels.EmitterSettings:
panelGameObjects.Find(x => x.PanelType == Panels.EmitterSettings).Panel.SetActive(true);
break;
}
}
You can also use ScriptableObjects instead of $$anonymous$$onoBehaviors so you don’t have to add a component to any GameObject and it’s reusable.
Thanks, this is a cool solution to another episode of Unity's "How do I fuckup the most basic flows" specialty.
Answer by nathanlink169 · Sep 04, 2018 at 07:30 PM
Hey, enum values aren't supported in the On Click delegate. To my knowledge, only integers and booleans are.
One wonders how ScriptableObjects are supported, but not enums ?!
Because the ArgumentCache only has those concrete types:
Object m_ObjectArgument;
string m_ObjectArgumentAssemblyTypeName;
int m_IntArgument;
float m_FloatArgument;
string m_StringArgument;
bool m_BoolArgument;
Answer by Laaste · Aug 11, 2020 at 07:28 PM
Simplest way i figuredout is make method take string and try parse it
public enum YourEnum { yourOption1, yourOption2 }
public class YourClass : MonoBehaviour { private YourEnum enumState;
public void SetEnum(string newState)
{
enumState = (YourEnum)Enum.Parse(typeof(YourEnum), newState);
}
}
Answer by Hex0dus · Jun 22, 2020 at 07:00 AM
I think that this question is worth to be answered because enums can be very useful in some cases. Certainly it's better then to just use a string as param and then make a typo that causes problems. This is the way I do it:
using UnityEngine;
public class MenuInvoker : MonoBehaviour
{
private enum State { Main, Settings };
[SerializeReference] private State state;
public void InvokeMenu(MenuInvoker currState)
{
switch (currState.state)
{
case State.Main:
Debug.Log("Main");
break;
case State.Settings:
Debug.Log("Settings");
break;
default:
Debug.Log("Default Menu");
break;
}
}
}
How would you use that? Add a script, then reference the script?