Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Cannot Convert from 'System.Func<int>' to 'UnityEngine.Events.UnityAction'

Discussion in 'Scripting' started by Fecus, Dec 28, 2022.

  1. Fecus

    Fecus

    Joined:
    Mar 23, 2020
    Posts:
    5
    Hello,
    I'm not new to unity or C# but I've only recently started to try to try out more 'advanced' things like event systems and more complex design patterns after taking some courses on C++.
    Right now I'm working on a very simple clicker game, and for an item system, I'm trying to add a listener to a button for a function pointer. The idea being that I can define the functionality somewhere else, however just trying to pass in the function pointer 'myEffect' into clickerButton.onClick.Addlistener yields the error in the title. I tried to google it but I couldn't find anything similar to my problem. So my question is, is there a way to convert from a function pointer to a Unity Action, or am I going about this all wrong?

    Heres the code.
    Basically i have an abstract Item class that contains the Effect struct, EffectType Enum, and some properties. TestItem inherits Item, defines Effects for _effects, and then AddItem, a function in PointManager, is supposed to loop through _effects and add a listener for each Effect.
    Code (CSharp):
    1.  public class TestItem : Item
    2.     {
    3.         int _cost = 100;
    4.         int _count = 1;
    5.         List<Effect> _effects = new List<Effect>();
    6.  
    7.         public override int Cost => _cost;
    8.  
    9.         public override int Count { get => _count; set => _count = value; }
    10.  
    11.         public override List<Effect> Effects => _effects;
    12.    
    13.         public TestItem()
    14.         {
    15.             Effect e1 = new Effect();
    16.             e1.type = EffectType.click;
    17.             e1.myEffect = ()=> PointManager.singleton.points += 1 * _count;
    18.             _effects.Add(e1);
    19.         }
    Code (CSharp):
    1.  
    2.  public struct Effect
    3.     {
    4.        public  EffectType type;
    5.        public Func<int> myEffect;
    6.  
    7.     }
    8.  
    Code (CSharp):
    1.  
    2.         public void AddItem(Item item)
    3.         {
    4.             int itemIndex = items.IndexOf(item);
    5.             if (itemIndex > -1)
    6.             {
    7.                 ++items[itemIndex].Count;
    8.             }
    9.             else
    10.             {
    11.                 items.Add(item);
    12.                 foreach(Effect e in item.Effects)
    13.                 {
    14.                     if(e.type == EffectType.click)
    15.                     {
    16.                         clickerButton.onClick.AddListener(e.myEffect);
    17.                     }
    18.                 }
    19.                 itemIndex = items.Count - 1;
    20.             }
    21.  
    Any help is greatly appreciated!

    Edit: Was able to resolve this by changing they type of myEffect from Func<int> to UnityEngine.Events.UnityAction, which sounds obvious now that I've got it.
     
    Last edited: Dec 30, 2022
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    A UnityAction is a parameter-less delegate with no return type. Ergo, it supports methods with a signature of:
    void SomeMethod()
    .

    Func<int>
    is a delegate that supports methods that have a return type of the defined generic type. Ergo, methods with a signature of:
    int GetSomeInt()
    .

    Naturally delegates with different signatures aren't compatible with one another.
     
    halley and chemicalcrux like this.
  3. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    717
    What should that int parameter be?

    If you don't care at all, you could do a little something like this:

    Code (CSharp):
    1. clickerButton.onClick.AddListener(() => e.myEffect(0));
    ...but I suspect that you want a meaningful value!
     
  4. Fecus

    Fecus

    Joined:
    Mar 23, 2020
    Posts:
    5
    Oh Ok, thank you, That makes sense. What do you suggest I do instead? a Function pointer/func<> must have a non-void return type. I'm assuming some kind of delegate would be better but I haven't been able to wrap my head around them so far.
     
  5. Fecus

    Fecus

    Joined:
    Mar 23, 2020
    Posts:
    5
    That is actually its return type, not a parameter.
     
    halley likes this.
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    Well buttons just to fire off events to say something has happened. It doesn't make sense for them to send values nor to expect a return type. Really, all you should be passing through to a button's
    onClick.AddListener
    call is a parameter-less method, rather than another delegate.

    It kind of looks like
    myEffect
    (which should be capitalised as MyEffect) should just be an System.Action as I don't see you using the return of the
    Func<int>
    delegate.

    Hard to say with the full context though. Hopefully you can use this information to find yourself the solution.
     
  7. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    717
    Func<T>
    demands a return type, but
    Action
    doesn't!

    Code (CSharp):
    1. Action foo = () => print("Hello");
    2. Action<int> bar = x => print(1 + x);
    3. Func<int> baz = () => 1;
    4. Func<int,int> buz = x => 1 + x;
    In general, Func<T1,T2,T3> is a function that takes T1 and T2 and produces T3, and Action<T1,T2,T3> is a function that takes T1, T2, and T3, with no return type.
     
  8. Fecus

    Fecus

    Joined:
    Mar 23, 2020
    Posts:
    5
    oh theres literally a thing called Action. Ok, ill see if i can just use that later tonight

    Edit: oh so different problem, here a unity event cannot have a return type or any parameters. That said, that gave me the bright idea to just make myEffect into a UnityAction, which worked. Thanks for the help guys.
     
    Last edited: Dec 30, 2022
  9. Fecus

    Fecus

    Joined:
    Mar 23, 2020
    Posts:
    5
    I actually dont need the return type, Its just there cause Func<> needs one. So if theres some other data type i could use that would be great.