Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved Reference to Monobehaviour script from static class.

Discussion in 'Scripting' started by MartinMa_, May 30, 2021.

  1. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    Hello can someone help me how to do this?


    I want initialize monobehaviour class from static class but i am getting warning.

    "You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all"

    If this will be in non static class i will go with
    Code (CSharp):
    1. MyScript script = FindObjectOfType<MyScript>();
    Currently i am using this but getting this warning
    Code (CSharp):
    1. MyScript script = new MyScript();
    But how can i do this from static class and dont get this warrning?

    Thanks for help.My code is working but i dont like this warning.
     
  2. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,363
    You can use the same construct as in a singleton. Fetch the object only if needed and store the reference in a static variable.
    Code (CSharp):
    1. public static class MyScript
    2. {
    3.     static MyScript instance;
    4.     public static MyScript Instance
    5.     {
    6.         get
    7.         {
    8.             if(instance == null)
    9.             {
    10.                 // create or find object
    11.                 instance = GameObject.FindObjectOfType<MyScript>();
    12.              }
    13.              return instance;
    14.         }
    15.     }
    16. }
    Update: fixed coding error.
     
    Last edited: May 30, 2021
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,931
    It has nothing to do with doing this from a static class.

    MonoBehaviours are designed to be attached to GameObjects at all times. Unity will not allow them to exist unless they are attached to a GameObject.

    The only valid ways to create an instance of a MonoBehaviour are:
    • AddComponent to create a new one and attach it to a GameObject
    • Instantiate to create a copy of an existing component and its GameObject together.
     
  4. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    I stilldont get how can i achieve what i want, i cant make static class monobehaviour and alsoi cant initialize fromstatic class
     
  5. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    What this will do?itwill enable me to initialize monobehaviour script from static class?I am not at home atm
     
  6. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,363
    It will allow you to execute the first line of code you posted from a static class. As @PraetorBlue said, you can not create it with "new". So you have two options.

    A) Find the existing object (Find.. et all) and reference it in your static class. Which is the solution I posted.
    B) Another option would be to create a new empty GameObject (new GameObject) and then use AddComponent<MyScript>() to create your script on it. Though usually people use Prefabs to do this. This is what PraetorBlue was talking about.
     
  7. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    I tried it but if i create public static class MyScript : MonoBehaviour
    it says this
     

    Attached Files:

  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,006
    This really sounds like classic XY Problem:

    https://en.wikipedia.org/wiki/XY_problem

    What are you TRYING to do, because 100% of the things you propose above will NEVER work in Unity.

    I could bore you with pages of detail about lifecycle and constructor times, but you still CANNOT DO what you are trying to do.

    So I ask again,

    "What are you TRYING to do here?"

    Note: this is not "What is your approach?" I can see your approach, that's the problem.

    The question is, "What is your goal here? What problem are you solving in your game?"
     
  9. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455


    I maybe write it wrong i have static clas

    I try to explain what i am trying to do :

    I have one non mono behaviour class what managing my DB - SqlManager
    In this script iam trying to create event what will trigger when value in my DB is updated.

    Then in my second MONOBEHAVIOUR class i want capture this event and i want update UI values, i post my codes.
    Thanks for help

    If i make both scripts monobehaviour and if i replace MenuUI mUI = new MenuUI(); for MenuUI mUI = FindObject...... and add SqlManager to GO then it is working but i dont want to have my SqlManager script as monobehaviour
     

    Attached Files:

    Last edited: May 30, 2021
  10. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    You can use
    UnityEngine.Object
    features in plain C# classes like usual, static or otherwise.

    Example of finding a type of MonoBehaviour:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public static class SomeClass {
    4.   MyScript script;
    5.  
    6.   void FindMyScript() {
    7.     script = Object.FindObjectOfType<MyScript>();
    8.   }
    9. }
    Example of instantiating a MonoBehaviour:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public static class SomeClass {
    4.   MyScript script;
    5.  
    6.   void InstantiateMyScript() {
    7.     GameObject scriptObject = new GameObject();
    8.     script = scriptObject.AddComponent<MyScript>();
    9.   }
    10. }
    Both of these will find/instantiate in the currently active scene.
     
    MartinMa_ and PraetorBlue like this.
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,006
    Doesn't need to be static... just make it a singleton with an instance initializer (kinda how Vryken is doing above) and the first time you use it, everything will get set up, because by that time, Unity is truly up and running and you can safely call .AddComponent<T>() to create your Monobehavior.
     
    MartinMa_ likes this.
  12. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455

    This solved my issue, thanks.

    Code (CSharp):
    1. sql = UnityEngine.Object.FindObjectOfType<SqlManager>();
     
  13. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,363
    My apologies, not sure why I inherited from MonoBehaviour there (typed it from memory on my tablet :D). I fixed the error above.

    If I got you right then SQLManager is NOT a MonoBehaviour. You could make it a singleton and then request it from whichever class needs it (MonoBehaviour or not).

    Also, I saw in your ui that you subscribe to the event with += in the Update() of your MonoBehaviour. You better move this to Awake() or OnEnable() or else it will subscribe anew in every frame, which I guess is not what you intended.

    Anyhow, glad you solved it.
     
  14. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    @_geo__
    @Kurt-Dekker
    @Vryken

    Thanks for your answers, it helped however i like to know one more thing.
    I have both scripts conected now Static class to Monobehaviour it is fine but i "FindingObjectOfType" each time i call this function and i dont like it. Is here some way how can i initilize this on start in static class?

    My code in static class look like this.
    Code (CSharp):
    1.    public static void AddIntValue(string name, int value)
    2.         {
    3.             events = UnityEngine.Object.FindObjectOfType<Events>();
    4.             events.OnGameValueChange?.Invoke(events, EventArgs.Empty);
    5.             if (name == Minerals.Soil.ToString())
    6.             {
    7.                 Materials.Soil += value;
    8.                 progressExperience += value;
    9.                 experience += value;
    10.                 Materials.carryingMaterial += 1;
    11.            
    12.             }
    13. }
     

    Attached Files:

  15. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    nvm i just made static method Start and i call it once on "game start"