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. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Accessing Class in Another Scene?

Discussion in 'Editor & General Support' started by CelticKnight, Mar 26, 2018.

  1. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    Hi Guys,

    I am trying to access a class that is in another scene and don't really know how to go about it. I have never done anything like this before.

    In the script trying to access the other class I am using the following code snippet

    public MusicManager mm;

    // Use this for initialization
    void Start () {
    mm = GetComponent<MusicManager>();
    mm.getIndex();
    }

    and am getting the following error from the: mm.getIndex() line

    NullReferenceException: Object reference not set to an instance of an object
    PlayMusic.Start ()

    Any help would be greatly appreciated.

    Warmest Regards.
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Classes aren't scene specific. All classes exist in all scenes. GameObjects and instances of their attached components though, only exist if they are a part of any running scene.

    The problem with your code is you're trying to find a MusicManager component on the same GameObject as this script is attached to. That is failing because that GameObject doesn't have a MusicManager component, so the GetComponent call returns null, and then you get a NullReferenceException when you try to call getIndex on the null reference.

    What you need is to get a reference to whatever GameObject has the MusicManager component. If no object exists in the scene with it, you need to make it exist first, or you need to wait to get a reference to it until it exists. You said it exists in another scene. Is this another scene that is currently running? (Unity can load scenes additively, so multiple scenes can be running at the same time) If the scene with that GameObject isn't running then you can't access its instance of MusicManager. You'd need to attach MusicManager to an object in this scene, or have the other object persist between scenes, etc.
     
  3. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    Right, now I understand how the GetComponent thingy works now:cool:. Only for that GameObject - doh! Thanks greatly for that, that is going to help moving forward.

    As for what I am attempting to do is set up a MusicManager that controls the background music in the scene. So, I set up the MusicManager in the SplashScreen scene and have all subsequent scenes access it and make changes to the BGmusic dependent on each scene. It's overkill for now. but. why not, a chance to learn something new. So, there is no need for the scene to be run concurrently just need to link up a path to the MusicManager - which I thought I did with the GetComponent - which I now know is erroneous (thanks again).

    The MusicManager has a don't destroy on load thingy, so, it's persisting and should be able to be accessed I just don't know how, yet.

    So any help, even pointing to some Unity docs would be very helpful.
     
  4. FirstTimeCreator

    FirstTimeCreator

    Joined:
    Sep 28, 2016
    Posts:
    768
    To access another class you need to know it's namespace if it has one.

    if it does, add Using *NameSpace; at the top of your c# script.

    if it does not:

    add this to the top of your class:
    SomeClass MyClassVar;
    The name of the class : Your name /scope for usage in this other class;

    Then you drag and drop the class of it is on a game object to the gameobject this class is on.

    Then you can access the class by typing:

    MyClassVar.SomeFunction();

    You can also drag the script from project navigation if you don't want or have it on a gameobject.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class MyCurrentClass: MonoBehaviour {

    public CustomRBController CustomRB; <- drag your character controller script here

    void FixedUpdate() {

    CustomRB.Activate(true);


    }


    }


    this is just an example, hope it helps.
     
    PaulR77 likes this.
  5. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    I have used that whatever.Activate(true) statement before in a racing game I was making, it may be a good idea to reacquaint myself with it, I vaguely remember using that to access a component in the same scene. I aslo had to make use of a using so I will look into that as well. Thanks for that :).

    As for my immediate concerns I found code trolling through the forums that works for now:

    mm = GameObject.Find("MusicManager").GetComponent<MusicManager>();
    mm.getIndex();
    Never been a fan of using "find", but, it will do for now it is only being run once per scene - so it shouldn't cause any major problems. And look for a better alternative later.

    Thanks for your responses - I always eager to learn :cool:.
     
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    It is slightly better to assign a custom tag to your MusicManager object and write your code more like this:

    Code (csharp):
    1. GameObject mmObject = GameObject.FindGameObjectWithTag("MusicManager");
    2. if (mmObject != null)
    3. {
    4.     mm = mmObject.GetComponent<MusicManager>();
    5.     mm.GetIndex();
    6. }
    7. else
    8. {
    9.     Debug.Log("MusicManager object not found");
    10. }
    Finding by tag instead of GameObject name performs slightly better, and it is less prone to errors in that tags are obvious identifiers you normally wouldn't accidentally change. GameObject names though usually don't matter, so it is more common to change them and not realize you're breaking code that depends on the name not changing.

    The above also won't throw a null reference error if the MusicManager object doesn't exist, instead just logging the issue.
     
    CelticKnight likes this.
  7. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    Oh really, thanks greatly for that! I will implement that immediately along with the info you provided as comments, so I can remember that in the future. I will be turning this into a custom package to use in future games so having those comments will really help.

    Thankyou and Regards :cool:.

    EDIT:

    I put that code into the editor and got the following error on the line:

    GameObject mmObject = GameObject.FindGameObjectWithTag("MusicManager");

    UnityException: Tag: MusicManager is not defined.
    PlayMusic.Start () (at Assets/PlayMusic.cs:24)

    I am unfamiliar with this code so do you know what the problem might be, I really like the idea of doing it your way but this is a little out of my league.
     
  8. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    Oh, I see, I need to define an actual Tag in the Inspector! :oops:

    I really, really like that idea! :cool::cool:
     
    Last edited: Mar 28, 2018
  9. StickyHoneybuns

    StickyHoneybuns

    Joined:
    Jan 16, 2018
    Posts:
    207
    IMO, switching to a singleton/pre-load scene/game manager is the best way to go about this. Once you adopt this method I doubt you will go back since it solves all the issues between different scenes. Since your MusicManager needs to have references to objects in different scenes then you can simply have a DontDestroyOnLoad on that object and then it can hold references to whatever you need.

    Here is the general idea:
    https://stackoverflow.com/questions...-script-works-only-one-time/35891919#35891919

    There is always a better way then using GameObject.Find.
     
    CelticKnight likes this.
  10. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Sorry, I should have been more explicit :p

    Glad you figured it out!
     
    CelticKnight likes this.
  11. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    From everything I've read and heard on Unity scripting - which to be honest isn't a great deal - was that singleton's should be avoided at all costs and are considered bad programming practice! Is this not the case? Or does necessity with a game manager trump that rule?
     
  12. StickyHoneybuns

    StickyHoneybuns

    Joined:
    Jan 16, 2018
    Posts:
    207
    With everything else a singleton is typically avoided. With a game manager however, how else would you do it? You need to have a manager keeping track of things throughout your game. This is how Unity teaches it as well in their game manager tutorial.

    https://unity3d.com/learn/tutorials/projects/2d-roguelike-tutorial/writing-game-manager

    The link I posted in the last post takes it a step further and uses a pre-load scene. When I first heard about a pre-load scene I was against it. Then I implemented it in my last project and it made things so much easier. Using DDOL insured there would only ever be one instance as well.
     
    CelticKnight likes this.
  13. CelticKnight

    CelticKnight

    Joined:
    Jan 12, 2015
    Posts:
    378
    Thanks a lot for your post and including the link as well. I'll read it the first chance I get! :cool:
     
  14. PaulR77

    PaulR77

    Joined:
    Dec 14, 2016
    Posts:
    2
    I managed to create a singleton to switch screens ...
    It works, as you can see from the screen print (UNITY_Experm02.png) I have uploaded. There is one thing I don't like about it: Every time the player switches screens, a new instance of the class SceneMainUIacts is created and then destroyed, since it is a duplicate. The C# code file has also been uploaded.
    Both screens have access to the singleton class.
     

    Attached Files:

    Last edited: Apr 6, 2018
    CelticKnight likes this.