Unity3D中查找距离目标最近的路径点 类Hitman Go游戏开发需求
实现逻辑
因为所有相邻路径点距离相等,直接用广度优先搜索(BFS)计算最短路径即可,BFS天然适配无权图的最短路径查找,也兼容3D空间的坐标计算。
具体步骤:
- 给每个路径点绑定独立ID和连通关系表,记录该点可直接到达的其他路径点
- 新增状态标记区分敌人的巡逻状态、警戒移动状态
- 触发警戒时,以敌人当前所在路径点为起点,警戒目标点为终点运行BFS得到最短路径队列
- 按路径队列逐点移动,到达目标点后可按需添加停留、返回原巡逻路线等逻辑
适配修改后的代码
首先给每个路径点挂载独立的路径点属性脚本:
// 挂在场景中每一个路径点对象上 public class Waypoint : MonoBehaviour { // 全局唯一的路径点ID public int waypointId; // 该路径点直接连通的其他路径点 public List<Waypoint> connectedWaypoints; }
修改原有的WaypointController脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; public class WaypointController : MonoBehaviour { // 原巡逻路径点列表 public List<Transform> patrolWaypoints = new List<Transform>(); private Transform targetWaypoint; private int patrolTargetIndex = 0; private float minDistance = 0.1f; private int lastPatrolIndex; public bool reversePatrolPath; public iTween.EaseType easeType = iTween.EaseType.easeInOutExpo; public float moveSpeed = 1.5f; public float rotateTime = 0.5f; public float iTweenDelay = 0f; // 警戒状态相关参数 private bool isInAlert = false; private List<Transform> alertMovePath = new List<Transform>(); private int alertPathIndex = 0; // 全局路径点字典,游戏初始化时把所有场景路径点注册到此处 public static Dictionary<int, Waypoint> AllWaypoints = new Dictionary<int, Waypoint>(); void Start() { lastPatrolIndex = patrolWaypoints.Count - 1; targetWaypoint = patrolWaypoints[patrolTargetIndex]; } public void EnemyTurn() { float distanceToTarget = Vector3.Distance(transform.position, targetWaypoint.position); CheckDistanceToWaypoint(distanceToTarget); iTween.MoveTo(gameObject, iTween.Hash( "position", targetWaypoint.position, "delay", iTweenDelay, "easetype", easeType, "speed", moveSpeed )); } void CheckDistanceToWaypoint(float currentDistance) { if (currentDistance <= minDistance) { if (isInAlert) { alertPathIndex++; UpdateAlertTarget(); } else { patrolTargetIndex++; UpdatePatrolTarget(); } } } // 原巡逻目标更新逻辑 void UpdatePatrolTarget() { if (patrolTargetIndex > lastPatrolIndex) { if (reversePatrolPath) { patrolWaypoints.Reverse(); } patrolTargetIndex = 1; } targetWaypoint = patrolWaypoints[patrolTargetIndex]; } // 触发警戒时调用该方法,传入目标路径点的ID public void TriggerAlert(int targetWaypointId) { isInAlert = true; alertPathIndex = 0; Waypoint currentWaypoint = GetCurrentStayWaypoint(); if (!AllWaypoints.ContainsKey(targetWaypointId) || currentWaypoint == null) { return; } Waypoint alertTarget = AllWaypoints[targetWaypointId]; // BFS计算最短移动路径 alertMovePath = FindShortestPath(currentWaypoint, alertTarget); UpdateAlertTarget(); } // 警戒状态目标更新逻辑 void UpdateAlertTarget() { if (alertPathIndex >= alertMovePath.Count) { // 到达警戒目标点后,此处可自定义后续逻辑,示例为返回巡逻状态 isInAlert = false; patrolTargetIndex = GetNearestPatrolWaypointIndex(); UpdatePatrolTarget(); return; } targetWaypoint = alertMovePath[alertPathIndex]; } // BFS查找最短路径 List<Transform> FindShortestPath(Waypoint startPoint, Waypoint endPoint) { Dictionary<Waypoint, Waypoint> parentMap = new Dictionary<Waypoint, Waypoint>(); Queue<Waypoint> searchQueue = new Queue<Waypoint>(); HashSet<Waypoint> visitedPoints = new HashSet<Waypoint>(); searchQueue.Enqueue(startPoint); visitedPoints.Add(startPoint); while (searchQueue.Count > 0) { Waypoint current = searchQueue.Dequeue(); if (current == endPoint) { break; } foreach (Waypoint neighbor in current.connectedWaypoints) { if (!visitedPoints.Contains(neighbor)) { visitedPoints.Add(neighbor); parentMap[neighbor] = current; searchQueue.Enqueue(neighbor); } } } // 回溯生成路径 List<Transform> resultPath = new List<Transform>(); Waypoint temp = endPoint; while (temp != startPoint) { resultPath.Add(temp.transform); if (!parentMap.ContainsKey(temp)) { break; } temp = parentMap[temp]; } resultPath.Reverse(); return resultPath; } // 获取当前所在的路径点 Waypoint GetCurrentStayWaypoint() { foreach (var wp in AllWaypoints.Values) { if (Vector3.Distance(transform.position, wp.transform.position) < minDistance) { return wp; } } return null; } // 警戒结束后找到最近的巡逻路径点继续巡逻 int GetNearestPatrolWaypointIndex() { int nearestIndex = 0; float minDist = float.MaxValue; for (int i = 0; i < patrolWaypoints.Count; i++) { float dist = Vector3.Distance(transform.position, patrolWaypoints[i].position); if (dist < minDist) { minDist = dist; nearestIndex = i; } } return nearestIndex; } }
使用说明
- 场景中所有路径点都挂载
Waypoint脚本,设置唯一ID,手动选择该点连通的其他路径点 - 游戏初始化阶段,把所有路径点按ID为键,存入
WaypointController.AllWaypoints全局字典 - 投掷石块触发警戒时,调用对应敌人身上
WaypointController的TriggerAlert方法,传入目标路径点的ID即可
内容的提问来源于stack exchange,提问作者Nastary
相关产品推荐
相关产品推荐

