不能让我的敌人在一个范围内随机移动。 Unity3D

时间:2015-03-01 14:12:55

标签: c# random unity3d artificial-intelligence

嗨:我正在研究FPS,并在3D中存活。我有一个代表我的敌人的动画模型。如果我在射程中,我可以让他向我移动。如果他越来越近,他就会停止移动(并制作动画)。现在我试图实现徘徊行为。

我的想法是这样的:敌人从起始位置开始。他检查玩家是否在范围内,如果为真,则FollowPlayer()如果为false则为MoveAround(),这意味着他计算了他实际位置的某个范围内的随机位置,Slerp到它,然后移动到该随机位置。到达随机位置后,他应该等待X秒直到下一步。我有的MoveAround()方法是一个Coroutine,但我不能让它工作。这是脚本:

using UnityEngine;
using System.Collections;

public class EnemyAI : MonoBehaviour {

public float rotationSpeed;
public float moveSpeed;
public float maxSpeed;
public float minRange;
public float maxRange;
public float moveRange;
Animator anim;
CharacterController controller;

// Use this for initialization
void Awake (){
    anim = GetComponent<Animator> ();
    controller = GetComponent<CharacterController> ();
}
void Start () {
}

// Update is called once per frame
void FixedUpdate () {
    FollowPlayer ();
    StartCoroutine(MoveAround ());
}
void FollowPlayer(){
    Vector3 playerPos = GameObject.Find ("Player").transform.position;
    Vector3 lookDir = playerPos - transform.position;
    Vector3 moveDir = lookDir;// * moveSpeed;
    moveDir *= Time.fixedDeltaTime;

    if((Vector3.Distance(transform.position, playerPos) <= maxRange) && (Vector3.Distance(transform.position, playerPos) > minRange) ){
        Vector3 previous = transform.position;
        transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (lookDir), rotationSpeed * Time.fixedDeltaTime);
        controller.Move(moveDir);
        float velocity = ((transform.position - previous).magnitude) / Time.fixedDeltaTime;
    //  Debug.Log("velocidad: " + velocity);
        previous = transform.position;
        anim.SetFloat ("speed", velocity);
    }
    if(Vector3.Distance(transform.position, playerPos) < minRange){
        controller.Move(Vector3.zero);
        Debug.LogWarning("hey");
        anim.SetFloat("speed",controller.velocity.magnitude);
    }
}
IEnumerator MoveAround(){
    Vector3 playerPos = GameObject.Find ("Player").transform.position;
    Vector3 randomPos = Random.onUnitSphere * moveRange;
    randomPos = new Vector3 (randomPos.x + transform.position.x, transform.position.y, randomPos.z + transform.position.z);
    Vector3 lookDir = randomPos - transform.position;
    Vector3 moveDir = lookDir;
    moveDir *= Time.fixedDeltaTime;
    Debug.Log ("Player Pos: " + playerPos);
    Debug.Log ("Random Pos: " + randomPos);
    Debug.Log ("Look Dir: " + lookDir);
    Debug.Log ("Move Dir: " + moveDir);

    if(Vector3.Distance(transform.position, playerPos) > maxRange){
        Debug.Log("Moving the enemy");
        Vector3 previous = transform.position;
        transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (lookDir), rotationSpeed * Time.fixedDeltaTime);
        controller.Move(moveDir);
        float velocity = ((transform.position - previous).magnitude) / Time.fixedDeltaTime;
    //  Debug.Log("velocidad: " + velocity);
        previous = transform.position;
        anim.SetFloat ("speed", velocity);
        Debug.Log("Enemy moved");
        yield return new WaitForSeconds(2f);
        Debug.Log("waiting the first 2 seconds");
    }
    Debug.Log ("arrived at destination");
    yield return new WaitForSeconds(2f);
    Debug.Log ("COroutine final");
}

void OnDrawGizmosSelected(){
    Gizmos.color = Color.green;
    Gizmos.DrawWireSphere (transform.position, maxRange);
    Gizmos.DrawWireSphere (transform.position, minRange);
}
}

注意:地图应该是平的,但如果代码适用于具有可变高度的地图,那将会很棒。 我用字符控制器移动字符是正确的方法吗?

1 个答案:

答案 0 :(得分:0)

你每帧都在调用MoveAroundFollowPlayer(实际上每个物理帧都是如此,这更常见)。你真的想做更像这样的事情:

void Start()
{
    StartCoroutine(Move());
}

IEnumerator Move()
{
    while (true)
    {
        if (nearPlayer)
            yield return StartCoroutine(FollowPlayer());
        else
            yield return StartCoroutine(MoveAround());
    }
}

这样,您只能在上一个动作完成后开始移动。如果你想检查每一帧的位置,它仍然有效,但你的检查会在MoveAroundFollowPlayer内进行。因为每一帧启动协同程序完全违背了协同程序的目的。如果你有想要每帧运行的逻辑(无例外),请直接将其放在UpdateFixedUpdate中,而不使用协同程序。

编辑:澄清一下,你的方法最简单的问题是,如果你的协同程序运行4秒钟,你会在任何一个时刻运行每个方法的4/Time.fixedDeltaTime个实例,可能互相争斗。我不认为你想要400个单独的MoveAround功能一起运行。 :)