将生成对象移动到随机位置
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;
}
您也可以使用 InvokeRepeating
或 Coroutine
来解决这个问题。
如果您不希望所有 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);
}
}
增加目的地的数量,让移动看起来更随机。顺便说一句,目的地不需要由游戏对象指定,这只是为了方便查看示例程序的行为。
我有一个生成器对象。每次生成游戏对象时,我都希望该对象随机移动(游荡)。我的脚本中的问题是游戏对象的移动非常随机(抖动)。我该如何解决?
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;
}
您也可以使用 InvokeRepeating
或 Coroutine
来解决这个问题。
如果您不希望所有 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);
}
}
增加目的地的数量,让移动看起来更随机。顺便说一句,目的地不需要由游戏对象指定,这只是为了方便查看示例程序的行为。