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

Unity跨场景实现篝火休息时指定类型敌人重生问题

解决类魂游戏跨场景敌人重生问题

你的核心问题在于:当前EnemyManager依赖场景内组件响应篝火休息事件,未加载场景的组件无法接收事件;同时重生逻辑绑定在单个敌人实例上,跨场景时无法触发未加载场景的敌人状态更新。

下面是具体的解决方案:

方案一:全局敌人状态管理器(单例模式)

创建一个全局单例的GlobalEnemyRespawnManager,统一管理所有敌人的重生状态,不管场景是否加载。

1. 全局管理器代码

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using ES3;

public class GlobalEnemyRespawnManager : MonoBehaviour
{
    public static GlobalEnemyRespawnManager Instance;

    // 存储所有敌人的重生状态:key为唯一敌人ID,value为是否可重生
    private Dictionary<string, bool> enemyRespawnStates = new Dictionary<string, bool>();

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
        
        // 从ES3加载已存储的敌人状态
        LoadEnemyRespawnStates();
        // 监听场景加载事件,处理新场景敌人的状态
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    private void LoadEnemyRespawnStates()
    {
        if (ES3.KeyExists("EnemyRespawnStates"))
        {
            enemyRespawnStates = ES3.Load<Dictionary<string, bool>>("EnemyRespawnStates");
        }
    }

    // 保存单个敌人的重生状态
    public void SaveEnemyRespawnState(string enemyId, bool canRespawn)
    {
        enemyRespawnStates[enemyId] = canRespawn;
        ES3.Save("EnemyRespawnStates", enemyRespawnStates);
    }

    // 获取单个敌人的重生状态
    public bool GetEnemyRespawnState(string enemyId)
    {
        return enemyRespawnStates.TryGetValue(enemyId, out var state) ? state : true;
    }

    // 篝火休息时触发全局重生逻辑
    public void TriggerGlobalRespawn()
    {
        // 遍历所有需要随休息重生的敌人,更新状态
        foreach (var enemyId in enemyRespawnStates.Keys)
        {
            if (GetEnemyDeathType(enemyId) == EnemyManager.DeathType.respawnOnRest)
            {
                SaveEnemyRespawnState(enemyId, true);
            }
        }

        // 通知当前已加载场景的敌人执行重生
        foreach (var manager in FindObjectsOfType<EnemyManager>())
        {
            manager.RespawnIfNeeded();
        }
    }

    // 获取敌人的死亡类型(从ES3读取)
    private EnemyManager.DeathType GetEnemyDeathType(string enemyId)
    {
        return ES3.KeyExists($"{enemyId}_DeathType") 
            ? ES3.Load<EnemyManager.DeathType>($"{enemyId}_DeathType") 
            : EnemyManager.DeathType.respawnOnRest;
    }

    // 场景加载完成后,自动处理该场景内的敌人状态
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        foreach (var manager in FindObjectsOfType<EnemyManager>())
        {
            bool canRespawn = GetEnemyRespawnState(manager.EnemyId);
            manager.SetEnemyActive(canRespawn);
        }
    }

    private void OnDisable()
    {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
}

2. 修改原EnemyManager脚本

去掉本地状态管理,改为依赖全局管理器:

using UnityEngine;

public class EnemyManager : MonoBehaviour
{
    public GameObject enemyCore;
    private Core core;

    public enum DeathType { respawnOnEnter, respawnOnRest, neverRespawn}
    [SerializeField] private DeathType deathType;

    private Death Death => death ??= core.GetCoreComponent(ref death);
    private Death death;

    // 公开敌人唯一ID,供全局管理器调用
    public string EnemyId { get; private set; }

    private void Awake()
    {
        core = enemyCore.GetComponent<Core>();
        // 生成唯一ID:场景名+父物体名,避免跨场景同名冲突
        EnemyId = $"{gameObject.scene.name}_{core.transform.parent.name}";
        // 存储敌人的死亡类型到ES3
        ES3.Save($"{EnemyId}_DeathType", deathType);
    }

    private void Start()
    {
        // 从全局管理器获取初始状态,设置敌人激活状态
        bool canRespawn = GlobalEnemyRespawnManager.Instance.GetEnemyRespawnState(EnemyId);
        SetEnemyActive(canRespawn);
    }

    private void Update()
    {
        if (Death.JustDied)
        {
            bool newRespawnState = deathType switch
            {
                DeathType.respawnOnEnter => true,
                _ => false
            };

            // 通知全局管理器更新状态
            GlobalEnemyRespawnManager.Instance.SaveEnemyRespawnState(EnemyId, newRespawnState);
            Death.JustDied = false;
        }
    }

    // 供全局管理器调用的重生方法
    public void RespawnIfNeeded()
    {
        if (deathType == DeathType.respawnOnRest)
        {
            SetEnemyActive(true);
            GlobalEnemyRespawnManager.Instance.SaveEnemyRespawnState(EnemyId, true);
        }
    }

    // 设置敌人激活状态
    public void SetEnemyActive(bool active)
    {
        core.transform.parent.gameObject.SetActive(active);
    }

    private void OnEnable()
    {
        PlayerRestState.RestAction += GlobalEnemyRespawnManager.Instance.TriggerGlobalRespawn;
    }

    private void OnDisable()
    {
        PlayerRestState.RestAction -= GlobalEnemyRespawnManager.Instance.TriggerGlobalRespawn;
    }
}

关键优化说明

  • 全局单例管理:所有敌人的重生状态集中存储,不受场景加载/卸载影响
  • 场景加载自动处理:新场景加载完成后,自动根据全局状态激活/隐藏敌人
  • 唯一ID标识:用「场景名+敌人名称」生成ID,彻底解决跨场景同名敌人的状态冲突
  • 事件驱动:篝火休息事件触发全局重生逻辑,已加载场景的敌人立即重生,未加载场景的敌人在加载时自动恢复

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 17:35:23