我有一个生成器对象。每次生成一个游戏对象时,我都希望该对象随机移动(游荡)。我的脚本中的问题是游戏对象的移动非常随机(抖动)。我该怎么解决?
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);
}
我用不同的方法制作了新的随机向量,因为我打算用探路器功能对其进行更改,并使其在不同的线程/任务中使用。
答案 0 :(得分:1)
您正在每帧选择一个新方向。那将永远是非常紧张的。至少在一个很小的间隔后,您就不会只改变方向。这是Unity网站上实现此目的的一种方法的链接。 https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html
答案 1 :(得分:1)
使用Navigation怎么样?正如您所说的wandering
,我认为这将为您带来不错的结果,并使您的代码更简单。
以下屏幕截图是带有导航的示例。移动的游戏对象也很好地改变了方向,尽管由于游戏对象是胶囊而无法在示例中看到它。
示例程序中的 Ground
游戏对象具有NavMesh
。请参见here来构建NavMesh。
Agent
游戏对象具有NavMeshAgent
组件。请参见here进行设置。
下面的行为类适用于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;
}
}
下一个Behavior类仅用于生成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);
}
}
增加目的地数,使移动看起来更加随机。顺便说一下,目的地并不需要由游戏对象指定,这只是为了易于查看示例程序的行为。
答案 2 :(得分:0)
抖动的根源在于您正在更新移动每一帧的位置,因此您的对象永远不会有一致的位置移动。相反,我建议为每个对象附加一个新的脚本,这些脚本分别处理它们的移动。在该脚本中,您可以执行以下操作,延迟将目标位置保持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);
}
答案 3 :(得分:0)
您正在改变它们在每一帧中的移动方向,这就是造成抖动的原因。
您可以稍等片刻,然后再更改方向。
// Outside update
float betweenChanges = 2;
float lastChange = 0;
// Inside update
if(Time.realtimeSinceStartup > lastChange)
{
// Change directions
// ...
lastChange = Time.realTimeSinceStart + betweenChanges;
}
您也可以使用InvokeRepeating
或Coroutine
解决此问题。
如果您不希望所有NPC都同时改变方向,并且仍然像您的示例一样计划控制同一类中的每个NPC,则应该为每个NPC实例添加一个计时器,并使用该计时器来决定何时改变方向。
一个更好的主意是让每个NPC都有自己的Movement
-脚本。