Unity场景切换保持GameObject销毁,新游戏时重置的实现方案
解决Unity新游戏重置已销毁对象状态的方案
方案1:为单个对象添加静态重置方法
这个方案适合只有少数几个需要持久化状态的对象,无需修改整体架构,直接在目标脚本中添加静态公共方法来重置状态:
修改乌鸦脚本
public Animator anim; public AudioSource audioSource; public AudioSource Flyingsound; public GameObject Crow; public GameObject trigger; // 保持静态变量私有,避免外部误修改 private static bool m_IsDeleted = false; private static bool n_IsDeleted = false; public void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag("Player")) { anim.SetTrigger("Flying"); audioSource.Play(); GetComponent<BoxCollider2D>().enabled = false; Flyingsound.Play(); StartCoroutine(crow(4)); m_IsDeleted = true; n_IsDeleted = true; } } IEnumerator crow(float waitTime) { yield return new WaitForSeconds(waitTime); Destroy(Crow); Destroy(this); } public void Awake() { if (m_IsDeleted) Destroy(Crow); if(n_IsDeleted) Destroy(this); } // 新增静态重置方法,供主菜单调用 public static void ResetCrowState() { m_IsDeleted = false; n_IsDeleted = false; }
修改主菜单脚本
在「开始新游戏」的PlayGame方法中,加载场景前调用重置方法:
using UnityEngine.SceneManagement; public GameObject gameObject; public void PlayGame() { // 替换CrowScript为你的乌鸦脚本实际类名 CrowScript.ResetCrowState(); SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); gameObject.SetActive(false); PlayerPrefs.DeleteKey("p_x"); PlayerPrefs.DeleteKey("p_y"); PlayerPrefs.DeleteKey("TimeToLoad"); PlayerPrefs.DeleteKey("Saved"); } // 其他方法保持不变 public void QuitGame() { Application.Quit(); } public void ContinueGame() { if(PlayerPrefs.GetInt("LoadSaved") == 1) { SceneManager.LoadScene(PlayerPrefs.GetInt("SavedScene")); gameObject.SetActive(false); } else { return; } }
原理:静态方法属于类本身,无需实例即可调用,既保留了静态变量的场景持久化特性,又能在新游戏时主动重置状态,避免暴露私有静态变量。
方案2:全局状态管理类(适合多对象场景)
如果你的游戏中有大量需要持久化销毁状态的对象,推荐用统一的全局状态管理器,避免每个脚本重复写静态变量和重置方法:
创建全局状态管理类
using System.Collections.Generic; public static class GameStateManager { // 用字典存储每个对象的销毁状态,key为对象唯一标识 private static Dictionary<string, bool> _destroyedObjects = new Dictionary<string, bool>(); // 标记对象为已销毁 public static void MarkObjectDestroyed(string objectKey) { if (_destroyedObjects.ContainsKey(objectKey)) { _destroyedObjects[objectKey] = true; } else { _destroyedObjects.Add(objectKey, true); } } // 检查对象是否已销毁 public static bool IsObjectDestroyed(string objectKey) { return _destroyedObjects.TryGetValue(objectKey, out bool isDestroyed) && isDestroyed; } // 重置所有对象状态(新游戏时调用) public static void ResetAllStates() { _destroyedObjects.Clear(); } }
修改乌鸦脚本
public Animator anim; public AudioSource audioSource; public AudioSource Flyingsound; public GameObject Crow; public GameObject trigger; // 在Inspector中给每个乌鸦设置唯一标识(比如"Crow_Forest_01") public string objectID; public void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag("Player")) { anim.SetTrigger("Flying"); audioSource.Play(); GetComponent<BoxCollider2D>().enabled = false; Flyingsound.Play(); StartCoroutine(crow(4)); // 标记当前乌鸦为已销毁 GameStateManager.MarkObjectDestroyed(objectID); } } IEnumerator crow(float waitTime) { yield return new WaitForSeconds(waitTime); Destroy(Crow); Destroy(this); } public void Awake() { if (GameStateManager.IsObjectDestroyed(objectID)) { Destroy(Crow); Destroy(this); } }
修改主菜单脚本
在PlayGame中调用全局重置方法:
public void PlayGame() { GameStateManager.ResetAllStates(); SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); gameObject.SetActive(false); PlayerPrefs.DeleteKey("p_x"); PlayerPrefs.DeleteKey("p_y"); PlayerPrefs.DeleteKey("TimeToLoad"); PlayerPrefs.DeleteKey("Saved"); }
原理:用一个静态类统一管理所有对象的状态,新游戏时只需清空字典即可重置所有对象,扩展性更强,适合复杂场景。
方案3:使用PlayerPrefs存储状态(支持跨游戏会话保留)
如果需要即使关闭游戏重启,也能保留对象的销毁状态,可以用PlayerPrefs存储状态:
修改乌鸦脚本
public Animator anim; public AudioSource audioSource; public AudioSource Flyingsound; public GameObject Crow; public GameObject trigger; // 每个对象的唯一键 private const string _crowDestroyedKey = "Crow_Main_Destroyed"; public void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag("Player")) { anim.SetTrigger("Flying"); audioSource.Play(); GetComponent<BoxCollider2D>().enabled = false; Flyingsound.Play(); StartCoroutine(crow(4)); // 存储已销毁状态 PlayerPrefs.SetInt(_crowDestroyedKey, 1); PlayerPrefs.Save(); } } IEnumerator crow(float waitTime) { yield return new WaitForSeconds(waitTime); Destroy(Crow); Destroy(this); } public void Awake() { // 读取状态,0为默认值(未销毁) if (PlayerPrefs.GetInt(_crowDestroyedKey, 0) == 1) { Destroy(Crow); Destroy(this); } }
修改主菜单脚本
在PlayGame中删除对应的PlayerPrefs键:
public void PlayGame() { PlayerPrefs.DeleteKey("Crow_Main_Destroyed"); // 其他删除操作... SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1); gameObject.SetActive(false); PlayerPrefs.DeleteKey("p_x"); PlayerPrefs.DeleteKey("p_y"); PlayerPrefs.DeleteKey("TimeToLoad"); PlayerPrefs.DeleteKey("Saved"); }
注意:PlayerPrefs会把数据存在本地文件中,适合需要跨会话保留的状态,若不需要则优先用前两个方案。
内容的提问来源于stack exchange,提问作者DariusnatorX
相关产品推荐
相关产品推荐

