Best way to communicate between scripts
Hello everyone. I would like to know what is the best way to communicate between scripts without referencing them through the inspector. I've found some very helpful answers but I'm not sure which is best and why. For example, we have a main script where all our info is saved or loaded and some secondary scripts with info. Most secondary scripts will need to use values from our main script pretty commonly and i know for sure GetComponent<MainScript>
is not the best way to do it, especially if you are going to reference them a lot . I could also create a variable and then drag the game object that holds the main script to it but then i would need to do that for every single secondary script and some scripts may need to be destroyed in runtime or some game objects may change many times which i think is waste of time, which is why I'm interested in being able to make a whole class static and use it's values or perhaps use namespaces? Any help would be appreciated and sorry for the confusing, I'm really confused as well!
Answer by tormentoarmagedoom · Jan 05, 2018 at 01:28 AM
Hello @Ant0ny !
I dont know if you are asking how to find things in the game without using inspector, but this is what i do:
You can find objects via script, and then no need to attach them in the inspector. Imagine you have that MainScript as a component of a GameObject called GameController.
MainScript TheScript;
GameObject TheGameController;
void Start()
{
TheGameController=GameObject.Find("GameController");
TheScript = TheGameController.GetComponent<MainScript>();
}
So now, you can access the MainScript like
TheScript.LevelTime=25;
But the GameObject.Find(string name) is not the best way to do it, it consumes more then the other way, which is searching for tag. For example, we create the tag "controller" for our GameControler, and now we can use:
TheGameController = GameObject.FindGameObjectsWithTag("controller");
Once you have a object, you can easy access to their parents or childs, you can use
GameObject ChildObject;
ChildObject = TheGameController.transform.GetChild(0).gameobject;
it takes the first child (child with index 0) of the gameobject. You can do the same for the parents
ParentObject = TheGameController.transform.parent.gameobject;
or the grandparent
GrandParentObject = TheGameController.transform.parent.parent.gameobject;
Here some of the Unity pages:
Not exactly, apologies if i confused you. I'm more interested in how to have a main script and access it from other scripts, what is the best way to do it. As i said i know GetComponent is not the best way especially if you use it in Update.
Answer by TarwaterPV · Jan 05, 2018 at 01:07 AM
I would research these three things:
Class Inheritance: https://unity3d.com/learn/tutorials/topics/scripting/inheritance
Interfaces: https://unity3d.com/learn/tutorials/topics/scripting/interfaces
Events and Delegates: https://unity3d.com/learn/tutorials/topics/scripting/events
I think the Class Inheritance is closer in what I'm interested in but not entirely. For example, when we set a variable to static we can access it from any script without assigning it to the inspector. Is there a similar stable way you can achieve that?
Some people may disagree with this suggestion, but I recommend you look into using singletons. I mainly restrict their use for objects that need an overall class structure like a generic button class that all buttons use or a generic player class that all players use. Overall, it is really based upon how you need the overall architecture of the project to be designed and unfortunately there may be instances where you cannot avoid using GetComponent().
When I design things, what I usually do is a top-down approach and avoid using static variables except in the instance that I am using a singleton. Any data or commands are passed down to smaller objects from the main class. For example, assigning a player number to a individual weapon projectile, the player number would be sent from a player class to the individual instance of that projectile class. This ensures that you are able to maintain encapsulation for your game objects. There are many ways to "find" the class you want to pass data to, but generally I try to make scripts as generic as possible, so I rarely make GetComponent() calls and ins$$anonymous$$d just drag game object components in generic serialized fields. This also allows me to plug in more than one object based upon how the class is being used, giving me versatility.
Anyway, I may be going into too much detail, so again I advise you plan out how you are going to structure the overall architecture of your project. This will help you deter$$anonymous$$e the "best" way to have your scripts interact with each other.
PS: For information on Singletons, look here.
Answer by Exonto · Jan 05, 2018 at 07:57 PM
If what you are trying to do is limit your use of GetComponent<>() because of its supposed costliness, you can do lazy instantiation.
private Transform _transform;
private Transform Transform
{
get
{
if (_transform == null)
_transform = this.gameObject.GetComponent<Transform>();
return _transform;
}
}
As far as I am aware, GetComponent<>() is really the "best" way to communicate between scripts on the same object. The downside to this method is that it assumes scripts will never be removed from the game object, which is usually fine. In the rare case that scripts are removed, I just bite the bullet and use GetComponent.
I just want to be sure I'm not putting much weight on it when i use GetComponent ().$$anonymous$$yVoid (); from other scripts. If there are not any others ways i will stick to GetComponent.
Answer by TR33 · Jan 05, 2018 at 11:49 PM
As I understood you, you are searching for something you can access from every other script and use functions of in every other script. I don't know what it's called but it wasn't posted yet and I think it's pretty handy.
public class SaveManager : MonoBehaviour
{
public SaveState state;
public static SaveManager Instance { set; get; }//#this line
private void Awake()
{
//Reset();
DontDestroyOnLoad(gameObject);//#this line
Instance = this;//#and this line
Load();
}
NOTE: You need an empty GO in your scene to attach the script to. When you change the scene the GO will stay in your scene (DontDestroyOnLoad(...)) You can access funtions by making them public (obviously) for example:
//Set index as the last selected LC
public void SetLC(int index)
{
state.last_Selected_LC = index;
Save();
}
and call it somewhere with
//Debug.Log("Select");
SaveManager.Instance.SetLC(lcModelCounter);
buySelect.text = "Selected";
Your answer
Follow this Question
Related Questions
What are some best practices for static variables in multiplayer? 0 Answers
I cant access a script that I made in Assets/Scripts from the FirstPersonCharacter script. 1 Answer
Can't reference other namespaces from within TextMeshPro (TMPro) namespace. 0 Answers
Cannot access a array in another script 2 Answers
Static Classes 3 Answers