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

Tons of scripts reference player's gameObject and script componenets

Discussion in 'Scripting' started by mrd777, May 10, 2017.

  1. mrd777

    mrd777

    Joined:
    May 4, 2017
    Posts:
    54
    Hi guys,

    So I'm finding that I keep writing the same code. I have to find the game object "player" and then get it's component that I want to use. Normally a "Stats" script component where I can change things like the player health, xp, speeds, etc...

    Is there a better way to always reference my player and his stats, so I don't keep writing the same reference lines?

    EDIT: I understand that using Find object or Get Object are bad methods to use, but I still have to constantly drag and drop from inspector on each script. Seems redundant.

    SIDE NOTE: Also, the concept of having a reference set outside of the code using drag and drop seems super strange to me, as I can't read my code and understand what the reference ends up being, without switching to the inspector and reading it. This "set the reference" outside of the code concept, just seems like such a bad practice to me. But I'm not expert coder, so please if someone can touch on this, I'd appreciate it!

    Thanks!
    Dave
     
    Last edited: May 10, 2017
  2. kiriri

    kiriri

    Joined:
    Jan 14, 2011
    Posts:
    107
    It depends on your project really. A very common practice around here (but abhorred by everyone else) are singletons. They work something like this :

    Code (CSharp):
    1. public static T t;
    2. void Awake(){
    3.     t = this;
    4. }
    where T is the type of your class (Eg Player or Stats). Now you can access your player object staticly via Player.t .

    PS : You can change script execution order in your project settings to make sure Player always runs first, to make sure t is always assigned.
    It's common practice to name the singleton after the Type . Eg Player.player
     
  3. mrd777

    mrd777

    Joined:
    May 4, 2017
    Posts:
    54
    I saw something like this and I think I tried it, but maybe i did it wrong. I will try it again.

    I also edited my OP with another few points, if you have time and can help, let me know. Thanks!
     
  4. kiriri

    kiriri

    Joined:
    Jan 14, 2011
    Posts:
    107
    Assigning field values from the inspector is an integral part of what Unity is. These types of assignments are meant for referencing resources such as textures or sound files that you would otherwise have to explicitly load via path.
    The other use for them is the construction of prefabs. Linking up different components that will always work as 1 module may look weird at first, but once you handle them as 1 prefab under a common parent object you won't have to deal with broken links ever again, no matter how you reshuffle the hierarchy.
    I personally do not use these types of references globally though. It is very easy to lose track of which component depends on which that way. And that just leads to bad practices.

    My own approach is to always have 1 Main class that manages all other classes in a one way(cascading) manner, but that's not necessarily what Unity was built for.

    PS : Good code should always have safety checks everywhere, so ideally you shouldn't care what is plugged into your inspector fields, anything should be handled or throw an error if it can't be.

    EDIT : About that singleton, the most important thing to check is that it needs to be set BEFORE anything else accesses it. Otherwise you get a null reference exception.
    It also does not require any setup in the inspector. The awake function is called immediately after the game starts/the gameObject is enabled, and this should set the global variable, which everyone can access via Type.fieldName
     
  5. mrd777

    mrd777

    Joined:
    May 4, 2017
    Posts:
    54
    So you're saying, we can set up an object and use the static idea to make it a kind of global scope variable, or global scope object that wont need to always be found.

    I remember coding in VB.NET and setting up modules, which were acting as global objects that i could reference from anywhere. It was indeed very helpful when I did that. Normally for things that I'd always be using, and that would only be one instance of in the game anyway. Eg, playerStats.


    Your answer also just reminded me of something else. Can I write a script, and leave it in my project folder and also instances that class, within the same script? Or does it have to be tied to a gameObject, if there is any sort of instancing going on?
     
  6. kiriri

    kiriri

    Joined:
    Jan 14, 2011
    Posts:
    107
    Unfortunately in Unity you don't have access to a Main class where your game starts in (The way all other programs work). So you will always need at least 1 gameObject to instantiate all other scripts. However, classes do not need to inherit from MonoBehaviour, the class that is attached as Components to GameObjects. You can just as well create a class that inherits from System.Object, which would not need a GameObject to work. However, you would lose all those nice "event" functions like Start,Update etc. You can pass them on from other classes though.
    VB.NET hides a lot of what's happening from the user. Unity is a tiny bit more hands-on. You always have to instantiate an Object, and the "Project" panel is merely for "raw uninitialized" data. So no, you can not write a script that instantiates automatically without any outside call. Even those Start/Update functions in MonoBehaviours are always called from some other internal class that these classes subscribed to when they were created.

    Unity does make Singleton patterns very easy though. You have the Awake() function which gets called before anything else, then the Start() or OnEnable(). So you can assign your singleton in Awake() and do all other initialization in Start() and access the other classes statically via the singleton.
     
    mrd777 likes this.
  7. mrd777

    mrd777

    Joined:
    May 4, 2017
    Posts:
    54
    So if I create a singleton, and instance it on the Awake, what if there are other awake methods in other scripts that try to reference the singleton? Race condition happens? Or do you generally want just to reference your singleton in Start or Update methods only because of the initial wait?
     
  8. kiriri

    kiriri

    Joined:
    Jan 14, 2011
    Posts:
    107
    Consider it a bad habit to write anything but independent code in your Awake and you should be fine :D Race conditions are real.
    If you somehow stumble upon a problem that you just can't solve with just Awake and Start, then there's Edit->ProjectSettings->ScriptExecutionOrder . Put in the conflicting MonoBehaviours and Unity will make sure they will run in exactly that order. That's project dependant though and a pain to transfer between projects, so try to avoid if possible.
     
    mrd777 likes this.
  9. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    In my experience, if your scripts interact this heavily, you should probably be using a manager class which calls your initialization code in the correct order. (I've never used the script execution order manager, and don't plan to, either.)
     
    mrd777 likes this.
  10. mrd777

    mrd777

    Joined:
    May 4, 2017
    Posts:
    54
    Thank you guys, this is awesome help :)
     
  11. mrd777

    mrd777

    Joined:
    May 4, 2017
    Posts:
    54
    Hey dude, your website is great. Thank you for the beginner articles!!
     
    StarManta likes this.