How to implement a general undefined function which can act as any given defined function.

Hello, I was hoping someone could help me with a problem I am having.

Lets say I have three C# scripts, ScriptA, ScriptB and ScriptX, all of which inherit from MonoBehaviour.

Say ScriptA is attached to GameObjectA and has a public function FunctionA(), which returns a boolean.

And ScriptB is attached to GameObjectB and has a public function FunctionB(), which also returns a boolean.

Now here is where it gets a little strange.

I want ScriptX to have a type of “unspecified” function called Evaluate() which returns a boolean and has the following ability:

Say I have two empty game objects, GameObjectX1 and GameObjectX2, and I attach ScriptX to both.

When I call Evaluate() from GameObjectX1 I get the result of FunctionA(),

But when I call Evalaute() from GameObjectX2 I get the result of FunctionB().

It is as if I wish ScriptX had a field in the inspector which I could assign FunctionA() or FunctionB() or really any function which returns a boolean, then when I call Evaluate() from ScriptX it acts as that assigned function.

Is this something that can be solved with delegates?

Any help would really be appreciated.

You might want to add the reason why you don’t use an interface or the like? Let’s call it IEvaluable, it really doesn’t matter though.

Two components could then implement said interface and in both, you’ll be able to specify what happens when the method of the concrete implementation is called. They don’t have to have anything else in common, all that matters is that both can be of type ‘IEvaluable’.

In order to achieve that, you can just call GetComponent() on either object and if the return value is not null, you can call Evaluate on it.

There are also other ways to achieve similar behaviour, but this should be sufficient from what you’ve written, unless I didn’t understand it completely.

2 Likes

An Interface makes most sense, but if you want to specify any type of behavior in ScriptX, delegates might work for you too.

You could do this with an enum and a switch statement

public class ScriptX : MonoBehavior
{
    public enum Function { FunctionA, FunctionB };
    public Function myFunction = Function.FunctionA;  // This should show in the inspector
    public bool Evaluate()
    {
        switch(myFunction)
        {
        case Function.FunctionA:
            return MyFunctionA();
        case Function.FunctionB:
            return MyFunctionB();
        }
    }
    private bool MyFunctionA() { return true; }
    private bool MyFunctionB() { return false; }
}

Thank you so much for your replies.

I have tried your suggestion Suddoha and it works wonderfully.
I am not too familiar with Interfaces which is why I did not try that.
Here is what I did just to make sure I am getting what you are saying.

I made the interface:

public interface IEvaluable
{
    bool Evaluate();
}

Here are ScriptA and ScriptB (attached to GameObjectA and GameObjectB respectively)

public class ScriptA : MonoBehaviour, IEvaluable
{
    public bool FunctionA() { /*...code...*/ }

    public bool Evaluate() { return FunctionA(); }
}
public class ScriptB : MonoBehaviour, IEvaluable
{
    public bool FunctionB() { /*...code...*/ }

    public bool Evaluate() { return FunctionB(); }
}

And here is ScriptX (this one does not implement IEvaluable)

public class ScriptX : MonoBehaviour
{
    public GameObject Obj;

    public bool Evaluate() { Obj.GetComponent<IEvaluable>().Evaluate() }
}

Now when I drag ScriptX onto a game object, it exposes the field Obj in the inspector.

If I drag GameObjectA on to the field, then Evaluate() in ScriptX gives FunctionA().

If I drag GameObjectB on to the field, then Evaluate() in ScriptX gives FunctionB().

Awesome, thank you again Suddoha.

Now I have question which builds on this. I will ask this question in the next post.

Here is my next question which builds on the above.

What is ScriptA has two functions in it, say FunctionA1() and FunctionA2().

I guess I could modify the interface to:

public interface IEvaluable
{
    bool Evaluate1();
    bool Evaluate2();
}

then ScriptA would look like:

public class ScriptA : MonoBehaviour, IEvaluable
{
    public bool FunctionA1() { /*...code...*/ }

    public bool FunctionA2() { /*...code...*/ }

    public bool Evaluate1() { return FunctionA1(); }

    public bool Evaluate2() { return FunctionA2(); }
}

Now this would work, but the problem I have is that ScriptA could have any number of
functions which I want to target in this way.

Can we generalize this technique so that if ScriptA has “n” functions I can some how
target any given one in ScriptX?

You can always pass in a parameter indicating which method to use.

Or for ultimate flexibility you can get into reflection. Warning, reflection is an advanced topic.

Could you add a concrete example?

At some point you have to determine which method you want to call, like @Kiwasi and others have said, you can always pass parameters but if that’s only a parameter to determine the method to call, you could also declare more methods and call them directly.

I like the idea of including say a string parameter in ScriptX which would allow me to call the function I am targeting

Thank you for all the suggestions and help!!

You’re looking for a serializeable event system. UnityEvent is a possibility, but it doesn’t support methods with return values.

This one looks good, but costs $20. I couldn’t find any free ones from a quick google.