Unity中TextMeshPro分数显示异常:场景切换后不更新求助
Unity 2D平台游戏跨场景分数显示异常问题
我正在开发一款Unity 2D平台游戏,玩家拾取道具时,跟踪分数的TextMeshPro元素每次加10,第一关功能正常。但通过LevelExit脚本的OnTriggerEnter2D切换关卡后,playerLives变量仍能正常联动TMPro元素并在死亡时更新,可score整数在第一关后不再更新。不过直接从第二关启动游戏时,分数显示正常,因此问题与场景加载逻辑相关。
我已在各处添加DebugLog,并编写ResetScore公共方法,控制台显示切换关卡后score确实重置为0,但Unity界面上无更新。尝试过强制刷新Canvas等多种更新TMPro的方法,均未解决问题。
相关脚本
ScoreKeeper Script
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using TMPro; public class ScoreKeeper : MonoBehaviour { Pickups pickups; private int score = 0; public int pickupCount = 0; [SerializeField] int playerLives = 3; [SerializeField] TextMeshProUGUI livesText; [SerializeField] TextMeshProUGUI scoreText; void Awake() { int numScoreKeepers = FindObjectsOfType<ScoreKeeper>().Length; if (numScoreKeepers > 1) { Destroy(gameObject); } else { DontDestroyOnLoad(gameObject); } } void Start() { score = 0; livesText.text = playerLives.ToString(); scoreText.text = score.ToString(); } public void ProcessPlayerDeath() { if (playerLives > 1) { TakeLife(); } else { ResetGameSession(); } } public void ResetGameSession() { FindObjectOfType<ScenePersist>().ResetScenePersist(); SceneManager.LoadScene(0); Destroy(gameObject); } void TakeLife() { playerLives --; int currentSceneIndex = SceneManager.GetActiveScene().buildIndex; SceneManager.LoadScene(currentSceneIndex); livesText.text = playerLives.ToString(); } public void IncrementScore(int value) { score += value; scoreText.text = score.ToString(); Debug.Log("scoreText.text is: " + scoreText.text); } public bool CheckIfHasPickups() { pickupCount = GameObject.FindGameObjectsWithTag("Pickups").Length; if (score >= pickupCount * 10) { return (true); } else { return (false); } } public void ResetScore() { score = 0; Debug.Log("Score is " + score); } }
Pickups Script
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Pickups : MonoBehaviour { ScoreKeeper scoreKeeper; Rigidbody2D myRigidbody; void Start() { scoreKeeper = FindObjectOfType<ScoreKeeper>(); myRigidbody = GetComponent<Rigidbody2D>(); } void Update() { PickupInteraction(); } public void PickupInteraction() { if (myRigidbody.IsTouchingLayers(LayerMask.GetMask("Player"))) { scoreKeeper.IncrementScore(10); Destroy(gameObject); } } }
ScenePersist Script
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ScenePersist : MonoBehaviour { void Awake() { int numScenePersists = FindObjectsOfType<ScenePersist>().Length; if(numScenePersists > 1) { gameObject.SetActive(false); Destroy(gameObject); Debug.Log("Level Persist sees it is a copy, destroys itself"); } else { DontDestroyOnLoad(gameObject); } } public void ResetScenePersist() { Destroy(gameObject); } }
LevelExit Script
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class LevelExit : MonoBehaviour { ScoreKeeper scoreKeeper; void Start() { scoreKeeper = FindObjectOfType<ScoreKeeper>(); } void OnTriggerEnter2D(Collider2D other) { if (other.tag == "Player" && scoreKeeper.CheckIfHasPickups()) { StartCoroutine(LoadLevel()); } else { Debug.Log("Not all pickups collected!"); } } IEnumerator LoadLevel() { yield return new WaitForSecondsRealtime(1); scoreKeeper.ResetScore(); int currentSceneIndex = SceneManager.GetActiveScene().buildIndex; SceneManager.LoadScene(currentSceneIndex + 1); FindObjectOfType<ScenePersist>().ResetScenePersist(); } }
问题分析与修复方案
问题根源
ScoreKeeper通过DontDestroyOnLoad在场景切换时保留,但它的scoreText和livesText引用的是第一场景中的UI元素。切换到第二场景后,旧场景的UI已被销毁,新场景的TMPro元素未与保留的ScoreKeeper建立关联,导致后续修改scoreText.text时,实际操作的是已销毁对象的属性,自然无法在新场景显示。
修复步骤
1. 给ScoreKeeper添加场景加载监听,动态获取新场景UI引用
修改ScoreKeeper代码,监听场景加载完成事件,每次场景切换后自动查找当前场景的TMPro元素并更新引用:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using TMPro; public class ScoreKeeper : MonoBehaviour { Pickups pickups; private int score = 0; public int pickupCount = 0; [SerializeField] int playerLives = 3; private TextMeshProUGUI livesText; private TextMeshProUGUI scoreText; void Awake() { int numScoreKeepers = FindObjectsOfType<ScoreKeeper>().Length; if (numScoreKeepers > 1) { Destroy(gameObject); } else { DontDestroyOnLoad(gameObject); // 注册场景加载完成监听 SceneManager.sceneLoaded += OnSceneLoaded; } } // 场景加载完成后执行 void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 通过标签精准查找UI(需给分数/生命UI添加对应标签) var livesObj = GameObject.FindGameObjectWithTag("LivesText"); var scoreObj = GameObject.FindGameObjectWithTag("ScoreText"); if(livesObj == null || scoreObj == null) { Debug.LogWarning("当前场景未找到LivesText/ScoreText标签的UI元素"); return; } livesText = livesObj.GetComponent<TextMeshProUGUI>(); scoreText = scoreObj.GetComponent<TextMeshProUGUI>(); // 同步当前数据到UI livesText.text = playerLives.ToString(); scoreText.text = score.ToString(); } void Start() { // 初始化逻辑移至OnSceneLoaded } public void ProcessPlayerDeath() { if (playerLives > 1) { TakeLife(); } else { ResetGameSession(); } } public void ResetGameSession() { // 移除监听避免内存泄漏 SceneManager.sceneLoaded -= OnSceneLoaded; FindObjectOfType<ScenePersist>().ResetScenePersist(); SceneManager.LoadScene(0); Destroy(gameObject); } void TakeLife() { playerLives --; int currentSceneIndex = SceneManager.GetActiveScene().buildIndex; SceneManager.LoadScene(currentSceneIndex); // 场景加载后OnSceneLoaded会自动更新生命UI } public void IncrementScore(int value) { score += value; if(scoreText != null) { scoreText.text = score.ToString(); Debug.Log("scoreText.text is: " + scoreText.text); } else { Debug.LogWarning("scoreText未初始化,无法更新分数"); } } public bool CheckIfHasPickups() { pickupCount = GameObject.FindGameObjectsWithTag("Pickups").Length; return score >= pickupCount * 10; } public void ResetScore() { score = 0; Debug.Log("Score is " + score); // 重置后立即更新UI if(scoreText != null) { scoreText.text = score.ToString(); } } void OnDestroy() { // 移除监听防止内存泄漏 SceneManager.sceneLoaded -= OnSceneLoaded; } }
2. 给UI元素添加标签
在Unity编辑器中,给显示生命的TextMeshProUGUI添加标签LivesText,给显示分数的TextMeshProUGUI添加标签ScoreText,确保脚本能精准找到目标UI。
3. 移除Inspector中的UI引用
因为现在通过动态查找获取UI引用,无需在Inspector中手动赋值,避免混淆。
内容的提问来源于stack exchange,提问作者lxjx
相关产品推荐
相关产品推荐

