Interacting with Unknown Game Object and Components

Hello!

I am trying to create a pop-up window showing the possible actions available upon right clicking on a game object.

I am wondering if there’s a faster/cleaner way to do it than the method I’m using right now. The method I’m using assumes we won’t know neither what object the user will be clicking nor the methods available from that object.

Here’s the scenario:

  1. The object to interact with, say a Tree, has two script components: a universal Interact script present on all interactable objects and the object’s unique Tree script, which have the methods Boop and Beep. On start, the Tree component passes a List(string) containing string “Examine” to the Interact script, which it stores.

  2. When the player right clicks on the tree, the player accesses the unknown game object’s Interact script, and asks for the List(string) containing the strings of the names of the methods available to the unique script.

  3. Then, using the strings from list given to the player from Interact, we can call method “Examine” using SendMessage and passing the string as a parameter.

    public class Interact : MonoBehaviour
    {
        public List<string> actions;
    
        //Give actions list to player
        public List<string> GetActions()
        {
            return actions;
        }
    
        //Pass method call from player to unique script
        public void Send(string msg)
        {
            this.SendMessage(msg);
        }
    }
    
    public class TreeComponent : MonoBehaviour 
    {
        public List<string> Actions;
        Interact interact;
    
    	void Start () 
        {
            //Add names of available methods to string list and send to Interact component
            Actions.Add("Examine");
            interact = GetComponent<Interact>();
    
            interact.actions = Actions;
    	}
    
        public void Examine()
        {
            Debug.Log("Examine!");
        }
    

The reason we can’t have the player access the Tree script directly is because we don’t know its a Tree so we can’t call GetComponent, which requires us to know the name of the component we want to access.

The main part I don’t like about this is having to use SendMessage, which I heard was slow and stuff.

Can anybody give me some pointers? The goal is to be able to show to the player the available methods of some unknown game object with an unknown script component attached.

Having the script be unknown is not the best way. What seems to be the easiest solution here is to either have an Interactable interface or abstract class. Which one you choose depends on how much code is shared between different interactables. Now have each interactable script inherit/implement the Interactable class/interface and vóìla the script is no longer unknown. Something along the lines of:

public interface Interactable{

    Dictionary<string,System.Action> GetActions();
}

public class TreeComponent : MonoBehaviour, Interactable
{
private Dictionary<string,System.Action> actions;
 
void Start ()
{
    actions = new Dictionary<string,System,Action>();
    actions.Add("Examine",Examine);
}
 
public void Examine()
{
    Debug.Log("Examine!");
}

public Dictionary<string,System.Action> GetActions(){
    return actions; //note the caller is able to modify this dict
}

Using the interactable is as easy as

Interactable obj = otherGO.GetComponent(typeof(Interactable)) as Interactable;
Dictionary<string,System.Action> dict = obj.GetActions();
//You can now e.g. loop over all keys in the dictionary. Calling the method is done by:
dict["Examine"]();

This approach suffers from not being able to send any parameters to the methods. There are ways around this limitation, if parameters are a necessity.