Почему текущий текст не обновляется? - PullRequest
2 голосов
/ 27 июня 2019

Я пытаюсь создать жизненную систему в моей игре, но тест на экране не обновляется, хотя переменная есть.Я хочу, чтобы мой текст также обновлялся.

enter image description here

Класс LoseCollider

[SerializeField] TextMeshProUGUI livesText;
[SerializeField] static int currentLives = 4;

public void Start()
{
    livesText.text = "Lives: " + currentLives.ToString();
    Debug.Log(currentLives);
}

private void OnTriggerEnter2D(Collider2D collision)
{
    if (currentLives > 0)
    {
        currentLives--;
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

    if (currentLives <= 0)
    {
        SceneManager.LoadScene("Game Over");
        currentLives = 4;
    }
}

Я думаю, что вы правы в отношении DontDestroyпроблема.

Это из другого сценария

public class GameSession : MonoBehaviour
{

    // config params
    [Range(0.1f, 10f)] [SerializeField] float gameSpeed = 1f;
    [SerializeField] int pointsPerBlockDestroyed = 83;
    [SerializeField] TextMeshProUGUI scoreText;
    [SerializeField] bool isAutoPlayEnabled;


    // state variables
    [SerializeField] int currentScore = 0;


    private void Awake()
    {
        int gameStatusCount = FindObjectsOfType<GameSession>().Length;

        if (gameStatusCount > 1)
        {
            gameObject.SetActive(false);
            Destroy(gameObject);
        }
        else
        {
            DontDestroyOnLoad(gameObject);
        }
    }


    // Start is called before the first frame update
    void Start()
    {
        scoreText.text = currentScore.ToString();  

    }

    // Update is called once per frame
    void Update()
    {
        Time.timeScale = gameSpeed;
    }

    public void AddToScore()
    {
        currentScore += pointsPerBlockDestroyed;
        scoreText.text = currentScore.ToString();
    }

    public void ResetGame()
    {
        Destroy(gameObject);
    }

    public bool IsAutoPlayEnabled()
    {
        return isAutoPlayEnabled;
    }
}

Теперь я полностью к единству.Есть идеи как это решить?

Ответы [ 2 ]

2 голосов
/ 27 июня 2019

Как я и подозревал, вы используете DontDestroyOnLoad.

Ваш первый скрипт, кажется, прикреплен к тому же объекту, что и GameSession, или находится в иерархии под ним (дочерний элемент).

Это делает Start be никогда , вызываемым снова.


Но вы можете зарегистрировать обратный вызов на SceneManager.sceneLoaded вЧтобы обновить текст:

public class GameSession : MonoBehaviour
{
    // ...

    private YourFirstScript yourFirstScript;

    // rather implement a Singleton pattern this way
    private static GameSession Instance;

    private void Awake()
    {
        if(Instance)
        {
            Destroy(gameObject);
            return;
        }

        Instance = this;

        DontDestroyOnLoad(gameObject);

        // Add the callback
        // it is save to remove even if not added yet
        // this makes sure a callback is always added only once
        SceneManager.sceneLoaded -= OnSceneLoaded;
        SceneManager.sceneLoaded += OnSceneLoaded;

        yourFirstScript = GetComponentInChildren<YourFirstScript>(true);
    }

    private void OnDestroy()
    {
        // make sure to remove callbacks when not needed anymore
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }

    // called everytime a scene was loaded
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        scoreText.text = currentScore.ToString(); 

        // Since you made it public anyway simply call the method
        // of your first script
        // You shouldn't call it Start anymore
        // because now it will be called twice
        yourFirstScript.Start();
    }

    // ...
}

Примечание. Также важно, чтобы livesText также был либо DontDestroyOnLoad, либо переназначался после загрузки сцены.В противном случае вы получите NullReferenceException в любом случае.


Как переназначить livesText?

Вы можете сделать Instance из GameSession

public static GameSession Instance;

это немного злоупотребляет одноэлементным шаблоном и противоречивым типом ... но я думаю, что это хорошо для быстрого прототипирования.

и также делает levelText в YourFirstScript

public TextMeshProUGUI levelText;

Тогда вы можете просто добавить новый компонент в соответствующий объект levelText, например

[RequireComponent(typeof(TextMeshProUGUI))]
public class LevelTextAssigner : MonoBehaviour
{
    // you can reference this already in the Inspector
    // then you don't need to use GetComponent
    [SerializeField] private TextMeshProUGUI _text;

    // Is called before sceneLoaded is called
    private void Awake()
    {
        if(!_text) _text = GetComponent<TextMeshProUGUI>();

        // It is possible that the first time GameSession.Instance is not set yet
        // We can ignore that because in this case the reference still exists anyway
        if(GameSession.Instance)
        {
            GameSession.Instance.YourFirstScript.leveltext = _text;
        }
    }
}
0 голосов
/ 27 июня 2019

Установите TextMeshProUGUI через API "SetText".Выполнение text = "something"; обновляет поле поддержки, где хранится значение, но не обязательно запускает графический интерфейс для обновления текста.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...