Root Motion and Jump

Hello everyone.

To learn I am trying to make a character controller using root motion, on ground everything is ok, but I can’t figure out how to do the jump. I do understand there is a character controller in unity but it does no use root motion and the goal here is to learn root motion.

Right now I have a forward jump animation, it look like I need forward, left and right to make a blend tree just for the jump. Is this correct? I thought that could be accomplished with only one animation, all I need is the character to keep its momentum and rotation and the same jump animation could be used.

Another problem I see is the timing of the animation, the animation can finish and the player might still be in the air, like falling from a cliff. I think the best way to go is to use 3 animations, one for jump, on for midair and on for landing. I have no idea on how to accomplish that with root motion.

Perhaps I should disable root motion for the animation during the jump and only use for when on the ground?

Any tips are very much appreciated.

@theANMATOR2b and @uacaman, what you want to do is to make a Vector3 variable, v, that equals the Animator.deltaPosition, then you want to store Rigidbody.velocity.y into v.y, then you set Rigidbody.velocity to v. The other part of your code will be in what checks to see if you’re grounded or not, so when your jump input fires, make sure that anim.applyRootMotion = false when you’re not grounded, and to true once you’re grounded. You’ll also have to break your jump animation into 3 parts, jump up, falling, and then landing. Then, in your jump up animation settings, make sure that only “Loop Time, Loop Pose, and Root Transform Position (XZ)” are all checked. Then for your falling animation, check-mark everything: Loop Time, Loop Pose, Rot Transform Rotation, Root Transform Position (Y), and Root Transform Position (XZ). Your landing animation shouldn’t loop, so don’t check-mark Loop Time nor Loop Pose and have everything else checked-marked.
Here’s what you can expect: (This is just a clip from a game I’m working on).

https://drive.google.com/file/d/14v7_-EN96EMzGe1BO98ndQRr_kGukSr0/view?usp=sharing

Here’s pieces of my code that handle airborne movement:

Rigidbody rbody;
Animator anim;

float extraGravityMultiplier = 2f;
float searchLength = 0.56f;
float searchLengthMax = 0.56f;
float jumpHeight = 2f //However high you want your character to jump
float moveMultiplier = 1f; //How much more distance to cover with root motion

bool isInAir = False;

Vector3 physicsCenter;
Vector3 groundNormal;

void Start() {
        rbody = GetComponent<Rigidbody>();
        anim = GetComponent<Animator>();
    }

void Update() {
        Jump();
    }

void FixedUpdate()
    {
        //All physics methods will be executed here
        isInAirCheck();
    }

public void OnAnimatorMove()
    {
        // we implement this function to override the default root motion.
        // this allows us to modify the positional speed before it's applied.
        if (!isInAir && Time.deltaTime > 0)
        {
            Vector3 v = (anim.deltaPosition * moveMultiplier) / Time.deltaTime;

            // we preserve the existing y part of the current velocity.
            v.y = rbody.velocity.y;
            rbody.velocity = v;
        }
    }

void isInAirCheck()
    {
        anim.SetBool("Grounded", !isInAir);

        RaycastHit hit;
        physicsCenter = this.transform.position + this.GetComponent<CapsuleCollider().center;
        //radius = capCollider.radius * 0.9f;

        if (Physics.SphereCast(physicsCenter, radius, Vector3.down, out hit, searchLength))
        {
            if (hit.transform.gameObject.tag != "Player")
            {
                isInAir = false;
                anim.applyRootMotion = true;
            }
        }
        else
        {
            groundNormal = Vector3.up;
            anim.applyRootMotion = false;
            isInAir = true;
        }

        #region old way of raycast ground checking 
        /*This is another way of ground checking with single raycast
        Debug.DrawRay(physicsCenter, Vector3.down, Color.red, searchLength);
        if (Physics.Raycast(physicsCenter, Vector3.down, out hit, searchLength))
        {
            groundNormal = hit.normal;
            if (hit.transform.gameObject.tag != "Player")
            {
                isInAir = false;
                anim.applyRootMotion = true;
            }
        }
        else
        {
            groundNormal = Vector3.up;
            anim.applyRootMotion = false;
            isInAir = true;
        }*/
        #endregion

        // apply extra gravity from multiplier:
        Vector3 extraGravityForce = (Physics.gravity * extraGravityMultiplier) - Physics.gravity;
        rbody.AddForce(extraGravityForce);
    }

void Jump()
    {
        //Going to handle jumping and airborne movement

        if (!isInAir && anim.GetBool("Can Jump") && Input.GetButtonDown("Jump") && !crouch)
        {
            anim.SetTrigger("Jump");
            searchLength = 0.001f; //used to be 0.01f;
            
            //Using own gravity variable incase different levels have different gravity requirements
            rbody.AddForce(transform.up * Mathf.Sqrt(2 * gravity * jumpHeight), ForceMode.VelocityChange); 
        }
        else {
            searchLength = searchLengthMax; //used to be 1.4f
        }
    }

BTW, you can define radius as public or serialize it if you want to adjust it from the editor, or you can just remove the two slashes before the radius assignment and you should be good to go. Hope this helps!

“all I need is the character to keep its momentum and rotation and the same jump animation could be used”
This is doable if the transform during the jump is controlled via code, rather than root motion. I’d be willing to bet most game setups that use root motion, do not use root motion for jumping.

“like falling from a cliff” Same - and your guess about separate animations - jump take-off, mid-falling/jumping, jump landing is correct. However if you want even more complexity - it is common to use different animations for falling and mid-jump. Even more complexity - different landing and take off animations for different jump heights and fall distances. :slight_smile:

You might also look into generating root motion in Unity, although I don’t think I’ve read about many having success with rigged characters using this technique.

I can’t figure out how to do the jump. I do understand there is a character controller in unity but it does no use root motion and the goal here is to learn root motion.

We use root motion with unity’s character controller. A lot of code is involved to “weave” everything together. Unfortunatly I can’t share this code but try it and if you have specific problems I’m sure I’ll remember how I fixed them.

Right now I have a forward jump animation, it look like I need forward, left and right to make a blend tree just for the jump. Is this correct? I thought that could be accomplished with only one animation, all I need is the character to keep its momentum and rotation and the same jump animation could be used.

You only need one jump animation, your navigation should allready steer the player in the proper direction, all you need is a layer set to override your nav layer and make sure its got a full body mask.
I suggest transitionning to your jumps from the any state node, itll be easier to manage. ALSO the import settings of your animations are extremely important, you need to RTFM here as you wont get anywhere if you dont get those right (especially the settings affecting root motion like “Bake into pose” and “Based upon”.

Another problem I see is the timing of the animation, the animation can finish and the player might still be in the air, like falling from a cliff. I think the best way to go is to use 3 animations, one for jump, on for midair and on for landing. I have no idea on how to accomplish that with root motion.

THIS is the hard part and most likely why everyone gives up on root motion jumping. I had this crazy Idea of manipulating animation data at runtime to match the jumps to the obstacles we were jumping and It works surprisingly well! But thats not code I can share at the moment. To clarify things, we still have 3 versions of each jumps for different heights but every jump in between heights uses this system + IK to position the hands.

Perhaps I should disable root motion for the animation during the jump and only use for when on the ground?

All depends how much time you got and how scared you are of R&D. I thrive on it.

I thought that could be accomplished with only one animation, all I need is the character to keep its momentum and rotation and the same jump animation could be used.

Animations dont transfer momentum to each other (they only appear to do so when in transition), depending on your animations and the results you are trying to get you sometimes need to manage momentum manually. I’m working on that right now for our falling animation that doesn’t inherit momentum from the long jump anim.

A few hints, momentum can be in the anim or added via code. To keep the orientation of the player at the moment of the jump, make sure the root transform rotation is set to bake into pose in the anim’s import settings, otherwise the animation data will apply any rotation data it has to the root of your player (changing its orientation).

Here is a video demonstrating an early version of the system wihtout IK

Good luck!