You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:07:24