Unity 2D沙盒游戏中销毁与主体断开部件的实现方案咨询
解决方案:基于连通性的战舰部件存活逻辑
核心思路:你的需求本质是判断灰色部件是否通过连通路径关联到至少一个存活的绿色核心部件,无关联则销毁。以下提供两种适配Unity场景的实现方案:
方案一:利用现有父子层级简化检测
既然你已经通过CollisionStay将相连部件设为主体子物体,可基于父子链+标签快速判断:
- 给绿色核心部件标记
CorePart标签,灰色部件标记AttachmentPart标签 - 在每个灰色部件的脚本中添加如下逻辑:
void Update() { // 递归检查自身或父物体链中是否存在存活的绿色核心 if (!HasAliveCoreInHierarchy(transform)) { Destroy(gameObject); } } bool HasAliveCoreInHierarchy(Transform current) { if (current == null) return false; // 检查当前物体是否为存活的绿色核心 if (current.CompareTag("CorePart") && current.gameObject.activeSelf) { return true; } // 递归向上检查父物体 return HasAliveCoreInHierarchy(current.parent); }
优化点:避免每帧递归,可在绿色核心销毁时触发全局检测,或给灰色部件添加OnTriggerExit(配合碰撞体)触发检查,降低性能消耗。
方案二:洪水填充(Flood Fill)实现复杂连通检测
洪水填充适用于非严格父子关系的连通场景(比如仅通过碰撞体接触的部件),以下是针对你的场景的完整示例:
1. 前置准备
- 所有战舰部件添加
Collider2D(可设为IsTrigger或保持碰撞体,匹配现有逻辑) - 绿色核心用
CorePart标签,灰色部件用AttachmentPart标签 - 创建全局管理脚本
ShipManager,挂载在DontDestroyOnLoad的物体上
2. 洪水填充算法实现
using System.Collections.Generic; using UnityEngine; public class ShipManager : MonoBehaviour { private List<GameObject> _allAttachmentParts = new List<GameObject>(); void Start() { // 初始化收集所有灰色部件 _allAttachmentParts.AddRange(GameObject.FindGameObjectsWithTag("AttachmentPart")); } // 绿色核心销毁时调用此方法 public void OnCorePartDestroyed() { List<GameObject> aliveCores = new List<GameObject>(GameObject.FindGameObjectsWithTag("CorePart")); // 无存活核心则直接销毁所有灰色部件 if (aliveCores.Count == 0) { foreach (var part in _allAttachmentParts) { if (part != null) Destroy(part); } _allAttachmentParts.Clear(); return; } // 标记所有连通到绿色核心的部件 HashSet<GameObject> connectedParts = new HashSet<GameObject>(); foreach (var core in aliveCores) { FloodFill(core, connectedParts); } // 销毁未连通的灰色部件 List<GameObject> toDestroy = new List<GameObject>(); foreach (var part in _allAttachmentParts) { if (part != null && !connectedParts.Contains(part)) { toDestroy.Add(part); } } foreach (var part in toDestroy) { Destroy(part); _allAttachmentParts.Remove(part); } } void FloodFill(GameObject startPart, HashSet<GameObject> visited) { if (visited.Contains(startPart)) return; visited.Add(startPart); // 获取当前部件接触的所有战舰部件 Collider2D[] adjacentColliders = Physics2D.OverlapCollider( startPart.GetComponent<Collider2D>(), LayerMask.GetMask("ShipParts") ); foreach (var collider in adjacentColliders) { GameObject neighbor = collider.gameObject; // 仅处理绿色核心或灰色部件 if (neighbor.CompareTag("CorePart") || neighbor.CompareTag("AttachmentPart")) { FloodFill(neighbor, visited); } } } }
3. 集成到现有流程
- 在绿色核心部件的脚本中添加销毁回调:
void OnDestroy() { ShipManager shipManager = FindObjectOfType<ShipManager>(); if (shipManager != null) { shipManager.OnCorePartDestroyed(); } }
- 将所有战舰部件归类到
ShipParts层,确保OverlapCollider能准确检测相邻部件。
性能优化建议:
- 避免每帧执行检测,仅在绿色核心销毁、部件连接状态变化时触发
- 使用
HashSet存储已访问部件,避免重复检测 - 大量部件场景下,可将检测逻辑放在
Coroutine中分步执行,避免卡顿
内容的提问来源于stack exchange,提问作者boiler room
相关产品推荐
相关产品推荐

