Using Inverse Kinematics for hand placement

Getting the placement of the hands correct is one of the hardest parts of doing a ledge grab system. For roof tops like in the video it is a little easier as you have an over hang for ledge so when the player is underneath it the hand placement will be correct as it is easy to get the colliders to line up. The issue comes in when you have a ledge that the player can not be directly underneath.
Unity_URXzGCfZzv

For these scenarios Inverse Kinematics will be a help.
I have a 2.5D 2.5D Platformer that I used this technique on, I used Scriptable Objects as variables to pass values in this project, but the principles are the same.

Along with an Article that I wrote up.
https://blog.devgenius.io/completing-the-ledge-grabbing-system-9a4fef94be3b

The first step is to enable IK Pass on the layer with the animation. In our case it is the Base Layer on the Player’s Animator Controller.
Unity_NsCeShJY8x

Now we need an On Animator IK Method to do our work.

LedgeDetector.cs


    [RequireComponent(typeof(Collider), typeof(Rigidbody))]
    public class LedgeDetector : MonoBehaviour
    {
        [SerializeField] private Transform leftHandPosition;
        [SerializeField] private Transform rightHandPosition;

        private bool _hasLeftHandPosition;
        private bool _hasRightHandPosition;
        private bool _useIK;

        public event Action<Vector3> OnLedgeDetect;

        private void Awake()
        {
            _hasRightHandPosition = rightHandPosition;
            _hasLeftHandPosition = leftHandPosition;
        }

        private void OnTriggerEnter(Collider other)
        {
            OnLedgeDetect?.Invoke(other.transform.forward);
            _useIK = true;
        }

        private void OnTriggerExit(Collider other)
        {
            _useIK = false;
        }        

       //private void OnAnimatorIK(int layerIndex) 
        public void OnLedgeAnimatorIK([NotNull] Animator animator)
        {
            float weight = _useIK ? 1 : 0; 
            Debug.Log($"{_useIK}: {weight}, {_hasLeftHandPosition}, {_hasRightHandPosition}");
            animator.SetIKPositionWeight(AvatarIKGoal.RightHand, _hasRightHandPosition ? weight : 0);
            animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, _hasLeftHandPosition ? weight : 0);
            
            if (_hasRightHandPosition) 
                animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandPosition.position);
            if (_hasLeftHandPosition)
                animator.SetIKPosition(AvatarIKGoal.LeftHand, leftHandPosition.position);
        }
    }

When Play Testing I Realized that for some reason the On Animator IK was not getting called from on the Ledge Detector to fix this I made the method public and added the On Animator IK Method to the Player State Machine.

In Player state machine

        private void OnAnimatorIK(int layerIndex)
        {
            if (LedgeDetector) LedgeDetector.OnLedgeAnimatorIK(Animator);
        }

Set Everything up in Unity, to set where the positions of the hands should go I lined them up with the hands on the player and just moved them forward on the Z axis a bit. When entering Play Mode I got found that I picked a correct position.

Play Testing
Unity_25KVqGbmFh

This can be approved upon. Like add a Ledge script to the Ledge and set the Use IK if you want to use IK for that ledge. So for over hang type ledges you would set it to false and for wall like edges set it to true.

   public class Ledge : MonoBehaviour
    {
        [field: SerializeField] public bool UseIK { get; private set; }
    }

In LedgeDetector

        private void OnTriggerEnter(Collider other)
        {
            OnLedgeDetect?.Invoke(other.transform.forward);
            if (other.TryGetComponent(out Ledge ledge))
                _useIK = ledge.UseIK;
        }

Or you can use a raycast to set the position of the hands to the nearest object surface.

4 Likes

What an excellent post! IK is a very useful tool for getting more precise placement of hands and feet in animation.

1 Like

I figured that this was worth a share. I read a comment some place that IK was not introduced as they where not very familiar with it. Nice that Unity introduced a simple form of this for Foot and Hand. This is the Most I know about IK.

I know that there is Unity also has the Animation Rigging Package.
Animation Rigging | Animation Rigging | 1.1.1
For those that are advanced in Animation IK and Rigging. This is one of the things that I am looking at playing around with some time when I get a chance. The Unity Learn uses it in one of the Learning Paths that show detailed Procedural Animation (something that would be nice to learn) and A Boss Worm Like Animation.
I have seen articles on AI creating Procedural Animations learn how to Stand Up ->Walk ->Run ->Jumping->Attacking. Something that would be an interesting Game Mechanic is as a Character gains a level in a skill they preform the task better, incorporate a sample from the AI Learned Pass and in the animation. More proficient in using a one handed sword the better the animation, start with one of the sluggish clumsy animation and work it’s way to one of the faster master animations.

The trickiest part about teaching things like IK and Root Motion is that these concepts tend to leave beginning students behind.

At some point, we need to make a course that moves past the intermediate stage and gets into some of the more advanced features.

4 Likes

IK and Root Motion is more of a Animation Artiest thing then a Programmer thing. Even though Unity does offer some programming solutions. I just know the very basics. I understand the concepts of IK and Root Motion. I have been doing some research on this ever since I read the article / saw the YouTube video on AI created Procedural Animation and thought that it was a cool concept to try to incorporate as a Game Play Mechanic.

Hi there !

I’m actually working on a project using IK and root motion and I encounter an issue. I found a solution to solve it, but I think this is not the correct solution to solve it.

My issue:

When I play my climbing Idle animation, my IK from (OnAnimatorIk) is fighting with my Idle animation.

How I solve this ? Well I juste untick the box from the paremeter of the animator and it’s working…

So am I good doing like this ? Or do you have any other ideas how can I fix this ?

Of course, this means you’re no longer using IK and root motion…

This might be better fixed with a StateMachineBehaviour attached to the state you wish to disable Root Motion on.

using UnityEngine;

public class RootMotionDisablingStateBehaviour : StateMachineBehaviour
{
    private bool usingRootMotion = false;
    public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        usingRootMotion = animator.applyRootMotion;
        animator.applyRootMotion = false;
    }

    public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.applyRootMotion = usingRootMotion;
    }

}

My version has a check to see if root motion is actually being used because I’ve used this setup in projects where some characters are using root motion and some are not. Usually, I slap this behaviour on idle states.

1 Like

If you are using the example above you just need to make sure UseIk is set to false when you do not want the IK to run. If you have IK for ledges and separate one for climbing a ladder then you may want to have a flag for the different implementations or look into using the more advanced Animation Rigging Package.

1 Like

@James_Lafritz I want to thank both of you for this precious advices !

Privacy & Terms