Unity 2D基于标签忽略碰撞及远程单位攻击逻辑异常求助
问题描述
我正在开发一款类似《Age Of War》的2D游戏,包含近战单位与远程单位,所有单位共用同一脚本。我在FixedUpdate函数中实现了远程单位的敌人检测逻辑,代码如下:
private void FixedUpdate() { if (RangeUnit) { RaycastHit2D hit = Physics2D.Raycast(enemyDetecter.transform.position, transform.right, rayDistance); if (hit.collider != null && hit.collider.gameObject != gameObject) { Debug.Log(CC_Name); if (!hit.collider.CompareTag(gameObject.tag)) { //if enemy ShouldMove = false; ShouldAttack = true; Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.green); CC_Name = hit.collider.gameObject.name; } else { //if friend Physics2D.IgnoreCollision(hit.collider, GetComponent<Collider2D>()); Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.magenta); } Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.yellow); } else { //if nothing ShouldAttack = false; ShouldMove = true; Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.red); Debug.Log("Hitted: Nothing"); } } }
场景中放置了3个单位:左侧1个近战单位、1个远程单位,右侧1个敌方近战单位。当前问题:远程单位检测到右侧敌人后停止移动并开始攻击,当友方近战单位击杀敌人后,远程单位仍持续攻击,调试CC_Name显示射线检测到的是友方单位而非敌人。所有单位处于同一Layer但标签不同。
死亡逻辑代码如下:
public void Death() { if (Dead == true) { Destroy(gameObject); } }
补充说明:当敌人与友方单位在远程单位前方交战时,远程单位表现正常;但敌人死亡后,远程单位会持续攻击直到友方单位超出射线检测范围。需求是找到彻底忽略友方碰撞的方法,同时解决攻击逻辑异常问题。
解决方案
1. 射线检测时直接过滤友方单位
当前代码检测到友方后仅忽略碰撞,但仍会进入判断分支导致ShouldAttack未被重置。修改为用Physics2D.RaycastAll获取所有命中对象,遍历筛选第一个敌方单位,跳过友方检测:
private void FixedUpdate() { if (RangeUnit) { RaycastHit2D[] hits = Physics2D.RaycastAll(enemyDetecter.transform.position, transform.right, rayDistance); RaycastHit2D enemyHit = default; // 遍历命中对象,找到第一个敌方单位 foreach (var hit in hits) { if (hit.collider.gameObject != gameObject && !hit.collider.CompareTag(gameObject.tag)) { enemyHit = hit; break; } } if (enemyHit.collider != null) { // 检测到敌人 ShouldMove = false; ShouldAttack = true; Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.green); CC_Name = enemyHit.collider.gameObject.name; } else { // 未检测到敌人 ShouldAttack = false; ShouldMove = true; Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.red); Debug.Log("Hitted: Nothing"); } } }
2. 优化死亡逻辑执行时机
确保敌人死亡时Dead被及时设置,且销毁操作立即执行,避免延迟导致的误检测:
public void Death() { Dead = true; // 可选:通知所有攻击当前单位的远程单位停止攻击 Destroy(gameObject); }
3. 用LayerMask优化射线检测(推荐)
给友方和敌方分配不同Layer,在射线检测时直接过滤友方Layer,从根源避免误判:
- 在Unity编辑器中创建
Friend和EnemyLayer,分别分配给对应单位; - 修改射线检测代码:
// 在Inspector中赋值Enemy层的LayerMask public LayerMask enemyLayer; private void FixedUpdate() { if (RangeUnit) { RaycastHit2D hit = Physics2D.Raycast(enemyDetecter.transform.position, transform.right, rayDistance, enemyLayer); if (hit.collider != null) { ShouldMove = false; ShouldAttack = true; Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.green); CC_Name = hit.collider.gameObject.name; } else { ShouldAttack = false; ShouldMove = true; Debug.DrawRay(enemyDetecter.transform.position, transform.right * rayDistance, Color.red); Debug.Log("Hitted: Nothing"); } } }
4. 修复友方碰撞忽略逻辑
避免在FixedUpdate中重复调用忽略碰撞API,改为在初始化时一次性设置:
private void Start() { if (RangeUnit) { GameObject[] friends = GameObject.FindGameObjectsWithTag(gameObject.tag); foreach (var friend in friends) { if (friend != gameObject) { Physics2D.IgnoreCollision(friend.GetComponent<Collider2D>(), GetComponent<Collider2D>()); } } } }
内容的提问来源于stack exchange,提问作者hany
相关产品推荐
相关产品推荐

