Search code examples
c#unity-game-engineevents

How to optimize communication between multiple gameObjects?


How should I set up the communication in betweed group of objects and a manager?

Here is the structure I have:

  • I have a gameObject that is called "ResourceManager" it has the script which contains multiple variables (integers)
  • I have other gameObjcets, let's call them "npcs" (they have NPC tag on them) they are instantiated out of prefab and are not existing until scene runs.

So basically everytime NPC triggered when entering a collider, it should add +2 to a varibale in ResourceManager, currently it happens in this way:

private resourceManager resourceManager;
void Start() {
 resourceManager = FindObjectOfType<resourceManager >();
}

- on trigger function here - 
resourceManager.resourceAmount +=2;

I do believe it currently works fine, but will it be a problem if, let's imagine, there will 100 NPCs that are doing this script? If so, would it better to replace this system with Action, Delegate or Event system? If so, should be a resourceManager who listens to event that is happening and would it be a problem if 100 NPC will handle same script and invoke events?

And another question is if I want to say to all NPC objects when 100 of resource amount is reached that amount is reached and to let them execute a script. Currently I think that the method is to search through each gameobject by specific tag, but I think it's extremely hard to execute in terms of CPU, how it should be done correctly?

Thanks for all advices in advance!


Solution

  • The solutions you suggested do sound like perfectly fine ways of communicating. Using a singleton "EventManager" tasked with relaying these sorts of events between any scripts that care to listen for them/invoke them is a design pattern that has served me well in the past. Also, nothing you are describing sound particularly expensive to me, so I probably wouldn't worry that yet, you probably need more testing to see.

    However, since you asked, my suggestion would be that this would be a perfect place to consider using a ScriptableObject for the ResourceManager. ScriptableObjects are kind of like prefabs for code instead of GameObjects, and they work really well as centralized data containers. (Depending on who you ask they can also be really good for storing more advanced common functionality and code as well, but that seems a little controversial).

    They exist as assets, which means they are stored as part of the project, not any particular scene, so as a bonus you can use them to have data persist easily between scenes if needed.

    The only concern with making ResourceManager a scriptable object is that you need to be aware that since it exists as an asset seperate from the scene, any changes made to it during runtime will persist once execution ends.

    There are common ways to get around this though, such as:

    1. Instantiating copies of the asset during runtime as needed, and only using the copies during execution, which will get destroyed upon exiting playmode.

    For example it is common to have scriptable objects which hold initial values for players or npcs and having each player instantiate their own version of the asset upon creation so they can modify their own values to their heart's content without worrying about modying other character's values.

    or

    2. (Possibly more relevant to your needs) Including functionality within the scriptable object to reset itself to an initial state.

    The simplest way to do this is just to have serialized private fields for setting the initial values in the inspector that nothing else can modify, and setting the (hiden in inspector) public values to those initial values in "OnEnable" or "Awake". But you can also have reset functions be called as you exit playmode if it's really important to you for whatever reason.

    Whichever technique you use, you just need to ensure the path to the asset is stored somewhere where all your npcs and gameobject can find it. If you opt for the second option, it could be as simple as putting the asset in a resources folder and doing:

    resourceManager = Resources.Load("ResourceManager");

    It is also really easy to listen for events called by a ScriptableObject as long as you have a reference to it, so it could work well for that as well.

    Hope this helps!