Random function selection

Hello,
I’m thinking about using random choices in Unity. I wanted to know if there is a chance to randomly choose a function and how it can be done. Example:

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

public class RandomScript: MonoBehaviour
{
void Update()
{
// random selection code
while(true) // example (like in C++)
{
//The code, which is to be executed indefinitely, is designed to randomly select functions (in the example //there are 2, and what if there were 10). An example can be colors that will be chosen randomly (functions in //which there is code for individual types of colors)
}
}

void FirstFun()
{
 // code
}

void SecondFun()
{
 // code
}

Sure! This is easy, even if the syntax looks bizarre, but it makes perfect sense because here is what’s going on:

What you are going to do is assign the address of the function (i.e., “where can I find FirstFunc?”) to a variable, and in this case we will put them in an array of such things so you can choose randomly.

A function pointer variable in this case is called a System.Action

You can make ONE of them this way:

System.Action whatFunc = FirstFun;

NOTE: FirstFun does not have parentheses after it in this case; you’re just asking “where is it?” you are not calling it yet.

To use the above variable (which can point at any void function), you would use:

whatFunc();

Now, you can make an array of them, as many as you like:

System.Action[] allFuncs = new System.Action[] {
    FirstFun,
    SecondFun,
    ThirdFun,
    MoreLikelyFun,
    MoreLikelyFun,
};

See how I added one function twice above? That lets me call that function twice as often on average.

Finally, to use it:

// choose one
int whichFunc = Random.Range( 0, allFuncs.Length);

// look up the one we want in the array and call it!
allFuncs[whichFunc]();

You could also pull it out into another temp variable, THEN call it:

System.Action whatToCall = allFuncs[whichFunc];

// call it
whatToCall();

If you expect it to be null, check it before you call it.

Here’s more reading on System.Action and System.Func (when you want to return values from it):

3 Likes

Thank you. I will try it :slight_smile:

1 Like

What if this function has a parameter? In addition, the parameter will be GameObject [ ].

Action[] Functions = new Action[]
    {
        StaticaFunctionsScript.ButtonObjectS(StaticsFunctionsScript.Button[0]),
    };

Error comment: “Cannot apply indexing with [ ] to an expression of type ‘GameObject’.”
What Can i do in this situation.
I created script with static class. In another script i used System.Action.

The problem is (apparently) that the your StaticsFunctionScript.Button is a GameObject, not an array of GameObjects, so you can’t dereference that with [0]…

You are conflating creating a list of Actions and you are invoking a function, which is unlikely to be what you want.

if you want to make Actions that take GameObjects, it’s this syntax:

System.Action<GameObject>[] actions = new System.Action<GameObject>[] {

// list functions that take gameobjects <HERE>

}

If you have a function like this:

void MyGameObjectTakingFunction( GameObject foo)
{
  // code
}

In the first snippet, you would put just MyGameObjectTakingFunction, below the comment that has in it, no parentheses, no arguments.

to invoke the first one it would be:

actions[0]( theGameObjectToPassIn);

Thank you. I did’t use System.Action before. I will do it as you say.:slight_smile:

I have tried the syntax you suggested me many times, but nothing worked. I do not fully understand how it works.
Here is the code (1):

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

public static class StaticFunctionsScript
{
    [SerializeField] public static GameObject yellowButton;
    [SerializeField] public static GameObject [] blueButton;

    public static Vector3 blueButtonPosition;
    public static Vector3 blackButtonPosition;

    public static void Start()
    {
        blueButtonPosition = yellowButton.transform.position;
    }

    public static void ButtonObjectPosition(GameObject bbutton) blackButton[]
    {
        // code
    }

}

(2):

using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.UI;

public class ActionScript : MonoBehaviour
{
    Action<GameObject>[] Functions = new Action<GameObject>[]
    {
            StaticFunctionsScript.ButtonObjectPosition(StaticFunctionsScript.blackButton[0]),
    };

}

This is error: “Cannot implicitly convert type ‘void’ to 'System.Action<UnityEngine.GameObject>”

Are you absolutely sure you need a list of functions??

I only ask because it looks like you’re using the same function (ButtonObjectPosition()) multiple times based on separate GameObjects in that array. For that you just call that function explicitly with different GameObjects!

In any case, if you want ButtonObjectPosition to accept a GameObject, it’s just like any other function, it looks like this:

public static void ButtonObjectPosition(GameObject bbutton)
{
  // etc
}

To say you want to put that into a list of actions that take a single GameObject, make that list like this:

System.Action<GameObject>[] actions = new System.Action<GameObject>[]
{
  StaticFunctionsScript.ButtonObjectPosition,   // this will be actions[0]
  // add other functions here that ALSO take a GameObject, if you want
}

When you invoke it,

int whichActionIWant = 0;   // you only created one action above, so zero is your only option now

actions[whichActionIWant]( TheGameObjectArgumentIWantToPassToIt);

Breaking that last line down:

actions[whichActionIWant] ← says I want a reference to this function

( TheGameObjectArgumentIWantToPassToIt) ← invokes the function you want with that GameObject argument passed in

I appealed and it worked, thanks. However, in the next stage:

actions[whichActionIWant]( TheGameObjectArgumentIWantToPassToIt);

Ie doesn’t see the name “actions” as if it wasn’t there at all. (Of course I used my names).

The actions[ ] array is great if you’re going to have a ton of different functions, but if you just have a few, why not a simple if/then or switch statement? Whatever number chosen from Random.Range() determines which function to call.

@seejayjames ,
Thanks for the suggestions. However, I do not know what it would look like.
The function swaps the places of objects (objects change places) so that they are a hindrance for the player when shooting and wants the place to be random. I decided that this might be a better solution.

On the original question, I’d probably create a list of delegates. Whatever random functions you want to choose from, make them a delegate and add them to the list. Then just pick a random number between 0 and list.count -1, and call the delegate at that index.

i used Random.Range(0, object.Length);