Any alternatives to using GetComponent or direct references?

Is there another way to make it so one class can make another class do something? Without using GetComponent or passing along direct references through code or using Find/FindWithTag?

Instead of having one big script do everything I am trying to create smaller ones that will be on most of the game objects, all behaving independently and I would like to make them as re-usable as possible.

For example, I am trying to create a menu for a game. I have the Menu object, which has children and it’s own script. One of the children is like an arrow pointer, a selector, whatever, it’s what shows the player what menu option they are on. It also has it’s own script. You can move this up and down and then hit spacebar to make a selection. So now that the user has made the selection, this arrow pointer now needs to make the script on the Menu object to do something, for that the Menu object has a function.

Now at this point I could do something like GetComponent of the Menu object script, which will now give me a direct reference to that object, and now I can just call the function on the Menu object. But I don’t want to do it this way because it will get very messy very quickly with many GetComponent calls, not to mention that now if I ever change something on the Menu I have to go back to this script and change it here. And I can’t really re-use this script in another game without making significant changes to it.

I’ve tried using events, but it doesn’t feel like this is what events are meant to be used for in C#. I also thought of, but haven’t tried, using the hierarchy tree for this, something like parent.DoSomething(), but that would probably be a similar problem as with GetComponent.

So could someone give me some suggestions please? I’m relatively new to programming and it seems like I’m very weak in OOP, and I want to have many small scripts that are independent of each other but are still able to communicate with each other when necessary. Is this even possible?
Any advice would be appreciated.

Why would you say this? Delgates/Events/Actions are designed to facilitate communication for all such needs.

Also even if you didnt use events I dont agree that you would constantly have to call GetComponent as you mention. Some sort of management structure would only need to set up and cache references once at the startup of the lifecycle of the code.

This is how I would set up a bunch of menu options, and a master Menu class to track all the menu options. You’ll notice that a MenuOption does not need to know anything about its containing Menu.

public class MenuOption : MonoBehaviour {
  public event System.Action<MenuOption> Selected;
  // However your option gets selected...
  bool selected {
    get { return m_selected; }
    set {
      m_selected = value;
      if (m_selected  Selected != null) { Selected(this); }
    }
  }
  bool m_selected;
}
public class Menu : MonoBehaviour {
  void Awake() {
    foreach (MenuOption o in GetComponentsInChildren<MenuOption>()) {
      o.Selected += HandleMenuOptionSelected;
    }
  }

  void HandleMenuOptionSelected(MenuOption theSelectedOption) {
    Debug.Log("Player has selected option " + theSelectedOption.name);
  }
}

P.S. You’re kinda sorta on your way towards Model-View-Presenter or Model-View-Controller design patterns. EDIT: I wouldn’t worry about MVP or MVC yet. Get used to OOP first. =) You can see how even something like a menu can get complicated pretty quickly!

That is basically how I had mine set up as well, except I was using multicast delegates with events, like the example here. I’ve not seen System.Action before and will have to read up on that.

The reason why it felt like the events weren’t really designed for this was because I wanted to re-use some of my events rather than create many similar ones in many classes, so I wrote a separate class to hold events, and call those events from other classes when needed, like so:

public static class EventManager
{
	public delegate void SomeNewType (some params);
	public static event SomeNewType eSomeEvent;

	public static void TriggerSomeEvent(some params)
	{
		if(eSomeEvent != null)
			eSomeEvent(params)
	}
}

public class SomeClass
{
	//doing something
	EventManager.TriggerSomeEvent(params);
}

public class ListenClass
{
    EventManager.eSomeEvent += HandleEvent;

    void HandleEvent(params)
    {
         //do something
    }
}

This is kind of like the way events are done in ActionScript3, almost, and so I tried to mimic that, but having to write a wrapper function to make this work felt like this really isn’t the way it was designed to work, that’s why I started looking for alternatives.

Object Oriented Theory incoming!

I actually have something very similar in my game, with really similar code too! I mainly use it though when I want to decouple classes. Ie: Two classes really don’t need to deal with each other. Just somewhere in my game there might be an interesting event that whoever might want to know about, then whoever can listen for that event without knowing anything about who actually triggered the event. This way I can reuse both parts without the parts depending on each other.

A menu with menu options is a little different I feel, just because they obviously work together. One is useless without the other. So I generally try to “black box” (encapsulation) the smaller pieces (options) that go into a larger container that controls them (menu). If you find yourself copying similar code over and over again, it might make sense to make a IMenuOption interface (subtyping) or a MenuOption base class that has the event (inheritance), then derived classes can reimplement the event if needed (polymorphism).

Really though, any way you code it doesn’t matter if it works! It’s only through a lot of experience and getting that object-oriented “feel” to know when it’s better to decouple classes, or how important black-boxing is, or as my CTO says “when a class has a bad code-smell”.

System.Action isn’t too complicated. It’s variable that holds references to delegates/functions, as long as the parameters match up. You can do the exact same thing with delegates.

P.S. I know nothing about ActionScript. >.>

Yes! That is exactly what I ended up doing. Yesterday I just completely re-wrote all of my code to handle the menu. Originally when I started I thought that I’d embrace OOP and Unity’s encouragement of “components” and wrote very small classes for almost all the objects that compose the menu and ended up with a lot of trouble trying to keep good communication and interaction between all the classes. But like you say, it actually doesn’t make sense to do it this way for something like a menu which is one whole. So this time around I re-wrote it much simpler, with much fewer classes and there’s less headaches to handle now and it took only a fraction of the time to do it this way compared to my original attempt.

I lack experience with programming and I guess the most important thing to learn about OOP for me would be when not to go overboard with it :slight_smile: