Search Unity

Bug Scene Asset as Object.name doesn't return a value when compiled

Discussion in 'Scripting' started by VakarisJ, Mar 21, 2021.

  1. VakarisJ

    VakarisJ

    Joined:
    Mar 21, 2021
    Posts:
    4
    So as to not hardcode the Scene names, I wanted a public variable to hold them. In the editor, everything works flawlessly, however once the game is compiled, Object.name doesn't return a value.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3. using UnityEngine.UI;
    4.  
    5. public class SceneLoadTest : MonoBehaviour {
    6.     public Object scene;
    7.     public Text text;
    8.  
    9.     void Update() {
    10.         text.text = scene.name;
    11.  
    12.         if (scene == null) text.text = "Scene is NULL!";
    13.  
    14.         if (Input.GetKey(KeyCode.Keypad0)) {
    15.             SceneManager.LoadScene(scene.name);
    16.         }
    17.     }
    18. }
    With this code, the Text retains its default value (the one assigned in the inspector), instead of changing to the name of the Scene. I've tried using different objects and found that Sprites and Sounds work fine, which indicates this is an issue with the Scene Asset after compilation.

    I'm using Unity version 2020.3.0f1 and have also noted this issue in version 2020.1.2f1.
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I'm confused about what your "scene" variable actually is.

    There are no such things as "Scene assets". Not in the sense that there are Meshes, and Sprites, and AudioClip assets.

    The scene type is a struct, meaning it doesn't inherit from UnityEngine.Object: https://docs.unity3d.com/ScriptReference/SceneManagement.Scene.html

    So what are you actually referencing in the inspector with that Object scene field? Did you create some random Sprite or something with the scene name as its name?
    It's unfortunate that Scenes are not considered Assets in unity, and they are not directly serializable the way other assets are. To get around this a lot of people just use strings with the scene name.
     
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Ok apparently I'm mistaken about there not being a Scene Asset:
    https://docs.unity3d.com/ScriptReference/SceneAsset.html

    The problem is - SceneAsset is part of the UnityEditor namespace. You cannot use anything from UnityEditor in a build. That's why it's only working in the editor. You have to ultimately just use a string to serialize a reference to your scene.
     
  4. VakarisJ

    VakarisJ

    Joined:
    Mar 21, 2021
    Posts:
    4
    Regardless of what it is, Unity Inspector allows it to slot into an Object field. It works in the editor, but not in the final build, yet is not specifically stated to be an editor-only item. In the final build, the Object does not return a null, meaning it is assigned, but its name cannot be called. Regardless how I look at it, it's still a bug.

    It's called a "Scene Asset" in the inspector window, just like a Sprite is called "Texture 2D" or a sound "Audio Clip", but I'm not using it as a Scene Asset, I'm using it as a generic Object, that it extends.

    To clarify, a "Scene Asset" is a ".unity" file that is used to load a level and even in that link you gave it clearly states "inherits from:Object".
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    But it is specifically stated to be an editor only item:

    Screen Shot 2021-03-21 at 1.54.29 PM.png

    You are using UnityEngine.Object in your script, which means you are not explicitly
    using UnityEditor;
    , but that doesn't change the fact that you are using a UnityEditor type.

    If you look at the doc page for SceneAsset, they include an example for how to use a SceneAsset properly that will work in a build. I do wish you could just straight up use SceneAsset without jumping through hoops.
     
    Last edited: Mar 21, 2021
  6. VakarisJ

    VakarisJ

    Joined:
    Mar 21, 2021
    Posts:
    4

    Since I cast it as an Object and not a Scene, I am explicitly using the UnityEngine, rather than UnityEditor.
     
  7. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Who do you think you are fooling?

    Yes the compiler will let you do it. But the SceneAsset class literally does not exist in your build. The variable type may be Object, but the actual object is of type SceneAsset. Editor types do not get packaged into your build.

    Why do you think you're having to jump through this hoop of using a plain Object field in the first place? That alone should tip you off something is not right. I'm guessing you tried to use SceneAsset, and then your game would not build, so you tried to "fix it" by changing the reference to Object?
     
    Kurt-Dekker likes this.
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,695
  9. VakarisJ

    VakarisJ

    Joined:
    Mar 21, 2021
    Posts:
    4
    Since I cast it as an Object, then it is an Object and all other properties are lost in the cast. Like casting a Vector3 to a Vector2. It is no longer a Scene Asset, but an Object that inherits some properties of the original. Like the name, that I need. I'm not trying to use it load a scene, I'm trying to use it to extract a string, which I can then use to load a scene.

    I'm not even sure we're talking about the same Scene Asset. The one I'm referring to is this:

    Not typeof, not as. Not even a struct, but an actual Asset.


    Well, thanks anyway.
     
  10. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I understand what you are trying to do, but your understanding of how object references work in C# is mistaken. When you cast a reference to a reference type such as UnityEngine.Object or System.object or SceneAsset, the object itself is not changed. You are merely changing the lens through which you are viewing the object. The fields are still there, you just can't access them through that variable. It is still a SceneAsset, even though you are viewing it through the lens of Object.

    When you convert a Vector3 to a Vector2 that is a different process. There is a special conversion Unity has defined between Vector3 and Vector2 as documented here: https://docs.unity3d.com/ScriptReference/Vector2-operator_Vector3.html

    Additionally, because Vector3 and Vector2 are structs, they are value types. This means assigning the value to a variable actually copies the object, and in this case with this conversion, it discards the z component. The main point though is that a copy is created, which is not the case for reference types like UnityEngine.Object and SceneAsset.

    We are talking about the same thing. It is this: https://docs.unity3d.com/ScriptReference/SceneAsset.html