最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - PersistentScene gets deleted wheb restarting the game - Stack Overflow

programmeradmin1浏览0评论

I'm creating a game called Gravity Shifter, and I currently have four scenes. The first one is the Main Menu, followed by PersistentScene, which contains UI elements such as buttons and health text, allowing the UI to persist across all levels. Then, I have Level1 and Level2.

As I mentioned, except for the Main Menu, I want PersistentScene to be present in all other scenes (the level scenes). However, when I play the game and press the restart button, the game restarts, but PersistentScene gets deleted. This shouldn't happen because, after restarting, I'm unable to use the UI elements.

Now I have some code that might be causing the problem.

GameManager.cs:

using UnityEngine;
using UnityEngine.SceneManagement;

// bu kod persistentSceneyi gerekli levellere eklemek icin var.
public class GameManager : MonoBehaviour
{
    public static GameManager instance;

    void Awake()
    {
        // Eğer GameManager'ın bir örneği henüz yoksa, bu örneği kalıcı yap
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject); // Bu GameObject ve bileşenleri sahne geçişlerinde kalır.
        }
        else
        {
            // Zaten bir örnek varsa, bu fazladan olanı yok et.
            Destroy(gameObject);
            return;
        }
    }

    void Start()
    {
        // PersistentScene zaten yüklenmemişse ve main menu sahnesinde degil isek o zaman yukleriz 
        if (!SceneManager.GetSceneByName("PersistentScene").isLoaded && SceneManager.GetActiveScene().name != "MainMenu")
        {
            SceneManager.LoadScene("PersistentScene", LoadSceneMode.Additive);
        }

        Time.timeScale = 1f;  // Level1'e girerken zaman ölçeğini sıfırlıyoruz
    }

    // Oyunu sıfırlama fonksiyonu Oyun restart oldugunda bu funcu restart game button scriptin de kullanicaz
    public void RestartGame()
    {
        // Zamanı normal hızda başlat oyun yeniden basladiginda bu deger 0 olursa oyun donar bunu engellemek icin de bunu 1 yapariz
        Time.timeScale = 1f;

        PlayerManager.Instance.ResetPlayerPosition();
    }
}

PlayerManager.cs:

using UnityEngine;

public class PlayerManager : MonoBehaviour
{
    private static PlayerManager instance;

    public static PlayerManager Instance
    {
        get { return instance; }
    }

    public GameObject player;

    public Vector3 startingPosition; // starting position when game restarts or starts

    private void Awake()
    {
        // Singleton yapısı
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);  // PlayerManager, sahne geçişlerinde yok edilmez
        }
        else
        {
            Destroy(gameObject); // Aynı PlayerManager birden fazla sahnede varsa, yalnızca biri kalır.
        }
    }

    public void ResetPlayerPosition()
    {
        if (player != null)
        {
            player.transform.position = startingPosition;  // Oyuncuyu sıfırla
        }
        else
        {
            Debug.LogWarning("Player object is not assigned.");
        }
    }

    // Oyuncuyu Don't Destroy'dan çıkar ve sil
    public void RemovePlayerFromDontDestroy() 
    {
        Destroy(gameObject);
    }
}

RestartGameButton.cs:

using UnityEngine;
using UnityEngine.UI;

public class RestartGameButton : MonoBehaviour
{
    public GameObject backupCamera; // Yedek kamera referansı (Inspector'dan atanacak)
    public void RestartGameFromBeginning()
    {
        // Yedek kamerayı SceneLoader'a aktar
        SceneLoader.backupCamera = backupCamera;

        // Singleton üzerinden GameManager'a erişip RestartGame fonksiyonunu çağır
        if (GameManager.instance != null)
        {
            GameManager.instance.RestartGame();  // GameManager üzerinden oyunu sıfırla
        }
        else
        {
            Debug.LogError("GameManager instance is not found!");
        }

        SceneLoader.LoadScene(2);  // level1'i yuklemek icin 
    }
}

SceneLoader.cs:

using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour
{
    public static GameObject backupCamera;  // Yedek kamera referansı
    private static string uiSceneName = "PersistentScene"; // UI'nin sahne adı

    public static void LoadScene(int sceneIndex)
    {
        // Eğer ana menüye dönülüyorsa, tüm sahneleri temizle
        if (sceneIndex == 1)
        {
            DestroyPersistentObjects();
            SceneManager.LoadScene(sceneIndex);
        }
        else
        {
            // Yeni sahneyi yükle (UI kaybolmaz)
            SceneManager.LoadScene(sceneIndex, LoadSceneMode.Single);

            // Eğer UI sahnesi yüklü değilse yükle
            if (!SceneManager.GetSceneByName(uiSceneName).isLoaded)
            {
                SceneManager.LoadScene(uiSceneName, LoadSceneMode.Additive);
            }

            // Yedek kamerayı aç
            if (backupCamera != null)
            {
                backupCamera.SetActive(true);
            }
        }
    }

    // Bu sadece ana menüye dönüş için kullanılır
    private static void DestroyPersistentObjects()
    {
        GameObject[] dontDestroyObjects = GameObject.FindObjectsOfType<GameObject>();

        foreach (GameObject obj in dontDestroyObjects)
        {
            if (obj.scene.buildIndex == -1)  // Eğer sahneye bağlı değilse (DontDestroyOnLoad)
            {
                Destroy(obj);
            }
        }
    }
}

I want the PersistentScene to be present in every level scene except the Main Menu.

Thank you!

I'm creating a game called Gravity Shifter, and I currently have four scenes. The first one is the Main Menu, followed by PersistentScene, which contains UI elements such as buttons and health text, allowing the UI to persist across all levels. Then, I have Level1 and Level2.

As I mentioned, except for the Main Menu, I want PersistentScene to be present in all other scenes (the level scenes). However, when I play the game and press the restart button, the game restarts, but PersistentScene gets deleted. This shouldn't happen because, after restarting, I'm unable to use the UI elements.

Now I have some code that might be causing the problem.

GameManager.cs:

using UnityEngine;
using UnityEngine.SceneManagement;

// bu kod persistentSceneyi gerekli levellere eklemek icin var.
public class GameManager : MonoBehaviour
{
    public static GameManager instance;

    void Awake()
    {
        // Eğer GameManager'ın bir örneği henüz yoksa, bu örneği kalıcı yap
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject); // Bu GameObject ve bileşenleri sahne geçişlerinde kalır.
        }
        else
        {
            // Zaten bir örnek varsa, bu fazladan olanı yok et.
            Destroy(gameObject);
            return;
        }
    }

    void Start()
    {
        // PersistentScene zaten yüklenmemişse ve main menu sahnesinde degil isek o zaman yukleriz 
        if (!SceneManager.GetSceneByName("PersistentScene").isLoaded && SceneManager.GetActiveScene().name != "MainMenu")
        {
            SceneManager.LoadScene("PersistentScene", LoadSceneMode.Additive);
        }

        Time.timeScale = 1f;  // Level1'e girerken zaman ölçeğini sıfırlıyoruz
    }

    // Oyunu sıfırlama fonksiyonu Oyun restart oldugunda bu funcu restart game button scriptin de kullanicaz
    public void RestartGame()
    {
        // Zamanı normal hızda başlat oyun yeniden basladiginda bu deger 0 olursa oyun donar bunu engellemek icin de bunu 1 yapariz
        Time.timeScale = 1f;

        PlayerManager.Instance.ResetPlayerPosition();
    }
}

PlayerManager.cs:

using UnityEngine;

public class PlayerManager : MonoBehaviour
{
    private static PlayerManager instance;

    public static PlayerManager Instance
    {
        get { return instance; }
    }

    public GameObject player;

    public Vector3 startingPosition; // starting position when game restarts or starts

    private void Awake()
    {
        // Singleton yapısı
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);  // PlayerManager, sahne geçişlerinde yok edilmez
        }
        else
        {
            Destroy(gameObject); // Aynı PlayerManager birden fazla sahnede varsa, yalnızca biri kalır.
        }
    }

    public void ResetPlayerPosition()
    {
        if (player != null)
        {
            player.transform.position = startingPosition;  // Oyuncuyu sıfırla
        }
        else
        {
            Debug.LogWarning("Player object is not assigned.");
        }
    }

    // Oyuncuyu Don't Destroy'dan çıkar ve sil
    public void RemovePlayerFromDontDestroy() 
    {
        Destroy(gameObject);
    }
}

RestartGameButton.cs:

using UnityEngine;
using UnityEngine.UI;

public class RestartGameButton : MonoBehaviour
{
    public GameObject backupCamera; // Yedek kamera referansı (Inspector'dan atanacak)
    public void RestartGameFromBeginning()
    {
        // Yedek kamerayı SceneLoader'a aktar
        SceneLoader.backupCamera = backupCamera;

        // Singleton üzerinden GameManager'a erişip RestartGame fonksiyonunu çağır
        if (GameManager.instance != null)
        {
            GameManager.instance.RestartGame();  // GameManager üzerinden oyunu sıfırla
        }
        else
        {
            Debug.LogError("GameManager instance is not found!");
        }

        SceneLoader.LoadScene(2);  // level1'i yuklemek icin 
    }
}

SceneLoader.cs:

using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour
{
    public static GameObject backupCamera;  // Yedek kamera referansı
    private static string uiSceneName = "PersistentScene"; // UI'nin sahne adı

    public static void LoadScene(int sceneIndex)
    {
        // Eğer ana menüye dönülüyorsa, tüm sahneleri temizle
        if (sceneIndex == 1)
        {
            DestroyPersistentObjects();
            SceneManager.LoadScene(sceneIndex);
        }
        else
        {
            // Yeni sahneyi yükle (UI kaybolmaz)
            SceneManager.LoadScene(sceneIndex, LoadSceneMode.Single);

            // Eğer UI sahnesi yüklü değilse yükle
            if (!SceneManager.GetSceneByName(uiSceneName).isLoaded)
            {
                SceneManager.LoadScene(uiSceneName, LoadSceneMode.Additive);
            }

            // Yedek kamerayı aç
            if (backupCamera != null)
            {
                backupCamera.SetActive(true);
            }
        }
    }

    // Bu sadece ana menüye dönüş için kullanılır
    private static void DestroyPersistentObjects()
    {
        GameObject[] dontDestroyObjects = GameObject.FindObjectsOfType<GameObject>();

        foreach (GameObject obj in dontDestroyObjects)
        {
            if (obj.scene.buildIndex == -1)  // Eğer sahneye bağlı değilse (DontDestroyOnLoad)
            {
                Destroy(obj);
            }
        }
    }
}

I want the PersistentScene to be present in every level scene except the Main Menu.

Thank you!

Share Improve this question edited 2 days ago DarkBee 15.6k8 gold badges70 silver badges115 bronze badges asked Feb 6 at 15:56 nuray nasirzadenuray nasirzade 12 bronze badges 2
  • Why not rather always load the persistent scene - and then according to required index load the according level scene as additional? Wouldn't this order make things a bit easier? – derHugo Commented Feb 6 at 16:55
  • just by glancing at your code it seems like you are on the right track by using AdditiveScene, one of the issues with using LoadSceneMode.Additive is that whenever you load a different Scene using LoadSceneMode.Single it will destroy all the rest of the current active scenes and only load the passed scene references. A way of handling this is by using SceneManager.UnloadScene whenever you want to change to a different scene but maintain some of them in your active scene list. – Yeis Gallegos Commented Feb 7 at 0:57
Add a comment  | 

1 Answer 1

Reset to default 0

In your RestartGameButton class just return after this line

GameManager.instance.RestartGame();

because after this line your code continues to this line

SceneLoader.LoadScene(2);

and this line is loading scene in index 2 in single mode which will remove all loaded scenes

But if you want to load the load scene on index 2 then you have to update your scene loader to hold a list of loaded scenes and unload loaded scenes first and then load new scenes and while doing this just exclude your PersistentScene scene

On top of this I would recommend you to watch this tutorial

发布评论

评论列表(0)

  1. 暂无评论