Unity中设置DontDestroyOnLoad的玩家死亡后触发场景无限重载Bug
问题原因分析
玩家死亡后场景无限重复加载的核心问题有以下几点:
Update方法中每帧都会检查currentHealth <=0 && canDie,死亡协程启动后没有立即禁用canDie或标记死亡状态,导致每帧都重复触发死亡逻辑- 死亡后直接加载场景,但没有重置玩家生命值,场景加载完成后玩家生命值仍为0,再次触发死亡检查
- 重生逻辑没有正确衔接,既没有调用
GameManager的重生方法重置玩家位置,也没有在场景加载完成后恢复玩家状态 GameManager仅在初始启动时查找RespawnPoint,场景切换后无法获取新场景中的重生点
修复方案
1. 修正玩家死亡逻辑,防止重复触发
在死亡协程启动前立即禁用canDie,避免Update持续触发;场景加载完成后通过GameManager处理重生,而不是直接加载场景后无操作。
2. 调整场景加载后的重生流程
使用SceneManager.sceneLoaded监听场景加载完成事件,在场景加载后调用GameManager的重生方法,重置玩家位置和生命值。
3. 修复GameManager的重生点获取逻辑
在场景加载完成后重新查找当前场景的RespawnPoint,而不是仅在初始Awake中查找。
4. 完善重生状态重置
确保重生时不仅恢复生命值,还要重新启用canDie并清除死亡标记。
修改后的代码
玩家生命值与重生代码(BasicPlayerMovement)
public int maxHealth = 5; public float timeInvincible = 2.0f; public int health { get { return currentHealth; } } int currentHealth; bool isInvincible; float invincibleTimer; public int respawn; public bool canDie = true; private bool isDead = false; UIManager uiManager; public static BasicPlayerMovement Instance; private void Awake() { // 防止玩家对象重复创建 if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); // 监听场景加载完成事件 SceneManager.sceneLoaded += OnSceneLoaded; } void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 场景加载完成后,如果处于死亡状态,触发重生 if(isDead) { GameManager.instance.RespawnPlayer(); } } // Start is called before the first frame update void Start() { currentHealth = maxHealth; } void Update() { if (isInvincible) { invincibleTimer -= Time.deltaTime; if (invincibleTimer < 0) isInvincible = false; } if ((currentHealth <= 0) && (canDie == true)) { StartCoroutine(PlayerDeath()); } } public void ChangeHealth(int amount) { if (amount < 0) { if (isInvincible) return; isInvincible = true; invincibleTimer = timeInvincible; } currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth); Debug.Log(currentHealth + "/" + maxHealth); } private IEnumerator PlayerDeath() { isDead = true; canDie = false; // 禁用死亡触发,防止重复调用 Time.timeScale = 1f; // 加载重生场景 yield return SceneManager.LoadSceneAsync(respawn); // 场景加载完成后OnSceneLoaded会触发重生 } public void Respawned() { isDead = false; canDie = true; // 重新启用死亡触发 currentHealth = maxHealth; }
游戏管理器代码(GameManager)
public class GameManager : MonoBehaviour { public string transitionedFromScene; public Vector2 respawnPoint; public Vector2 platformingRespawnPoint; [SerializeField] RespawnPoint rP; public static GameManager instance { get; private set; } private void Awake() { if(instance != null && instance != this) { Destroy(gameObject); } else { instance = this; } DontDestroyOnLoad(gameObject); // 监听场景加载完成事件,重新获取当前场景的重生点 SceneManager.sceneLoaded += OnSceneLoaded; } void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 场景切换后重新查找当前场景的重生点 rP = FindObjectOfType<RespawnPoint>(); } public void RespawnPlayer() { if(rP != null && rP.interacted) { respawnPoint = rP.transform.position; } else { respawnPoint = platformingRespawnPoint; } BasicPlayerMovement.Instance.transform.position = respawnPoint; BasicPlayerMovement.Instance.Respawned(); } }
重生点代码(RespawnPoint)
public class RespawnPoint : MonoBehaviour { public bool interacted; private void OnTriggerStay2D(Collider2D collision) { if(collision.CompareTag("Player") && Input.GetKeyDown(KeyCode.Z)) { interacted = true; // 可添加交互反馈,比如音效或提示 } } }
额外说明
- 使用
LoadSceneAsync代替同步加载,避免场景加载时卡顿,同时确保协程等待加载完成后再处理后续逻辑 - 通过
SceneManager.sceneLoaded统一处理场景切换后的重生和重生点查找逻辑,保证状态同步 - 死亡时立即禁用
canDie,从根源上避免Update循环触发死亡协程
内容的提问来源于stack exchange,提问作者Knackered7
相关产品推荐
相关产品推荐

