another way to use OnAnimatorIK

I am creating my own third person mechanism (discussed in my post before, and no one replied), I call OnAnimatorIK inside of my script which is separate from Animator GameObject for some reason, and I realized it doesn’t work. Here’s my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InputHandler : MonoBehaviour
{
    public Camera cam;
    public Animator mecAnim;
    public Text textRotateYaw, textTargetRoot, textAngle, textFollowPos;
   
    void Awake()
    {
        if (cam == null)
            cam = Camera.current;
        if (mecAnim == null)
            mecAnim = GameObject.FindObjectOfType<Animator>();

        sTargetRoot = targetRotation.ToString();
        sRotateYaw = rotateYawVelocity.ToString();
        sAngle = angle.ToString();
        sFollowPos = followPos.ToString();

        targetRotation = mecAnim.transform.eulerAngles.y;
    }

    // Update is called once per frame
    void Update()
    {
        controlCharacterByRootMotion(mecAnim, cam.transform);
    }

    private void LateUpdate()
    {
        FollowCameraToObject(cam.transform, mecAnim.transform);
    }

    #region Camera

    public Vector3 offset = new Vector3(0, 0, -1.25f);
    public Vector3 followPos;
    float pitch, yaw, yawVel;
    public float maxPitch = 55f, minPitch = -75, height = 1.5f;
    public float MouseSensitivity = 10;

    void FollowCameraToObject(Transform cameraTrans, Transform targetTrans)
    {
        yaw += Input.GetAxis("Mouse X") * 10;
        pitch -= Input.GetAxis("Mouse Y") * 10;
        pitch = Mathf.Clamp(pitch, minPitch, maxPitch);
        Vector3 targetRotation = new Vector3(pitch, yaw);
        cameraTrans.eulerAngles = targetRotation;
        followPos = targetTrans.position + new Vector3(0, height,0);
        cameraTrans.position = followPos + cameraTrans.TransformDirection(offset);
    }
    #endregion

    float rotateYawVelocity, targetRotation, angle;
    bool rotateCheck = false;
    void controlCharacterByRootMotion(Animator animator, Transform viewPoint)
    {
        if (animator.runtimeAnimatorController == null)
        {
            height = 0;
            return;
        }
        angle = Mathf.RoundToInt(Mathf.Abs(animator.transform.eulerAngles.y) - Mathf.Abs(viewPoint.eulerAngles.y));
        if (angle > 120f || angle < -120f || Mathf.Clamp01(Mathf.Abs(animator.GetFloat("Straight"))
            + Mathf.Abs(animator.GetFloat("Strafe"))) > 0)
            rotateCheck = true;
        if( angle == 0f)
            rotateCheck = false;

        if (rotateCheck && !Input.GetButton("Fire2") && animator.runtimeAnimatorController != null)
        {
            targetRotation = viewPoint.eulerAngles.y;
            animator.transform.eulerAngles = animator.transform.up
                * Mathf.SmoothDampAngle(animator.transform.eulerAngles.y, targetRotation,
                ref rotateYawVelocity, 15 * Time.deltaTime);
            animator.SetFloat("Turn", rotateYawVelocity); // doesn't work
        }
        else animator.SetFloat("Turn", 0);

        animator.SetFloat("Straight", Input.GetAxis("Vertical"));
        animator.SetFloat("Strafe", Input.GetAxis("Horizontal"));
    }

    string sRotateYaw, sTargetRoot, sAngle, sFollowPos;
    private void OnGUI()
    {
        if(sRotateYaw != rotateYawVelocity.ToString())
        {
            sRotateYaw = rotateYawVelocity.ToString();
            textRotateYaw.text = "RotateYaw: "+sRotateYaw;
        }
        if (sTargetRoot != targetRotation.ToString())
        {
            sTargetRoot = targetRotation.ToString();
            textTargetRoot.text = "TargetRot: " + sTargetRoot;
        }
        if (sAngle != angle.ToString())
        {
            sAngle = angle.ToString();
            textAngle.text = "Angle: " + sAngle;
        }
        if(sFollowPos != followPos.ToString())
        {
            sFollowPos = followPos.ToString();
            textFollowPos.text = "X:"+ followPos.x+" Y:"+followPos.y+" Z:"+followPos.z;
        }
    }

    void OnAnimatorIK(int layerIndex)
    {
        mecAnim.SetLookAtPosition(cam.transform.forward * 10);
        mecAnim.SetLookAtWeight(1.0f);
    }
}

Oh anyway I can’t set Turn parameter, also need a hand for this.

Your script must be attached to the same object as your animation controller to receive OnAnimatorIK. I don’t see the point of calling it yourself (if you do that, I don’t see it in your script), as there is no guarantee that it’s happenig at the correct moment or with the correct animator context.

You can solve this with a relay script on the Animator in question.

public class InputHandler : MonoBehaviour {
    ...
    void Awake()
    {
        ...
        if (mecAnim == null)
            mecAnim = GameObject.FindObjectOfType<Animator>();
        var relay = mecAnim.gameObject.AddComponent<OnAnimatorIKRelay>();
        relay.OnAnimatorIKCallback += OnAnimatorIK;
        ...
    }
    ...
}

// in the same file
public class OnAnimatorIKRelay : MonoBehaviour {
    public event Action OnAnimatorIKCallback;

    private void OnAnimatorIK() {
        OnAnimatorIKCallback();
    }
}

ALSO you really don’t want to do GameObject.FindObjectOfType() to find the animator if it’s not assigned - that finds some arbitrary Animator in the scene, which is probably not what you want unless you never will have more than a single Animator.

I think I should change my logic code, thanks for advice.

And thanks for the reply