Unity 2018 - 在范围内时NPC 如何平滑地转向面对玩家

3

当前代码会使NPC检测到玩家并播放所需的动画,然后朝向玩家。然而,在玩家在范围内绕着NPC走动时,NPC只会猛地转向面对玩家,而不会持续旋转。

我想修改代码,让NPC在玩家仍处于碰撞体范围内时能够持续平稳地面对角色。我认为这与void update有关,但由于转向函数目前在onTriggerEnter中,对像我一样的初学者来说有些困惑。

public class helloTrigger : MonoBehaviour
{
    public Animator anim;
    public CharacterController player;
    public Transform Player;

    void Start()
    {
        player = GameObject.FindObjectOfType<CharacterController>();
        anim = GetComponent<Animator>();
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag != "Player") return;

        anim.Play("Hello");
        Vector3 lookAt = Player.position;
        lookAt.y = transform.position.y;
        transform.LookAt(lookAt);
    }

    void OnTriggerExit(Collider other)
    {
        if (other.tag == "Player")
        {
            anim.Play("Idle");
        }
    }
}

如果你不打算使用 Update,那就把它删除。在编译时,Unity 会创建一个对象列表,如果定义了 Update,则调用该列表上的对象。因此,在不使用 Update 时拥有它会影响性能。 - AustinWBryan
1个回答

3
如果你想让一个游戏对象平滑地面向另一个游戏对象,请使用Quaternion.LookRotation计算目标旋转,然后使用Quaternion.Lerp在当前旋转和使用Quaternion.LookRotation计算出的目标旋转之间进行插值。最后,根据时间进行插值。请参见文章以了解如何在旋转上进行插值。你可以在Update函数中实现这个功能,但我会在协程函数中使用它,因为这样可以更好地控制时间。
一个简单的平滑看向函数:
IEnumerator LookAtSmoothly(Transform objectToMove, Vector3 worldPosition, float duration)
{
    Quaternion currentRot = objectToMove.rotation;
    Quaternion newRot = Quaternion.LookRotation(worldPosition -
        objectToMove.position, objectToMove.TransformDirection(Vector3.up));

    float counter = 0;
    while (counter < duration)
    {
        counter += Time.deltaTime;
        objectToMove.rotation =
            Quaternion.Lerp(currentRot, newRot, counter / duration);
        yield return null;
    }
}

您的新脚本:
public class helloTrigger : MonoBehaviour
{
    public Animator anim;
    public CharacterController player;
    public Transform Player;
    Coroutine smoothMove = null;

    // Use this for initialization
    void Start()
    {
        player = GameObject.FindObjectOfType<CharacterController>();
        anim = GetComponent<Animator>();
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Player")
        {
            anim.Play("Hello");
            LookSmoothly();
        }

    }

    void OnTriggerExit(Collider other)
    {
        if (other.tag == "Player")
        {
            anim.Play("Idle");
        }
    }

    void LookSmoothly()
    {
        float time = 1f;

        Vector3 lookAt = Player.position;
        lookAt.y = transform.position.y;

        //Start new look-at coroutine
        if (smoothMove == null)
            smoothMove = StartCoroutine(LookAtSmoothly(transform, lookAt, time));
        else
        {
            //Stop old one then start new one
            StopCoroutine(smoothMove);
            smoothMove = StartCoroutine(LookAtSmoothly(transform, lookAt, time));
        }
    }

    IEnumerator LookAtSmoothly(Transform objectToMove, Vector3 worldPosition, float duration)
    {
        Quaternion currentRot = objectToMove.rotation;
        Quaternion newRot = Quaternion.LookRotation(worldPosition -
            objectToMove.position, objectToMove.TransformDirection(Vector3.up));

        float counter = 0;
        while (counter < duration)
        {
            counter += Time.deltaTime;
            objectToMove.rotation =
                Quaternion.Lerp(currentRot, newRot, counter / duration);
            yield return null;
        }
    }
}

1
顶级的!!! 并且帮助我更清晰地看到如何以及为什么使用协程。非常感谢!!! - Confused
确实!一开始我不确定什么是协程!谢谢你! - ReignBeaux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接