Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Best ways to share code between multiple C# files?

Discussion in 'Scripting' started by MrLucid72, Jan 26, 2016.

  1. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    902
    I'm a bit confused how to do this.. I heard there's multiple ways, but I'm doing something wrong. I miss VB where I can just "Friend" and done :) So yea, need practice..

    A has name, and B is trying to get the name. I am getting a null value on B when it pulls from A. What is the way to do this? How can I share things between them?

    Let's say I have 2 public classes: exampleA and exampleB, where I can dumb down what I have for example's sake:

    // I want to share code between the 2 classes:

    Code (CSharp):
    1. public class ExampleA : MonoBehaviour {
    2.     public static ExampleA myExampleA; // This should share between all classes..?
    3.     public string myName;
    4.     ExampleA exampleA; // This is all I need to do, or do I instantiate it as new? But if new, don't i lose name val?
    5. }
    6.     void Awake() {
    7.         myA = this; // this = this instance?
    8.         myName = "John Doe"; // Example B should receive this name
    9.     }
    10. }
    Code (CSharp):
    1. public class exampleB : MonoBehaviour {
    2.     public static ExampleB myExampleB; // Just in case I want to share something with "A" later
    3.     public string hisName;
    4.  
    5.     ExampleA exampleA;
    6.  
    7.     void Awake() {
    8.         myA = this;
    9.         exampleA = ExampleA.myExampleA; // To reference this specific instance, right?
    10.         hisName = exampleA.myName; // Says cannot be accessed with an instance ref: use type name.
    11.         [S]hisName = ExampleA.myName // Well, so much for type name. It's not there! [/S]
    12.         // Tried doing exampleA = new ExampleA(); but then the value just appeared null, since it's, well, new.
    13.     }
    14. }
    =======================

    Can someone give me a nice template for sharing a value with another file..? Thanks :)
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    "myA" doesn't exist anywhere. You just need to set "myExampleA" to this in ExampleA.Awake(). From there, in any other script file, you can access that instance like ExampleA.myExampleA.myName.

    Also, however, note that there is not necessarily a guarantee of execution order; exampleB's Awake might run before ExampleA's Awake. You can force execution order in the project settings, but it's a better practice to initialize these things in Awake, but wait until Start (which is always after Awake) before trying to access anything that any other script may have to initialize.

    The name for what you're doing here, by the way, is singleton, and it's a wonderful, but very easily abused tool. It should generally only be used when there is, conceptually, only a single instance of that script that will ever exist. A GUI, for example - there will probably only ever be one of those. Maybe the main player's object. The problem with singletons is that they're too easy to use, and it's easy to code yourself into a corner. If you know what corners to watch out for, they're awesome.

    If there will be more than one instance of a script and you need a particular copy of it, some use or variation of GetComponent<ExampleA>().myName will be more appropriate.
     
    MrLucid72 likes this.
  3. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    there are several ways to access the values and even build up a script structure. (also you have many spelling mistakes with lower and upper case :D )

    you have to look into script execution order, as you set the text in one script and read it in another and both on Awake() you can't say which Awake will be executed first.

    You need to know, if the Gameobjects the scripts are on are permanently in scene or will be instantiated later. So it depends on your usecase how you access it.

    To make it simple how it could look like, when you have two Cubes, and on each cube is One Script. ExampleA and ExampleB

    Code (CSharp):
    1. public class ExampleA : MonoBehaviour {
    2.     public string cubeName = "Cube A";
    3.  
    4.     public ExampleB cubeB;
    5.  
    6.     void Awake() {
    7.         if (cubeB != null) {
    8.             Debug.Log(cubeB.cubeName);
    9.         }
    10.     }
    11. }
    12.  
    13. public class ExampleB : MonoBehaviour {
    14.     public string cubeName = "Cube B";
    15.  
    16.     public ExampleA cubeA;
    17.  
    18.     void Awake() {
    19.         if (cubeA != null) {
    20.             Debug.Log(cubeA.cubeName);
    21.             // also possible -> cubeA.cubeB.cubeA.cubeB.cubeName;
    22.         }
    23.     }
    24. }
    make a empty scene, add two cubes, assign each script to one of the cubes. than drag cubaA into the script of cubeB there should be a field in inspector for it. and the same for cubeB draged into cubeA script

    that's just one way and not a very complicated one.

    Google:
    GetComponent
    GetComponentInChild
    Singelton

    http://docs.unity3d.com/410/Documentation/ScriptReference/index.Accessing_Other_Game_Objects.html
     
    MrLucid72, JoeStrout and StarManta like this.
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,848
    Just to be clear, how you access values (note: this has nothing to do with sharing code) from one script to another depends very much on whether they are intended to be two components of the same GameObject, or intended to be on two completely different GameObjects.

    @martinmr described how to handle the latter case, but he also pointed out the GetComponent method, which is how you would handle the very common former case. And then there are in-between situations, where the scripts may be on two different but closely related objects, like a sword being carried by the player or whatever.

    Finally, somebody should point out that in most cases you should NOT tightly couple your scripts like this. In other words, ExampleB shouldn't be poking around in ExampleA's parts, and vice versa. When your scripts are tightly coupled, it is nearly impossible to reuse code in a different context, causing you to write the same or very similar code many times. It also leads to projects that are brittle and very hard to change without breaking anything. Check out this short tutorial on UnityEvent for a good way to avoid coupling your scripts.
     
    cjdev and MrLucid72 like this.
  5. TroyDavis

    TroyDavis

    Joined:
    Mar 27, 2013
    Posts:
    78
    using your example you would fix a to this :

    Code (CSharp):
    1. public class ExampleA : MonoBehaviour {
    2.     public static ExampleA instance = null; // This should share between all classes..?
    3.     public string myName;
    4.  
    5.     void Awake() {
    6.         instance = this; // this = this instance?
    7.         myName = "John Doe"; // Example B should receive this name
    8.     }
    9. }
    To access this from any other code simply do the following in whatever script you create.

    Code (CSharp):
    1. public class ExampleB : MonoBehaviour {
    2.     public string hisName; // can be a private variable as well since we created an instance.
    3.  
    4.     void Awake() {    
    5.         hisName = ExampleA.instance.myName;
    6.     }
    7. }

    To give an example of how this code can be useful. Lets say you store your characters data in this file as a collection of variables. We will call this class PlayerData.

    Now we need him to take damage so he has a variable named CurrentHealth which is set to public and is say 100.

    In our damage script he takes 10 points damage, so we simply say PlayerData.instance.CurrenHealth -=10 which reduces the 100 by 10 leaving CurrentHealth at 90.
     
    Last edited: Jan 26, 2016
    MrLucid72 likes this.
  6. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    902
    oops bad typos on my part, but thx guys for the awesome examples!
     
  7. Cargoji

    Cargoji

    Joined:
    Jan 27, 2016
    Posts:
    1
    Working Good Coding.. your are genius Thanks for sharing.