嗨:我正在研究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);
}
}
注意:地图应该是平的,但如果代码适用于具有可变高度的地图,那将会很棒。 我用字符控制器移动字符是正确的方法吗?
答案 0 :(得分:0)
你每帧都在调用MoveAround
和FollowPlayer
(实际上每个物理帧都是如此,这更常见)。你真的想做更像这样的事情:
void Start()
{
StartCoroutine(Move());
}
IEnumerator Move()
{
while (true)
{
if (nearPlayer)
yield return StartCoroutine(FollowPlayer());
else
yield return StartCoroutine(MoveAround());
}
}
这样,您只能在上一个动作完成后开始移动。如果你想检查每一帧的位置,它仍然有效,但你的检查会在MoveAround
和FollowPlayer
内进行。因为每一帧启动协同程序完全违背了协同程序的目的。如果你有想要每帧运行的逻辑(无例外),请直接将其放在Update
或FixedUpdate
中,而不使用协同程序。
编辑:澄清一下,你的方法最简单的问题是,如果你的协同程序运行4秒钟,你会在任何一个时刻运行每个方法的4/Time.fixedDeltaTime
个实例,可能互相争斗。我不认为你想要400个单独的MoveAround功能一起运行。 :)