Unity中如何实现Navmesh Agent追踪最近玩家及多玩家适配
原代码存在两个核心问题:一是GameObject.FindWithTag("Player")仅会返回第一个匹配标签的玩家对象,无法适配多玩家场景;二是每帧调用Find方法会额外消耗性能。以下是针对两个问题的具体解决方案:
一、实现追踪最近玩家的逻辑
- 维护当前活跃玩家的列表,避免每帧重复查找玩家对象
- 遍历玩家列表,计算每个玩家与敌人的距离,筛选出距离最近的目标
- 将最近玩家的位置设置为NavMesh Agent的导航目标
二、适配多玩家的完整追踪逻辑
除了筛选最近玩家,还需要处理目标玩家离开场景(被销毁/切换场景)的情况:
- 每帧检查当前追踪目标是否有效,若无效则重新选择最近玩家
- 通过手动调用或事件监听的方式,实时更新活跃玩家列表
修改后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class EnemyFollow : MonoBehaviour { private NavMeshAgent navMeshAgent; // 存储当前活跃的玩家对象 private List<Transform> playerTransforms = new List<Transform>(); // 当前追踪的目标玩家 private Transform currentTarget; private void Awake() { navMeshAgent = GetComponent<NavMeshAgent>(); // 初始化获取所有玩家 UpdatePlayerList(); } private void Update() { if (playerTransforms.Count == 0) return; // 如果当前目标为空或者已被销毁,重新选择最近玩家 if (currentTarget == null) { currentTarget = FindClosestPlayer(); } // 更新导航目标 navMeshAgent.destination = currentTarget.position; } // 更新玩家列表,可在玩家加入/离开时调用 public void UpdatePlayerList() { playerTransforms.Clear(); GameObject[] players = GameObject.FindGameObjectsWithTag("Player"); foreach (GameObject player in players) { playerTransforms.Add(player.transform); } } // 寻找距离最近的玩家 private Transform FindClosestPlayer() { Transform closestPlayer = null; float closestDistance = Mathf.Infinity; Vector3 enemyPosition = transform.position; foreach (Transform player in playerTransforms) { if (player == null) continue; float distance = Vector3.Distance(enemyPosition, player.position); if (distance < closestDistance) { closestDistance = distance; closestPlayer = player; } } return closestPlayer; } // 可选:监听玩家销毁事件,实时更新列表 private void OnEnable() { // 假设玩家对象销毁时会触发自定义事件,可根据游戏逻辑调整 // Player.OnPlayerDestroyed += UpdatePlayerList; } private void OnDisable() { // Player.OnPlayerDestroyed -= UpdatePlayerList; } }
代码关键点说明
- 用
List<Transform>缓存活跃玩家,避免每帧调用FindGameObjectsWithTag带来的性能损耗 FindClosestPlayer方法通过遍历计算距离,精准筛选出最近的玩家目标- 每帧校验当前目标的有效性,确保目标玩家离开后能自动切换追踪对象
- 提供
UpdatePlayerList方法,可结合玩家加入/离开的游戏逻辑手动调用,或通过事件监听实现自动更新
内容的提问来源于stack exchange,提问作者BlastHardCheese
相关产品推荐
相关产品推荐

