3

With the current code the NPC will detect the and turn towards the player with the desired animation playing. However, the NPC only snaps to face the player and does not continue to rotate as the player walks around the NPC while they are in range.

I would like to modify this so that the NPC consistently and smoothly turns to face the character while the player is in range of the collider. I figured it would have something to do within void update, but since the function to turn is currently in onTriggerEnter it's a little confusing to a beginner such as myself.

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");
        }
    }
}
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
ReignBeaux
  • 43
  • 2
  • 14
  • If you're not gonna use `Update`, then delete it. Unity, at compile time, creates a list of objects to call `Update` on if it is defined. Therefore, having `Update` when you aren't using it is bad for performance. – AustinWBryan Jul 02 '18 at 02:10

1 Answers1

3

If you want a GameObject to face another GameObject smoothly, use Quaternion.LookRotation to calculate the destination rotation then use Quaternion.Lerp to lerp between the current rotation and the destination rotation calculated with Quaternion.LookRotation. Finally, do the lerping over time. See this post to understand how lerping over rotation work. You can do this in the Update function but I will use it in a coroutine function since it gives you more control.

A simple Look-at smoothly function:

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;
    }
}

Your new script:

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;
        }
    }
}
Programmer
  • 121,791
  • 22
  • 236
  • 328