- Home /
Using IK the head is not returning smooth to his natural look position how can I fix it ?
From line 184 is where the player head and body should be a return to the natural look :
// Let the player smoothly look away from the last target to the neutral look position
I just don't understand why the head and body are not returning to the natural look position smoothly? And how to fix that problem? It seems to me that the problem is more with the head. When I drag the target object above the player's head then a bit to the back behind the player returns to his natural-looking position but not smooth it's like it's "jumping" at once to the natural look position and not smooth slowly. When I move the target object back above the player in front of him when the target is in the player's sight again then he looks at it smooth slowly but when he loses the target from his sightsee he is not returning the head smooth slowly to the natural look.
The script is a bit long: but the back to natural-looking position part in the code is starting from line 184:
using UnityEngine;
using System;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
using TMPro;
[RequireComponent(typeof(Animator))]
public class IKControl : MonoBehaviour
{
public List<InteractableItem> lookObjs = new List<InteractableItem>();
public TextMeshProUGUI text;
public float weightDamping = 1.5f;
public bool RightHandToTarget = true;
public float throwSpeed;
public bool handFinishedMove = false;
public GameObject descriptionTextImage;
public GameObject naviParent;
public DimLights dimLights;
public Light[] naviLights;
public bool startMovingNAVI = false;
public InteractableItem target;
public bool toTarget = false;
public bool hasSent = false;
public InteractableItem leftHand;
private List<InteractableItem> allDetectedItems;
private Animator animator;
private InteractableItem lastPrimaryTarget;
private float lerpEndDistance = 0.1f;
private float finalLookWeight = 0;
private bool transitionToNextTarget = false;
private List<string> objectsNames = new List<string>();
private bool setNaviRotation = false;
private void Awake()
{
}
void Start()
{
animator = GetComponent<Animator>();
allDetectedItems = new List<InteractableItem>();
dimLights.lightsToDim = naviLights;
}
// Callback for calculating IK
void OnAnimatorIK()
{
if (lookObjs != null)
{
lookObjs.RemoveAll(x => x == null);
InteractableItem primaryTarget = null;
float closestLookWeight = 0;
// Here we find the target which is closest (by angle) to the players view line
allDetectedItems.Clear();
foreach (InteractableItem target in lookObjs)
{
Vector3 lookAt = target.transform.position - transform.position;
lookAt.y = 0f;
// Filter out all objects that are too far away
if (lookAt.magnitude > target.distance) continue;
float dotProduct = Vector3.Dot(new Vector3(transform.forward.x, 0f, transform.forward.z).normalized, lookAt.normalized);
float lookWeight = Mathf.Clamp(dotProduct, 0f, 1f);
if (lookWeight > 0.1f && lookWeight > closestLookWeight)
{
closestLookWeight = lookWeight;
primaryTarget = target;
}
allDetectedItems.Add(target);
}
if (allDetectedItems.Count == 2)
{
objectsNames = allDetectedItems.Select(item => item.transform.name).ToList();
if (objectsNames.Contains("NAVI") && objectsNames.Contains("Security Keypad Interactable"))
{
InteractableItem navi = allDetectedItems.Single(item => item.transform.name == "NAVI");
InteractableItem securitykeypad = allDetectedItems.Single(item => item.transform.name == "Security Keypad Interactable");
var crate = GameObject.Find("Crate_0_0");
if (crate.gameObject.GetComponent<UnlockCrate>().HasOpened())
{
primaryTarget = navi;
target = primaryTarget;
startMovingNAVI = true;
}
else
{
primaryTarget = securitykeypad;
}
}
}
InteractWithTarget(primaryTarget, closestLookWeight);
}
}
private void InteractWithTarget(InteractableItem primaryTarget, float closestLookWeight)
{
if (primaryTarget != null)
{
if ((lastPrimaryTarget != null) && (lastPrimaryTarget != primaryTarget) && (finalLookWeight > 0f))
{
// Here we start a new transition because the player looks already to a target but
// we have found another target the player should look at
transitionToNextTarget = true;
}
}
// The player is in a neutral look position but has found a new target
if ((primaryTarget != null) && !transitionToNextTarget)
{
if (primaryTarget.IsAnyAction())//.interactableMode == InteractableItem.InteractableMode.ActionWithoutThrow)
{
RightHandToTarget = true;
}
lastPrimaryTarget = primaryTarget;
//finalLookWeight = Mathf.Lerp(finalLookWeight, closestLookWeight, Time.deltaTime * weightDamping);
finalLookWeight = Mathf.Lerp(finalLookWeight, 1f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .1f;
animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(primaryTarget.transform.position);
if (RightHandToTarget && primaryTarget.IsAnyAction())
{
Vector3 relativePos = primaryTarget.transform.position - transform.position;
Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
if (primaryTarget.interactableMode == InteractableItem.InteractableMode.ActionWithoutThrow)
{
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 1f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, primaryTarget.transform.position);
}
if (primaryTarget.interactableMode == InteractableItem.InteractableMode.Action)
{
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 0.1f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, primaryTarget.transform.position);
}
// -> new code block
if (finalLookWeight > 0.95f) // here you can play with a value between 0.95f -> 1.0f
{
if (primaryTarget.interactableMode == InteractableItem.InteractableMode.Action
&& hasSent == false)
{
target = primaryTarget;
toTarget = true;
hasSent = true;
primaryTarget.description = "";
// Here I need to find where to make hasSent false again.
}
}
else
{
hasSent = false;
}
if (finalLookWeight > 0.9f)
{
handFinishedMove = true;
}
}
}
// Let the player smoothly look away from the last target to the neutral look position
if ((primaryTarget == null && lastPrimaryTarget != null) || transitionToNextTarget)
{
finalLookWeight = Mathf.Lerp(finalLookWeight, 0f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(lastPrimaryTarget.transform.position);
if (RightHandToTarget)
{
Vector3 relativePos = lastPrimaryTarget.transform.position - transform.position;
Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 0.5f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, lastPrimaryTarget.transform.position);
}
if (finalLookWeight < lerpEndDistance)
{
transitionToNextTarget = false;
finalLookWeight = 0f;
lastPrimaryTarget = null;
transform.rotation = Quaternion.Euler(0, transform.eulerAngles.y, 0);
}
}
if (text != null)
{
// Show primary object found by the player
if (primaryTarget != null)
{
if (primaryTarget.description != "")
{
descriptionTextImage.SetActive(true);
text.text = primaryTarget.description;
}
}
else
{
text.text = "";
descriptionTextImage.SetActive(false);
}
}
}
private void Update()
{
if (MenuController.LoadSceneForSavedGame == true && setNaviRotation == false)
{
transform.rotation = Quaternion.Euler(0, transform.eulerAngles.y, 0);
setNaviRotation = true;
}
}
}