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. Dismiss Notice

Question Values get Unassigned after scene reset

Discussion in 'Editor & General Support' started by Magix314, Sep 27, 2023.

  1. Magix314

    Magix314

    Joined:
    Apr 11, 2020
    Posts:
    2
    Hello, after my player dies it resets the scene but my Image healthBar that I assigned in the editor gets removed along with other values or prefabs I assigned in the editor, what could be a possible fix?

    Here is the GameManager script where it resets the scene:

    using TMPro;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;

    public class GameManager : MonoBehaviour
    {
    [Header("Attributes")]
    [SerializeField] public Image healthBar; // This component gets unassigned
    [SerializeField] public float health = 100f;
    [SerializeField] private TextMeshProUGUI scoreText;
    [SerializeField] private TextMeshProUGUI cashText;
    [SerializeField] public static float cashMultiplier = 1f;


    [HideInInspector] public static float maxHealth = 100;
    public static int points = 0;
    public static int cash = 0;

    [Header("Events")]
    public static UnityEvent onScoreUpdate = new UnityEvent();

    private void Awake()
    {
    DontDestroyOnLoad(this.gameObject);
    onScoreUpdate.AddListener(UpdateScore);
    }
    void Update()
    {

    if (health <= 0)
    Death();

    if (health > maxHealth)
    health = maxHealth;

    if (Input.GetKeyDown(KeyCode.Alpha1))
    TakeDamage(20f);

    if (Input.GetKeyDown(KeyCode.Alpha2))
    Heal(20f);

    if (Input.GetKeyDown(KeyCode.Alpha4))
    {
    cash += 1000;
    cashText.text = ("Cash:" + cash);
    }

    }

    public void Death()
    {
    maxHealth = 100;
    health = maxHealth;

    GameObject healthBarObject = healthBar.gameObject;
    healthBarObject.transform.SetParent(null);
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }


    public void TakeDamage(float damage)
    {
    if (healthBar != null)
    {
    health -= damage;
    healthBar.fillAmount = health / maxHealth;
    }
    else
    {
    Debug.LogWarning("healthBar is not assigned in the Inspector.");
    }
    }

    public void Heal(float healAmount)
    {

    health += healAmount;
    healAmount = Mathf.Clamp(health, 0, maxHealth);

    healthBar.fillAmount = health / maxHealth;
    }
    public void UpdateScore()
    {
    scoreText.text = ("Score:" + points);
    cashText.text = ("Cash:" + cash);
    }
    }

    In this screenshot we see more prefabs and items get unnasigned
    upload_2023-9-27_21-36-52.png
     
  2. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,834
    Changes made to (almost) anything in the Inspector while you are in Play mode will be dropped and reset to prior values when you stop playing. This is to let you experiment during play mode. Do the actual designing outside play mode.
     
  3. Magix314

    Magix314

    Joined:
    Apr 11, 2020
    Posts:
    2
    I'm aware of that feature, I have not assigned anything in the inspector during play mode all in editor. The Assigned values only get removed after I reset the current scene
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Yes, you have a DontDestroyOnLoad object that's referencing an object in a scene.

    When you reload a scene, everything in it is destroyed, and a whole new instance of everything is reloaded. Your DontDestroyOnLoad object now has a reference to a bunch of destroyed game objects/components, hence the 'missing' in the object field.

    If you want to take this approach, your managers probably need to express a singleton pattern, and these components subscribe/unsubscribe themselves from said manage when they're created and destroyed.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance

    Alternately you could start one up with a
    RuntimeInitializeOnLoad
    attribute.

    The above solutions can be modified to additively load a scene instead, BUT scenes do not load until end of frame, which means your static factory cannot return the instance that will be in the to-be-loaded scene. This is a minor limitation that is simple to work around.

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

    OR just make a custom ScriptableObject that has the shared fields you want for the duration of many scenes, and drag references to that one ScriptableObject instance into everything that needs it. It scales up to a certain point.

    And finally there's always just a simple "static locator" pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

    WARNING: this does NOT control their uniqueness.

    WARNING: this does NOT control their lifecycle.

    Code (csharp):
    1. public static MyClass Instance { get; private set; }
    2.  
    3. void OnEnable()
    4. {
    5.   Instance = this;
    6. }
    7. void OnDisable()
    8. {
    9.   Instance = null;     // keep everybody honest when we're not around
    10. }
    Anyone can get at it via
    MyClass.Instance.
    , but only while it exists.