Загрузить сцену с переменной param Unity

В моей игре есть вид карты, содержащий сетку плиток 50x50. Когда вы щелкаете по плитке, вы попадаете в эту плитку, которая просматривает объекты и атакует их и т. Д. Единственная разница между этими "плитками" в том, что касается кода, - это идентификатор плитки, он же. какой номер в сетке. Этот номер будет передан серверу при инициализации, чтобы обработать все остальное.

Очевидно, что это единственное различие в плитках, было бы ошибкой создавать сцену "1", сцену "2" ... сцену "2500" и вызывать SceneManager.LoadScene для переключения на конкретный вид плитки.

Я мог бы использовать DontDestroyOnLoad (); при нажатии на плитку для сохранения идентификатора плитки при переключении сцены, но 1) он принимает только игровые объекты, а не только переменную типа int 2) Мне не нужно / не хочу сохранять эту переменную для чего-либо, кроме инициализации в представлении плитки. Так что, хотя это могло сработать, это кажется излишним.

Есть ли лучший способ просто передать параметр в загрузку сцены?


person DasBeasto    schedule 22.02.2017    source источник
comment
Я полагаю, вы могли бы создать статический класс, содержащий информацию, если он вам не нужен для взаимодействия с игровыми объектами (наследование моноповедения). 1 сек, приведу небольшой пример.   -  person Fredrik Schön    schedule 22.02.2017


Ответы (3)


Вы можете создать статический класс, который будет хранить для вас информацию. Этот класс не будет прикреплен к какому-либо GameObject и не будет уничтожен при смене сцены. Это static, что означает, что может быть только ОДИН из них; вы не можете написать StaticClassName scn = new StaticClassName() для создания новых статических классов. Например, вы получаете к ним доступ прямо через StaticClassName.SomeStaticMethod(), и к ним можно получить доступ откуда угодно. В этом примере показано, как сохранить значение в переменной, изменить сцену и затем использовать ее в этой сцене (обратите внимание на добавленный using UnityEngine.SceneManagement;):

Обычный скрипт Unity, прикрепленный к GameObject в тесте сцены:

using UnityEngine;
using UnityEngine.SceneManagement;
public class TestingScript : MonoBehaviour {
    void Start()
    {
        StaticClass.CrossSceneInformation = "Hello Scene2!";
        SceneManager.LoadScene("Test2");
    }
}

Новый статический класс (не наследуемый от monobehaviour), содержащий информацию:

public static class StaticClass {
    public static string CrossSceneInformation { get; set; }
}

Скрипт, прикрепленный к игровому объекту в сцене Test2:

using UnityEngine;
public class TestingScript2: MonoBehaviour {

    void Start () {
        Debug.Log(StaticClass.CrossSceneInformation);
    }
}

Вам не нужно, чтобы весь класс был статическим (если вам по какой-то причине нужно создать больше его экземпляров). Если бы вы удалили static из класса (а не из переменной), вы все равно можете получить доступ к статической переменной через StaticClass.CrossSceneInformation, но вы также можете сделать StaticClass sc = new StaticClass();. С этим sc вы можете использовать нестатические члены класса, но не static CrossSceneInformation, поскольку может быть только ОДИН из них (потому что он статический).

person Fredrik Schön    schedule 22.02.2017
comment
Обычно я просто создаю один такой класс для каждой сцены, которому нужна некоторая контекстная информация. - person Dunno; 22.02.2017
comment
Мне это очень нравится! Как раз то, что мне нужно. И что вы для напоминаний о том, что такое статика, я использовал их несколько произвольно. - person DasBeasto; 22.02.2017
comment
Здорово! Рад помочь! - person Fredrik Schön; 22.02.2017
comment
Но где живет StaticClass? В каком файле или скрипте? - person KevinVictor; 13.04.2019
comment
В любом месте, если он статичен, он будет доступен откуда угодно. Он может находиться в вашем корневом каталоге или любой подпапке, если он находится в вашем решении. - person Fredrik Schön; 13.04.2019
comment
В ПОРЯДКЕ. Так инициализируются ли все статические поля во всем решении при запуске игры? - person KevinVictor; 13.04.2019
comment
да. Однако статический КОНСТРУКТОР не вызывается до тех пор, пока класс (или поле в классе) не будет вызван в первый раз. - person Fredrik Schön; 13.04.2019
comment
Хорошо, спасибо. Кстати, трудно было понять, что к статическому полю в MonoBehaviour, прикрепленном к GameObject в одной сцене, можно получить доступ из любого места, даже если эта сцена не загружена. например У меня может быть сцена MainMenu, в которой есть сценарий со статическими полями, и эти поля сохраняются даже при загрузке другой сцены. - person KevinVictor; 13.04.2019
comment
Хотя это действительно не похоже на правильный способ сделать это ...? Я надеялся на пример с использованием LoadSceneParameters ....? Это совсем не ООД. - person Dylan Brams; 23.05.2020
comment
С точки зрения технологий, это старый ответ. Я не думаю, что в 2016/2017 году было другое решение. Загрузка сцены с параметрами кажется приятной, я должен взглянуть на 2020 год и посмотреть, смогу ли я обновить ответ! - person Fredrik Schön; 25.05.2020
comment
объектно-ориентированный убийца ... - person Erçin Dedeoğlu; 05.01.2021

Просто хотел поделиться готовым решением для этого, поскольку на вопрос уже дан ответ, поэтому другие или, возможно, даже OP используют его.

Этот скрипт использует подход «ключ-значение» для хранения и изменения переменных внутри статического класса, что означает, что он доступен во всех сценах, поэтому вы можете использовать его как постоянное хранилище между сценами, так что все, что вам нужно сделать импортирует скрипт в ваш проект Unity и использует API (пример см. ниже):

using System.Collections.Generic;

/// <summary>
/// A simple static class to get and set globally accessible variables through a key-value approach.
/// </summary>
/// <remarks>
/// <para>Uses a key-value approach (dictionary) for storing and modifying variables.</para>
/// <para>It also uses a lock to ensure consistency between the threads.</para>
/// </remarks>
public static class GlobalVariables
{

    private static readonly object lockObject = new object();
    private static Dictionary<string, object> variablesDictionary = new Dictionary<string, object>();

    /// <summary>
    /// The underlying key-value storage (dictionary).
    /// </summary>
    /// <value>Gets the underlying variables dictionary</value>
    public static Dictionary<string, object> VariablesDictionary => variablesDictionary;

    /// <summary>
    /// Retrieves all global variables.
    /// </summary>
    /// <returns>The global variables dictionary object.</returns>
    public static Dictionary<string, object> GetAll()
    {
        return variablesDictionary;
    }

    /// <summary>
    /// Gets a variable and casts it to the provided type argument.
    /// </summary>
    /// <typeparam name="T">The type of the variable</typeparam>
    /// <param name="key">The variable key</param>
    /// <returns>The casted variable value</returns>
    public static T Get<T>(string key)
    {
        if (variablesDictionary == null || !variablesDictionary.ContainsKey(key))
        {
            return default(T);
        }

        return (T)variablesDictionary[key];
    }

    /// <summary>
    /// Sets the variable, the existing value gets overridden.
    /// </summary>
    /// <remarks>It uses a lock under the hood to ensure consistensy between threads</remarks>
    /// <param name="key">The variable name/key</param>
    /// <param name="value">The variable value</param>
    public static void Set(string key, object value)
    {
        lock (lockObject)
        {
            if (variablesDictionary == null)
            {
                variablesDictionary = new Dictionary<string, object>();
            }
            variablesDictionary[key] = value;
        }
    }

}

И вы можете использовать его в сценарии, который находится внутри сцены Главное меню, скажем:

public class MainMenuScript : MonoBehaviour
{

    void Start()
    {

        // Load a sample level
        LoadLevel(12);
    }

    public void LoadLevel(int level)
    {
        GlobalVariables.Set("currentLevelIndex", level);
        UnityEngine.SceneManagement.SceneManager.LoadScene("Game");
    }

}

А другой находится внутри сцены Игры:

public class GameScript : MonoBehaviour
{

    void Start()
    {
        int levelIndex = GlobalVariables.Get<int>("currentLevelIndex");
        Debug.Log(levelIndex); // Outputs 12
    }

}

Итак, данные назначаются в главном меню, сцена доступна из Игры или любой другой сцены.

Подробнее о скрипте с примерами использования ›

person Empire    schedule 11.03.2021
comment
Я бы просто использовал MyScript: Singleton ‹MyScript› {} вместо - person Nick Turner; 18.03.2021

Маакеп! Идеальный и простой код!

Но ваш метод загрузки сцены не работает.

Вы можете использовать другой метод:

UnityEngine.SceneManagement.SceneManager.LoadScene("Vuforia-4-Spheric");
person azatserzhan    schedule 11.07.2018
comment
Это тот же метод, но с указанием всего пространства имен вместо его импорта. Если вы добавите using UnityEngine.SceneManagement; в начало файла, вы сможете использовать его как SceneManager.LoadScene("scene"). :) - person Fredrik Schön; 26.07.2018