将生成对象移动到随机位置

Move spawn object to random position

我有一个生成器对象。每次生成游戏对象时,我都希望该对象随机移动(游荡)。我的脚本中的问题是游戏对象的移动非常随机(抖动)。我该如何解决?

void Start ()
{
    InvokeRepeating("SpawnNPC", Spawntime, Spawntime);
}

// Update is called once per frame
void Update () {
    population = GameObject.FindGameObjectsWithTag("NPCobject");
    for (int i = 0; i < population.Length; i++)
    {
        getNewPosition();
        if (population[i].transform.position != pos)
        {
            population[i].transform.position = Vector3.MoveTowards(population[i].transform.position, pos, .1f);
        }
    }
}
void getNewPosition()
{
    float x = Random.Range(-22, 22);
    float z= Random.Range(-22, 22);

    pos = new Vector3(x, 0, z);
}

我用不同的方法制作了新的随机化向量,因为我打算用探路者功能改变它并用不同的方法制作它thread/task。

抖动的根源在于您正在更新位置以移动每一帧,因此您的对象永远不会有一个一致的位置可以移动到。相反,我会建议将一个新脚本附加到您的每个单独处理其移动的对象。在那个脚本中你可以做类似下面的事情,它有一个延迟来保持目标位置超过 1 帧。

float delaytimer;
Vector3 pos;

void Start () {
    getNewPosition(); // get initial targetpos
}

void Update () {
    delaytimer += Time.deltaTime;

    if (delaytimer > 1) // time to wait 
    {
        getNewPosition(); //get new position every 1 second
        delaytimer = 0f; // reset timer
    }
    transform.position = Vector3.MoveTowards(transform.position, pos, .1f);
}

void getNewPosition()
{
    float x = Random.Range(-22, 22);
    float z= Random.Range(-22, 22);

    pos = new Vector3(x, 0, z);
}

你每一帧都在选择一个新的方向。那将永远是非常紧张的。您至少不想在一小段时间后才改变方向。这是 Unity 网站上的一种 link 方法。 https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html

您正在改变它们在每一帧中移动的方向,这就是导致抖动的原因。

你可以稍等片刻再改变方向,也许是这样。

// Outside update
float betweenChanges = 2;
float lastChange = 0;

// Inside update
if(Time.realtimeSinceStartup > lastChange) 
{
    // Change directions
    // ...

    lastChange = Time.realTimeSinceStart + betweenChanges;
}

您也可以使用 InvokeRepeatingCoroutine 来解决这个问题。

如果您不希望所有 NPC 同时改变方向并且仍然计划像您的示例中那样从同一个 class 控制每个 NPC,您或许应该为每个 NPC 实例添加一个计时器并用它来决定何时改变方向。

更好的办法是让每个 NPC 都有自己的 Movement-脚本。

使用 Navigation 怎么样?正如你所说 wandering,我认为它会给你一个很好的结果,也可以使你的代码简单。

以下屏幕截图是带有导航的示例。移动的游戏对象也很好地改变了它们的方向,虽然在示例中看不到,因为游戏对象是胶囊...

Ground 示例程序中的游戏对象有NavMesh。请参见 here 构建 NavMesh。

Agent 游戏对象有 NavMeshAgent 组件。请参阅 here 进行设置。

下面的行为 class 适用于 Agent 游戏对象。

using UnityEngine;
using UnityEngine.AI;

public class NavAgentBehaviour : MonoBehaviour {

    public Transform[] Destinations { get; set; }

    // Use this for initialization
    void Start ()
    {
        InvokeRepeating("changeDestination", 0f, 3f);
    }

    void changeDestination()
    {
        var agent = GetComponent<NavMeshAgent>();
        agent.destination = Destinations[Random.Range(0, Destinations.Length)].position;
    }
}

下一个行为 class 仅用于生成 Agent 和设置目的地。在 Unity 上,将其设置为场景中的任何游戏对象,并将游戏对象分配给字段。

using UnityEngine;

public class GameBehaviour : MonoBehaviour {

    public GameObject Agent;
    public Transform SpawnPoint;

    public Transform Destination1;
    public Transform Destination2;
    public Transform Destination3;

    // Use this for initialization
    void Start()
    {
        Agent.SetActive(false);
        InvokeRepeating("Spawn", 0f, 2f);
    }

    void Spawn() {
        var newAgent = Instantiate(Agent);
        newAgent.GetComponent<NavAgentBehaviour>().Destinations = new[] { Destination1, Destination2, Destination3 };
        newAgent.transform.position = SpawnPoint.position;
        newAgent.SetActive(true);
    }
}

增加目的地的数量,让移动看起来更随机。顺便说一句,目的地不需要由游戏对象指定,这只是为了方便查看示例程序的行为。