unity3d 如何让Unity中的Navmesh Agent跟随最近的玩家?

but5z9lq  于 2023-04-12  发布在  其他
关注(0)|答案(2)|浏览(266)

我正在做一个多人游戏,一个导航网格代理跟随玩家,如果有多个,它只跟随一个,直到它不再在场景中。我如何让导航网格跟随两个?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class EnemyFollow : MonoBehaviour
> {
> \[SerializeField\] private Transform movePositionTransform;

private NavMeshAgent navMeshAgent;

Start is called before the first frame update
private void Awake()
>     {
navMeshAgent = GetComponent<NavMeshAgent>();
>     }

Update is called once per frame
private void Update()
>     {
navMeshAgent.destination = GameObject.FindWithTag("Player").transform.position;
>     }

> }
9ceoxa92

9ceoxa921#

如果你想让智能体跟随最近的玩家,检查玩家和智能体之间的距离,然后选择最近的一个作为目的地。我不会使用FindWithTag("Player")方法,因为它真的很重(它每一步都迭代场景中的所有对象)。相反,我将创建一个球员列表并将其填充到Start()上,然后为agent创建另一个方法,检查哪个玩家是最接近的,并将其设置为目的地。下面是我的意思的伪代码:

List<Player> players;

void Start(){
    players = FindObjectsWithTag("Player")
}

void SetAgentDestination(){
    float min = 0;
    Player closest = null;
    foreach (Player p in players){
        if (<calculate distance> < min){
            min = <calculated distance>
            closest = p;
        }
    }
    agent.SetDestination(closest);
}

就像这样

rjee0c15

rjee0c152#

FindGameObjectsWithTag()方法搜索场景中的所有对象(一个接一个),以检查它是否符合要求(例如:如果它有标签“播放器”)
Update()上调用FindGameObjectsWithTag()会使它成为一个性能很差的代码。每帧调用一次更新。你在所有可能的时间循环/搜索所有对象。

以下是你可以做的:

你可以在Awake()Start()上使用FindGameObjectsWithTag(),并将其缓存/保存到列表或数组中。这样你只需要搜索一次对象。
检查哪个玩家是最近的一个(Vector3.Distance),并将navmesh代理移动到它。
它应该看起来像这样:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class EnemyFollow : MonoBehaviour
{
    [SerializeField] List<GameObject> players;
    [SerializeField] Transform movePositionTransform;

    private NavMeshAgent navMeshAgent;

    //Start is called before the first frame update
    void Awake()
    {
        navMeshAgent = GetComponent<NavMeshAgent>();
        players = FindObjectsWithTag("Player");
    }

    //Update is called once per frame
    void Update()
    {
        navMeshAgent.destination = GetClosestPlayer().transform.position;
    }

    //Loops through all players and returns the closest one
    GameObject GetClosestPlayer()
    {
        GameObject closestPlayer = players[0]; //settings the first player to be the closest one by default
        float distanceToClosestPlayer = Vector3.Distance(navMeshAgent.gameObject.transform.position, closestPlayer.transform.position);
        
        // loops/searches through all players
        foreach(GameObject player in players)
        {
            // calculate distance to this player
            float distanceToThisPlayer = Vector3.Distance(navMeshAgent.gameObject.transform.position, player.transform.position;

            // if this player is the closest one so far
            if (distanceToThisPlayer < distanceToClosestPlayer)
                {
                    // cache/save it
                    closestPlayer = player;
                    distanceToClosestPlayer = distanceToThisPlayer;
                }
        }
    }
}

注意:这会缓存玩家一次,在对象的唤醒时。如果玩家列表在那之后可以改变运行时(玩家可以在游戏中加入/退出),那么你应该更新当前的玩家列表(可能使用代理)。

相关问题