Best way to access a script component without knowing it's name?

I’ve only been programming for a couple months, and I’ve run into a problem that I suspect stems from my lack of experience with basic OOP concepts. Please bear with me and help me understand where I’m going wrong here :slight_smile:

I’m working on a stock market trading game. The core gameplay relies on a few different “Market Elements” that interact with one another: Stocks, Commodities, and Statistics. So for instance the “BirthRate” statistic needs to affect the “BabyFood Corporation” stock.

I’ve built each element as a separate script that gets attached to a generic game object. I then fill in the data for each object using the inspector (will probably switch this to XML at some point). So there is a “BirthRate” object, with a “Statistic” script attached to it. These objects each have a list of “Dependencies” that includes any other Market Elements that should be affected by that particular object.

The problem comes when I need to access an object’s Dependencies… Because the Dependency objects can have a Stat Component, a Stock Component, or a Commodity Component, I can’t ever be sure which Type to look for.

My solution up until this point was to create a separate “Market Element Interface” script that was added to each element. Each Stock/Stat/Commodity script sends the data I need to it’s Interface script, allowing me to grab it from there. This solution works when I need to access data from an element, but it still doesn’t allow me to CHANGE data.

How would you approach this design? I’m wondering if I should just put the Stock/Stat/Commodity scripts into one big “MarketElement” script? This seems messy, but it would allow me to access the script freely. Are there any other tricks involving generics or reflection that might work in a case like this? I haven’t delved into those topics yet and everything I’ve read didn’t seem to apply to this case.

If you made it this far… then thank you for reading. Hopefully someone can give me a clue as to where I should go from here. Thanks in advance!

From what I get you have either stock or Stat or Commodity but never the three of them on one object.

The most OOP style would be to use an abstract class (since interface cannot inherit they cannot be turned into component) like:

public abstract class  Dependency:MonoBehaviour{
   public abstract void GetTradeInfo();
   public void abstract void SetTradeInfo();
}

Now each of the dependency can inherit from Dependency and will have to implement the method the appropriate way.

As a result, it does not matter what is the type of your dependency since they are all of type Dependency and will for sure have the method implemented the proper way.

In the end, you call the same method name but the compiler will redirect to the appropriate one whether it is stock,stat or commodity.

So you can simply do:

GameObject obj;

Dependency dep = obj.GetComponent<Dependency>();
dep.SetInfo();

You shouldn’t put more in one script. :slight_smile: But, in many game designs, it’s OK to have a main Game Script for example that has access to everything (well, all major classes for example). You can then easily find the main script, and access the other scripts through this game class. Btw, the title of your question - why wouldn’t other game objects know it’s name? Sometimes it’s unavoidable that two classes know things about each other. It’s hard to make everything completely modular, and sometimes undesirable.

Another solution, which I only recommend infrequently, is to use delegates in a message passing system. You can notify other scripts when an event happens (baby boom data comes out)… each of the scripts listening for baby boom data can then update themselves instantly.

Similarly, there’s also the concept of listeners. When one class has new data available, any other class that is ‘listening’ to that class can update itself. For example, I implemented a listening system for keypresses. I have an inputhandler that takes certain keyboard input on certain game states. When a player say, fires a gun, i have a few classes that listen for this signal who are ‘registered’ to the inputhandler. rather than have all classes constantly listening to all input, they only get what they need. So fire gun can activate an animation class, deduct a bullet from an ammunition manager, etc.

A component should never directly “change” another component. A component represents a certain aspect of your whole project. It is responsible to fulfill this purpose. If it needs information from other components it should ask for this information and collect it.

A component might produce some kind of “event” and others might react to this event.

For this kind of communication in a component based system (loose coupling), Unity provides the SendMessage() function. However in your case interfaces would be the best way i guess.

You can use GetComponent with an interface, however the generic functions won’t work since they are constraint to the type “Component”. However the type-version works great:

public interface ISomeInterface
{
    int SomeValue{get;}
    void SomeAction();
}

public class SomeComponent : MonoBehaviour, ISomeInterface
{
   //...
}


ISomeInterface myRef = otherObject.GetComponent(typeof(ISomeInterface)) as ISomeInterface;
myRef.SomeAction();
var val = myRef.SomeValue;

You can also make your own generic “GetInterface” function like this:

public static T GetInterface<T>(this GameObject aObj) where T : class
{
    return aObj.GetComponent(typeof(T)) as T;
}
public static T GetInterface<T>(this Component aObj) where T : class
{
    return aObj.GetComponent(typeof(T)) as T;
}

which can be used exactly like GetComponent:

ISomeInterface myRef = otherObject.GetInterface<ISomeInterface>();
myRef.SomeAction();
var val = myRef.SomeValue;

You can make it modular and reusable by a Dependency manager component on each object. Then you can add three List members to it for lists of stats, stocks and Comodities. Then you can just tell any of those scripts to add themselves to the appropreate list in the dependency manager which is a component attached to the same game object.

When you want to contact the class just you can contact the DependencyManager and check the lists and have public methods for working with other classes as well to wrap them.

If this additional layer is not required just doing GetComponents to see if something is available or not is ok. The only advantage of the manager is that you can create a layer of abstraction as a general dependency on top of different kinds of it, if you don’t need it as a concept forget about it.