0
\$\begingroup\$

The script is very long so I will zoom in the specific script places of the problem and in the end I will add the full script too.

The problem is at lines 209 - 235 when the player is smoothly looking away from the last target back to the natural look. The problem is that it's not that smooth.

// 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, t / duration);//Time.deltaTime * weightDamping);
            t += Time.deltaTime;

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

I changed the lines 211 and 212 it was before using only Time.deltaTime * weightDamping but I changed it to use the t variable and duration. duration is public.

This part is working smooth slowly depending on the duration but it's not solving the problem.

The problem is when the player is start looking away back to natural he is doing it at once almost at once like "jumping" to natural look.

The lerp is helping for the last part when the player head is looking away to natural but not the part from looking the target item. I tried to set in other script the target to be null or the distance to 0 but nothing make it smooth slowly.

I recorded a very short 13 seconds video clip of the problem. The problem is at second 5 to 7.

https://www.youtube.com/watch?v=4JTSCpCHGhQ

The completed script :

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;
    public bool useHead = false;
    public float duration;

    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 float t;

    private void Awake()
    {

    }

    void Start()
    {
        animator = GetComponent<Animator>();
        allDetectedItems = new List<InteractableItem>();

        if (dimLights != null)
        {
            dimLights.lightsToDim = naviLights;
        }

        t = 0;
    }

    // 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)
            {
                if(target.enabledInteraction == false)
                {
                    continue;
                }

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

            /*if (allDetectedItems.Count == 1)
            {
                var crate = GameObject.Find("Crate_0_0");
                InteractableItem navi = allDetectedItems.Single(item => item.transform.name == "NAVI");

                if (crate.gameObject.GetComponent<UnlockCrate>().HasOpened())
                {
                    primaryTarget = navi;
                    target = primaryTarget;
                }
            }

                */
        }
    }

    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, t / duration);//Time.deltaTime * weightDamping);
            t += Time.deltaTime;

            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;
        }
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Problem solved. Should I answer or delete ? \$\endgroup\$ Oct 4 at 19:01
  • \$\begingroup\$ You should accept your solution. \$\endgroup\$
    – phresnel
    Oct 6 at 10:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.