Unity技术问询:不切换场景实现类Rogue Legacy式房间敌人重置及Cinemachine锁定
实现无场景切换的房间式敌人状态管理 + Cinemachine房间锁定方案
嘿,我之前做过类似的类《Rogue Legacy》项目,完全明白你不想用场景切换来避免内存问题的需求,下面给你拆解两个核心需求的实现思路:
一、房间敌人状态重置与隔离的实现
核心思路是给每个房间做边界标记,通过玩家的房间进出事件来控制敌人的状态,全程不需要切换场景:
房间边界触发器设置
- 给每个房间的根节点添加一个
BoxCollider2D(或PolygonCollider2D),勾选Is Trigger,调整大小覆盖整个房间范围 - 给这个触发器挂载
RoomManager脚本,用来标记房间ID,同时存储房间内所有敌人的引用
- 给每个房间的根节点添加一个
敌人状态控制逻辑
- 给每个敌人添加
EnemyController脚本,包含EnterActiveState()(激活巡逻/攻击行为)和EnterIdleResetState()(回到 idle 并重置位置、血量等状态)方法 - 在
RoomManager中,通过OnTriggerEnter2D和OnTriggerExit2D检测玩家的进出:- 玩家进入房间:遍历房间内所有敌人,调用
EnterActiveState(),激活敌人的AI和动画 - 玩家离开房间:遍历房间内所有敌人,调用
EnterIdleResetState(),让敌人回到初始位置,切换到 idle 状态,同时重置血量、仇恨等状态
- 玩家进入房间:遍历房间内所有敌人,调用
- 给每个敌人添加
代码示例片段
// RoomManager.cs public class RoomManager : MonoBehaviour { [SerializeField] private List<EnemyController> roomEnemies; private PlayerController currentPlayer; private CinemachineConfiner cameraConfiner; private void Awake() { cameraConfiner = FindObjectOfType<CinemachineConfiner>(); } private void OnTriggerEnter2D(Collider2D other) { if (other.TryGetComponent(out PlayerController player)) { currentPlayer = player; ActivateRoomEnemies(); // 同步切换相机边界(后面会讲) UpdateCameraBounds(); } } private void OnTriggerExit2D(Collider2D other) { if (other.TryGetComponent(out PlayerController player) && player == currentPlayer) { DeactivateAndResetEnemies(); currentPlayer = null; } } private void ActivateRoomEnemies() { foreach (var enemy in roomEnemies) { enemy.EnterActiveState(); } } private void DeactivateAndResetEnemies() { foreach (var enemy in roomEnemies) { enemy.EnterIdleResetState(); } } } // EnemyController.cs public class EnemyController : MonoBehaviour { private Vector3 initialPosition; private Animator anim; private EnemyAI enemyAI; private HealthSystem healthSystem; private void Awake() { initialPosition = transform.position; anim = GetComponent<Animator>(); enemyAI = GetComponent<EnemyAI>(); healthSystem = GetComponent<HealthSystem>(); } public void EnterActiveState() { enemyAI.enabled = true; anim.SetBool("IsActive", true); // 启用敌人碰撞体(如果之前禁用了) GetComponent<Collider2D>().enabled = true; } public void EnterIdleResetState() { enemyAI.enabled = false; transform.position = initialPosition; anim.SetBool("IsActive", false); // 重置血量、清除仇恨 healthSystem.ResetHealth(); enemyAI.ClearAggro(); // 可选:禁用非必要碰撞体节省性能 GetComponent<Collider2D>().enabled = false; } }
二、Cinemachine锁定当前房间的方法
要让相机只在当前房间内移动,核心是动态切换Cinemachine的边界限制:
给每个房间添加相机边界碰撞体
- 给每个房间创建一个
PolygonCollider2D(或BoxCollider2D),调整形状贴合房间的可移动区域(避开墙壁、障碍物),不要勾选Is Trigger - 把这个碰撞体作为房间的相机边界,放在
RoomManager的子物体下
- 给每个房间创建一个
动态切换Cinemachine Confiner的边界
- 给你的Cinemachine Virtual Camera添加
CinemachineConfiner组件 - 在
RoomManager的UpdateCameraBounds()方法中,当玩家进入房间时,把Confiner的m_BoundingShape2D设置为当前房间的边界碰撞体,同时强制刷新缓存
- 给你的Cinemachine Virtual Camera添加
补充代码片段(在RoomManager.cs中)
[SerializeField] private PolygonCollider2D roomCameraBounds; private void UpdateCameraBounds() { if (roomCameraBounds != null && cameraConfiner != null) { cameraConfiner.m_BoundingShape2D = roomCameraBounds; // 强制刷新边界缓存,避免相机卡顿 cameraConfiner.InvalidatePathCache(); } }
额外优化建议
- 如果是程序化生成房间,记得在生成房间时自动创建边界触发器和相机边界碰撞体,并把生成的敌人自动添加到
roomEnemies列表中 - 可以给离开房间的敌人添加“休眠”逻辑,比如禁用刚体、动画组件(除了idle动画),进一步降低内存和性能消耗
内容的提问来源于stack exchange,提问作者TheYargonaut
相关产品推荐
相关产品推荐

