Using a callback OnAnimatorIK() with FixedUpdate in the same script is fine ?

using UnityEngine;
using System;
using System.Collections;
using UnityEngine.SocialPlatforms;
using UnityEditor.Animations;
using UnityEngine.UI;
using System.Collections.Generic;

[RequireComponent(typeof(Animator))]

public class IKControl : MonoBehaviour
{
    public List<Transform> targets = new List<Transform>();
    public Transform lookObj = null;
    public Transform head = null;
    public float finalLookWeight;
    public float weightDamping = 1.5f;
    public float playerSpeedRot;
    public bool rotatePlayer = false;
    public GameObject text;

    protected Animator animator;

    private float inputMovement;
    private Text textC;

    void Start()
    {
        animator = GetComponent<Animator>();
        textC = text.GetComponent<Text>();
    }

    //a callback for calculating IK
    void OnAnimatorIK()
    {
        var ClosestTarget = GetClosestTarget(targets, transform);

        lookObj = ClosestTarget;

        Vector3 flattenedLookAtVector = Vector3.ProjectOnPlane(lookObj.position - transform.position, transform.up);
        float dotProduct = Vector3.Dot(transform.forward, flattenedLookAtVector);
        float lookWeight = Mathf.Clamp(dotProduct, 0f, 1f);
        finalLookWeight = Mathf.Lerp(finalLookWeight, lookWeight, Time.deltaTime * weightDamping);
        float bodyWeight = finalLookWeight * .5f;

        animator.SetLookAtWeight(finalLookWeight, bodyWeight);
        animator.SetLookAtPosition(lookObj.position);

        if (rotatePlayer == true)
        {
            var lookPos = lookObj.position - transform.position;
            lookPos.y = 0;
            var rotation = Quaternion.LookRotation(lookPos);
            transform.rotation = Quaternion.Slerp(transform.rotation, rotation,
                Time.deltaTime * playerSpeedRot);
        }
    }

    private void FixedUpdate()
    {
        TargetHit();
    }

    private void TargetHit()
    {
        int layerMask = 1 << 8;
        RaycastHit hit;
        // Does the ray intersect any objects excluding the player layer
        if (Physics.Raycast(head.position, head.TransformDirection(Vector3.forward), out hit, Mathf.Infinity, layerMask))
        {
            text.SetActive(true);
            textC.text = "Hit !" + hit.transform.name;
        }
        else
        {
            textC.text = "Nothing to hit !";
        }
    }

    private Transform GetClosestTarget(List<Transform> targets, Transform fromThis)
    {
        Transform bestTarget = null;
        float closestDistanceSqr = Mathf.Infinity;
        Vector3 currentPosition = fromThis.position;
        foreach (Transform potentialTarget in targets)
        {
            Vector3 directionToTarget = potentialTarget.position - currentPosition;
            float dSqrToTarget = directionToTarget.sqrMagnitude;
            if (dSqrToTarget < closestDistanceSqr)
            {
                closestDistanceSqr = dSqrToTarget;
                bestTarget = potentialTarget;
            }
        }
        return bestTarget;
    }
}

The script is working great.

My question is if using the callback OnAnimatorIK and FixedUpdate in the same script is fine ?
I tested it and if I’m calling the method TargetHit from inside the callback OnAnimatorIK it’s not working. but if I’m calling the TargetHit from inside the FixedUpdate it’s working. It’s more a knowledge question then a problem since it’s working fine.

One problem at a time. Find out if OnAnimatorIK is even being called when you care. It might not be an interaction with FixedUpdate at all.

As far as the timing of each, there might be some implications to how you structure your code. Perhaps this will help you reason about possible timing scenarios:

1 Like

I didn’t see any problems with the timing when calling it from the FixedUpdate. Just wondered about the logic using it with the cllback I mean when writing a script. The script is working fine. It’s executing the callback and fixedupdate and I didn’t notice of any timing problems so far. Just wondered about scripting writing logic if it’s fine to do it this way or as you mentioned it might be make problems in the future ?

See my code in the old thread if you see bad lK transitions between multiple targets :slight_smile:

On this topic:
You shouldnt rotate the player inside the OnAnimatorIK callback function. Here you should use the FixedUpdate method too if your player has a rigidbody or character controller component attached.

Basically you should do in the IK callback only animator related things and not change the physics of the game or change GO positions / rotations.

2 Likes

Ooh, yes, good spot Zer0!

Also… if you’re using physics and expect collisions to work, do not ever assign to transform.rotation or transform.position directly. If you do, you will miss collisions and get weird glitching.

Instead, always use the .MovePosition() and .MoveRotation() methods on the Rigidbody, otherwise you will “startle” the physics system by moving stuff without its knowledge.

1 Like