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

Unity如何实现按R键/按钮重启场景(无需SceneManager)

场景重启功能实现方案

你的旧代码单例逻辑和事件写法存在小问题,下面分两种实现路径提供可直接运行的参考,两种方案都原生支持「按R键重启」「点击UI按钮重启」两个触发条件。


核心实现逻辑

  • 所有触发入口统一调用同一个重置方法,不要分开写两套冗余逻辑
  • 单例管理器必须做重复实例校验,避免场景重载后出现多个管理器实例报错
  • 两种实现可选:用Unity原生SceneManager重载(新手推荐,出错概率极低)、自定义状态回滚(完全不调用SceneManager)

方案1:使用SceneManager实现(新手首选)

这个方案直接重载当前场景,Unity会自动销毁所有场景内对象、重新加载场景配置,不需要手动记录每个对象的初始状态,是最省事的官方标准实现。
修正后的ResetManager代码如下,把脚本挂到场景任意空对象上即可:

using UnityEngine;
using UnityEngine.SceneManagement;

public class ResetManager : MonoBehaviour
{
    public static ResetManager Instance { get; private set; }
    private int _currentSceneIndex;

    private void Awake()
    {
        // 单例校验:如果已经存在管理器实例,销毁当前重复的对象
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        _currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
    }

    private void Update()
    {
        // 检测键盘R键按下
        if (Input.GetKeyDown(KeyCode.R))
        {
            DoReset();
        }
    }

    // 公共重置方法,UI按钮的OnClick事件直接绑定这个方法即可
    public void DoReset()
    {
        SceneManager.LoadScene(_currentSceneIndex);
    }
}

UI按钮绑定操作:选中画布上的重启按钮,在Inspector面板找到Button组件的OnClick事件列表,点+号,把挂了ResetManager脚本的对象拖到对象选择槽,下拉菜单选ResetManager -> DoReset()就完成绑定。


方案2:不借助SceneManager的自定义重置

如果不想重载场景,可以在场景启动时记录所有需要重置的对象的初始状态,触发重置时直接恢复状态即可,适合对象量少的小型学习项目。
参考实现代码:

using UnityEngine;
using System.Collections.Generic;

public class ResetManager : MonoBehaviour
{
    public static ResetManager Instance { get; private set; }
    // 存储所有场景内置对象的初始状态
    private List<ResettableObject> _initialStates = new List<ResettableObject>();
    // 存储所有运行时动态生成的对象,重置时直接销毁
    private List<GameObject> _runtimeSpawnedObjects = new List<GameObject>();

    // 可重置对象的状态结构体,有自定义属性(比如血量、分数)直接在这里加字段存初始值即可
    private struct ResettableObject
    {
        public Transform targetTrans;
        public Vector3 initPos;
        public Quaternion initRot;
    }

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        // 启动时自动记录所有带Resettable标签的场景内置对象初始状态
        foreach (var obj in FindObjectsOfType<GameObject>())
        {
            if (obj.CompareTag("Resettable"))
            {
                _initialStates.Add(new ResettableObject
                {
                    targetTrans = obj.transform,
                    initPos = obj.transform.position,
                    initRot = obj.transform.rotation
                });
            }
        }
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            DoReset();
        }
    }

    // 供外部动态生成对象时调用,把生成的对象注册到重置列表
    public void RegisterSpawnedObject(GameObject obj)
    {
        _runtimeSpawnedObjects.Add(obj);
    }

    public void DoReset()
    {
        // 销毁所有运行时生成的敌人、道具等对象
        foreach (var obj in _runtimeSpawnedObjects)
        {
            if (obj != null) Destroy(obj);
        }
        _runtimeSpawnedObjects.Clear();

        // 恢复所有场景内置对象的初始状态
        foreach (var state in _initialStates)
        {
            state.targetTrans.position = state.initPos;
            state.targetTrans.rotation = state.initRot;
            // 自定义属性重置逻辑写在这里,比如玩家血量回满、分数清零
        }
    }
}

使用这个方案时,只需要给所有场景初始就存在、需要重置的对象打上Resettable标签,运行时动态生成的对象在生成时调用ResetManager.Instance.RegisterSpawnedObject(gameObject)注册即可,UI按钮绑定方式和方案1完全一致。


注意:你原代码里的事件写法public event System.Action ResetEvent = new delegate {};存在内存泄漏风险,建议改成public event System.Action ResetEvent;,触发时用ResetEvent?.Invoke();调用即可避免空引用报错。

内容的提问来源于stack exchange,提问作者rayman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:21:21