Unity 2018 - NPC smoothly turning to face the Player while within range

Multi tool use
Unity 2018 - NPC smoothly turning to face the Player while within range
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.
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
Update
Update
1 Answer
1
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.
Quaternion.LookRotation
Quaternion.Lerp
Quaternion.LookRotation
Update
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;
}
}
}
Top Drawer!!! and helps me see how and why to use Coroutines, a little clearer. THANK YOU!!!
– Confused
Jul 2 at 7:35
Indeed! I wasn't sure what a coroutine was in the first place! Thank you!
– shinjabo
2 days ago
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
If you're not gonna use
Update
, then delete it. Unity, at compile time, creates a list of objects to callUpdate
on if it is defined. Therefore, havingUpdate
when you aren't using it is bad for performance.– AustinWBryan
Jul 2 at 2:10