Ezreal
Ezreal

Reputation: 37

How to reference a monobehavior class in abstract class

I recently decided to make a command console for my game, and then proceeded to make some groundwork. My issue is I cannot use it to change any relevant variables, as I have gotten stuck trying to get references to the classes where said variables are stored.

I have an abstract class for my command:

public abstract class Command
{
    public abstract void Execute(string[] args);
}

Then I have a class deriving from above class for my command

public class RunesAdd : Command
{
    public override void Execute(string[] args)
    {

        int number;
        if(args.Length == 1 && int.TryParse(args[0], out number))
        {
            Debug.Log(number);
            RunCtr.runes += number;
        }
        else
        {
            ConCtr.addLogEntry("Incorrect syntax, correct syntax is: runes.add <runes>");
        }
    }
}

and finally my registry of commands

public class CommandRegistry
{
    private Dictionary<string, Command> _commands;

    public CommandRegistry()
    {
        _commands = new Dictionary<string, Command>();
    }
    
    public void RegisterCommand(string name, Command command)
    {
        if (_commands.ContainsKey(name))
        {
            Debug.Log("Created command already exists");
        }
        _commands[name] = command;
    }
    
    public void RegisterAllCommands()
    {
        RegisterCommand("testcommand", new TestCommand());
        RegisterCommand("runes.add", new RunesAdd());
    }

    public bool ExecuteCommand(string commandName, string[] args)
    {
        if (_commands.ContainsKey(commandName) == false)
            return false;
        _commands[commandName].Execute(args);
        return true;
    }
}

My problem is that I am unable to get a reference to my class with the variable for runes. I first tried to get a reference to the class in the Command class, so that those variables would be available in all children, but in order to do that I must make a method to actually assign those references, which would look like this:

public void GetReferences()
    {
        controllerObject = GameObject.FindGameObjectWithTag("Controller Object");
        RunCtr = controllerObject.GetComponent<Runes_Controller>();
        ConCtr = controllerObject.GetComponent<Console_Controller>();
    }

The issue here is that since I cannot get a reference the Command class (due to it being abstract) in any of my monobehavior scripts which have the void Start() method, I cannot actually execute this method to assign the references. I then tried to make another class called GetReferences, which looks like this:

public class GetReferences
{
    public GameObject controllerObject;
    public Runes_Controller RunCtr;
    public Console_Controller ConCtr;

    public void GetReferencesMethod()
    {
        controllerObject = GameObject.FindGameObjectWithTag("Controller Object");
        RunCtr = controllerObject.GetComponent<Runes_Controller>();
        ConCtr = controllerObject.GetComponent<Console_Controller>();
    }
}

Then I made the Command class derive from my GetReferences class, called the GetReferencesMethod() from a monobehavior script on start. Doing this I no longer get an error for not having assigned my classes to references, but whenever I try to edit the values it just does nothing. I have been searching the web for 2 hours now, but no dice. If I explained myself poorly please let me know. Any help is much appreciated, and thanks in advance!

Upvotes: 3

Views: 404

Answers (1)

CorrieJanse
CorrieJanse

Reputation: 2598

Ok from what I understand is that you are trying to get your Command class using the GetComponent<> method. I might be wrong on this, so correct me if I am wrong.

If it is, then the issue is GetComponent<> only works with MonoBehaviour derived classes. Meaning you have to implement your class as a MonoBehaviour, which should be as simple as this:

public abstract class Command : MonoBehaviour {...}

EDIT

After reading your comments I believe you can use of the a Singleton pattern.

If you place your RuneController & CommandController on the same object and add another class called GameManager or InGameManager. Then you can use a singleton pattern to access it.

public class GameManager 
{
    public GameManager Instance { get; private set; }
    public RuneController RuneController { get; private set; }
    public CommandController CommandController { get; private set; }
    
    void Awake ()
    {
        // If there is an instance, and it's not me, delete myself.
        if (Instance != null && Instance != this) 
        { 
            Destroy(this); 
        } 
        else 
        { 
            Instance = this; 
        }
    }
    
    void Start() 
    {
        this.RuneController = GetComponent<RuneController>();
        this.CommandController = GetComponent<CommandController>()
    }
}

So the usage will look as follow:

GameManager.Instance.RuneController.Execute(command);

Upvotes: 1

Related Questions