Unity 2D敌人巡逻异常问题:需实现两点巡逻及玩家检测攻击功能
问题修复与功能实现方案
一、先解决巡逻逻辑错误
你的代码存在两个核心问题,导致敌人单向跑动无法折返:
- 错误的位置赋值:
Vector2 point = currentPoint.position = transform.position;这行代码把目标点的位置直接改成了敌人当前位置,导致目标点永远跟着敌人,完全无法触发切换逻辑。应改为获取目标点位置,而非赋值。 - 过大的距离阈值:
50f的距离判断远超常规2D游戏的单位尺度,敌人还没接近目标点就会切换方向,甚至直接跑出地图。改成0.5f这类小数值更合理。
修复后同时新增玩家检测与攻击功能的完整代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyPatrol : MonoBehaviour { public GameObject pointA; public GameObject pointB; private Rigidbody2D rb; private Animator anim; private Transform currentPoint; public float speed; // 玩家检测与攻击相关变量 public Transform player; public float detectRange; public float attackRange; private bool isChasing; private float attackCooldown = 1f; private float lastAttackTime; void Start() { rb = GetComponent<Rigidbody2D>(); anim = GetComponent<Animator>(); currentPoint = pointB.transform; anim.SetBool("IsRunning", true); isChasing = false; lastAttackTime = -attackCooldown; } void Update() { // 优先执行玩家检测逻辑 CheckPlayerStatus(); if (!isChasing) { PatrolBetweenPoints(); } else { ChaseAndAttackPlayer(); } } // 两点间巡逻逻辑 void PatrolBetweenPoints() { Vector2 targetPos = currentPoint.position; // 朝目标点移动并翻转朝向 if (currentPoint == pointB.transform) { rb.velocity = new Vector2(speed, rb.velocity.y); transform.localScale = new Vector3(1, 1, 1); } else { rb.velocity = new Vector2(-speed, rb.velocity.y); transform.localScale = new Vector3(-1, 1, 1); } // 到达目标点后切换巡逻方向 if (Vector2.Distance(transform.position, targetPos) < 0.5f) { currentPoint = currentPoint == pointB.transform ? pointA.transform : pointB.transform; } } // 玩家状态检测 void CheckPlayerStatus() { if (player == null) return; float distanceToPlayer = Vector2.Distance(transform.position, player.position); // 进入检测范围开始追击 if (distanceToPlayer <= detectRange && distanceToPlayer > attackRange) { isChasing = true; anim.SetBool("IsRunning", true); } // 超出检测范围回到巡逻状态 else if (distanceToPlayer > detectRange) { isChasing = false; anim.SetBool("IsRunning", true); } } // 追击与攻击逻辑 void ChaseAndAttackPlayer() { if (player == null) return; float distanceToPlayer = Vector2.Distance(transform.position, player.position); // 朝向玩家移动 if (player.position.x > transform.position.x) { transform.localScale = new Vector3(1, 1, 1); rb.velocity = new Vector2(speed, rb.velocity.y); } else { transform.localScale = new Vector3(-1, 1, 1); rb.velocity = new Vector2(-speed, rb.velocity.y); } // 进入攻击范围且冷却完成时触发攻击 if (distanceToPlayer <= attackRange && Time.time >= lastAttackTime + attackCooldown) { rb.velocity = Vector2.zero; anim.SetBool("IsRunning", false); anim.SetTrigger("Attack"); lastAttackTime = Time.time; } } // 调试用:绘制检测范围 void OnDrawGizmosSelected() { Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(transform.position, detectRange); Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); } }
二、使用步骤
- 巡逻点设置:在场景中创建两个空物体作为
pointA和pointB,拖入脚本对应字段,调整位置为巡逻路径的两端。 - 玩家赋值:将玩家对象拖入脚本的
player字段。 - 参数调整:根据游戏需求修改
speed(移动速度)、detectRange(玩家检测范围)、attackRange(攻击触发范围)、attackCooldown(攻击冷却时间)的数值。 - 动画适配:确保Animator控制器中有
IsRunning布尔参数和Attack触发参数,对应跑动和攻击动画。
三、优化建议
- 视野限制:添加角度判断,只有玩家在敌人正面视野范围内才触发追击,提升逻辑合理性。
- 障碍物规避:若巡逻路径有障碍物,可使用射线检测或NavMesh2D实现绕路功能。
- 状态重置:玩家死亡或脱离范围后,敌人延迟几秒再回到巡逻状态,避免切换过于突兀。
内容的提问来源于stack exchange,提问作者Gabriel Asis
相关产品推荐
相关产品推荐

