I´m trying to write a simple wandering AI for a 2D game.
My code should generate a random position, move the object there and continue this. I know how it shoud be done, but my code is just not working.
Here is my code:
using UnityEngine;
using System.Collections;
public class ZombieAI : MonoBehaviour {
public float WalkSpeed;
public float WalkRadius = 10;
public bool Wandering;
// Update is called once per frame
void Update () {
if (Wandering == true) {
Vector2 WalkPoint = Random.insideUnitCircle * WalkRadius + new Vector2(transform.position.x,transform.position.y);
Debug.Log(WalkPoint);
while(new Vector2(transform.position.x, transform.position.y) != WalkPoint){
transform.position = Vector3.MoveTowards (transform.position, WalkPoint, WalkSpeed / Time.deltaTime);
}
}
}
When I run my game now, the Sprite realy fast from one point to another, like it´s teleporting. Even if i lower the speed value noting changes.
I think the proble is with the while-loop, but if I delete it the another problem shows up: The debug.Log returns normal coordinates, but the Sprite moves just very tiny very fast steps. It seems like the Sprite has not enough time to move to the target point ,instead it generates a new target every frame.
Please help me to figure out what´s wrong.
Thank you,
TheSakuron
You’re correct that the while loop is the issue. You’re generating the random point and moving the transform all the way to the target point in a single frame. And when you remove the while loop, you’re generating the random point, moving one step towards it in a single frame, and then the next frame you’re generating a new random point and moving one step towards that.
This kind of scenario comes up all of the time in game programming. You need to be able to do work that spans multiple frames. There are a number of ways you could handle this, but Coroutines are a decent fit here.
Something like this:
void Start()
{
// start the coroutine to randomly move the zombie around
StartCoroutine(ZombieMove());
}
IEnumerator ZombieMove()
{
// keep on running - you could replace "true" with a variable that would let you control when it stops
while (true)
{
Vector2 WalkPoint = Random.insideUnitCircle * WalkRadius +
new Vector2(transform.position.x,transform.position.y);
Debug.Log(WalkPoint);
while(new Vector2(transform.position.x, transform.position.y) != WalkPoint)
{
transform.position = Vector3.MoveTowards (transform.position, WalkPoint, WalkSpeed / Time.deltaTime);
yield return null; // wait for the next frame
}
}
}
Oh, and I just noticed that you’re comparing transform.position
with WalkPoint
. Since vectors use floating point, it’s generally not a good idea to compare values for equality. Because of rounding errors and such it will be rare that they’re exactly equal to another value. A good way to handle this is to compare distance from the target point. So replace the while (new Vector2...
code with this:
while (Vector2.Distance(new Vector2(transform.position.x, transform.position.y),
WalkPoint) > 0.1f)
{
}
This will keep looping until the transform moves within 0.1 units of the target. You may want a smaller values than 0.1, but that’s something to play around with. Probably make it a public member variable so you can set it in the inspector.
Try
transform.position = Vector3.MoveTowards (transform.position, WalkPoint, WalkSpeed * Time.deltaTime);
instead.