#Problem with code? Trying to fix animations (Root Motion)
1 messages ยท Page 1 of 1 (latest)
Making a thread to help clear up the chat for other people
I've actually been stuck on trying to get this root motion movement to work for about 2 weeks now and I still can't figure out where it's going wrong. Even though I now have just used a pre-built animator setup ๐
There's something really wrong with a setting or code or something
I'll show what the readme for the animator says which is
The graph is controlled by 3 variables:
-
InputMagnitude
This is a float that should be controlled by Input Axis Vector Magnitude (so for example, how far is the joystick bent). It controls the transitions between Idling and running. -
InputDirection
This is a float that should be controlled by the angle between character's Forward Axis and the Input Axis Vector. So for example, if the joystick is bent right, the angle will be 90 degrees, if back, the angle will be 180 degrees and so on. -
IsRightLegUp
This is a bool that should be controlled by which foot is currently higher in a run cycle, so the controller knows which animation it should play while stopping. Easiest way to get this info is checking which foot bone has a bigger Global Transform Y at the moment. So, if right foot is higher - we change IsRightLegUp to true.
So, if anyone can see where I'm going wrong, I would greatly love some help ๐ญ
Problem with code? Trying to fix animations (Root Motion)
based on the video, it look like it might be related to the camera. I see this line in the code: // Camera relative movement var move = mainCamera.right * moveInput.x+ mainCamera.forward * moveInput.y; but I don't see where you adjust the camera facing direction (assume in a different script).. it look almost like a feedback thing going on .. when you turn left hard, the camera turns fast, then you turn "harder". I'd test this by making that line use transform.right and transform.forward, rather than the mainCamera.right/forward.
I feel like you might be onto something with the camera affecting things somehow.
I've just done as you suggested so it looks this now
// Camera relative movement
var move = transform.right * moveInput.x+ transform.forward * moveInput.y;
move.y = 0;
The movement still seems to be the same as the above video so I don't think it appears to have really changed anything. But yeah, I do feel like it could possibly be a camera thing somehow
What I've noticed just now, is maybe something is wrong with Input Direction? Looking at the animator parameters, it doesn't seem to receive a constant input?
For example, I am holding right, the inputdirection initially increases, but then starts to 0 out so my character just starts running straight even though I am trying to go right
I dont see where it actually changes the character's facing dir...
https://gyazo.com/6f9c966e7b31226bf955ab1f96581ecc
Sort of shows how it zeros out
Give me a moment and I'll try to find where the change is happening, it's been a little bit since I looked at camera stuff
From looking through, my only other thing I can find, is the empty object I attached to the character as a target, so that when the object rotates (with mouse) etc, the camera rotates also
using UnityEngine;
using UnityEngine.InputSystem;
public class CameraController : MonoBehaviour
{
public InputActionReference lookAction;
public InputActionReference aimAction;
public Transform cameraTransform;
public Transform aimCamTransform;
public Animator animator;
public float xSens = 2.5f;
public float ySens = 2.5f;
public float yMinLimit = -20;
public float yMaxLimit = 80;
public float centerWaitTime = 2f;
public float centerSpeed = 5f;
private float centerTimer;
private float xRotation;
private float yRotation;
private float aimLayerWeight;
private void Start()
{
var rot = transform.rotation.eulerAngles;
xRotation = rot.x;
yRotation = rot.y;
}
private void Update()
{
var input = aimAction.action.IsPressed();
cameraTransform.gameObject.SetActive(!input);
aimCamTransform.gameObject.SetActive(input);
aimLayerWeight = Mathf.Lerp(aimLayerWeight, input ? 1 : 0, Time.deltaTime * 5);
animator.SetLayerWeight(1, aimLayerWeight);
}
private void LateUpdate()
{
var input = lookAction.action.ReadValue<Vector2>();
if (input.magnitude < 0.01f)
{
centerTimer += Time.deltaTime;
if (centerTimer > centerWaitTime)
{
xRotation = Mathf.LerpAngle(xRotation, 0, Time.deltaTime * centerSpeed);
yRotation = Mathf.LerpAngle(yRotation, 0, Time.deltaTime * centerSpeed);
}
}
else
{
centerTimer = 0;
}
xRotation += input.x * xSens;
yRotation -= input.y * ySens;
yRotation = ClampAngle(yRotation, yMinLimit, yMaxLimit);
var rotation = Quaternion.AngleAxis(xRotation, Vector3.up) * Quaternion.AngleAxis(yRotation, Vector3.right);
transform.localRotation = rotation;
}
private float ClampAngle(float angle, float min, float max)
{
if (angle < -360) angle += 360;
if (angle > 360) angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
Vector3 inputAxisVector = new Vector3(moveInput.x, 0, moveInput.y); angle = Vector3.SignedAngle(transform.forward, inputAxisVector, Vector3.up); your turn angle is NOT relative to the transform.forward.. it's moveInput is relative to Vector2(0,1) no?
(left on the joystick means turn left 90. regardless of direction char is facing...)
you used Atan2 else where ... I think that's the way to go here too
private void UpdateDirection()
{
// Camera relative movement
var move = transform.right * moveInput.x+ transform.forward * moveInput.y;
// var move = mainCamera.right * moveInput.x+ mainCamera.forward * moveInput.y;
move.y = 0;
// Transforming to local space of character
// move = transform.InverseTransformDirection(move);
forward = move.z;
lateral = move.x;
turn = Mathf.Atan2(move.x, move.z);
At the bottom there
unless I misunderstand what inputDirection is.. is that a world-space angle or "how much to turn"?
So basically, after troubleshooting a bunch. I tried to go with a different animation pack to sorta elimate the pack as an issue.
This pack comes with a basic controller already set up and this is what the readme says
The graph is controlled by 4 variables:
-
InputMagnitude
This is a float that should be controlled by Input Axis Vector Magnitude (so for example, how far is the joystick bent). It controls the transitions between Idling and running. -
InputDirection
This is a float that should be controlled by the angle between character's Forward Axis and the Input Axis Vector. So for example, if the joystick is bent right, the angle will be 90 degrees, if back, the angle will be 180 degrees and so on. -
IsRightLegUp
This is a bool that should be controlled by which foot is currently higher in a run cycle, so the controller knows which animation it should play while stopping. Easiest way to get this info is checking which foot bone has a bigger Global Transform Y at the moment. So, if right foot is higher - we change IsRightLegUp to true.
So really, direction and magnitude are what I was trying to go for so that I could make the controller work as intended
(Says controlled by 4 variables in the readme but it only is 3)
" if the joystick is bent right, the angle will be 90 degrees, if back, the angle will be 180 degrees and so on." ya sounds like atan2 using the joystick inut is the way to go here
It ofc talks about joystick etc, but just to sort of make sure as I'm not sure if this is a conflicting thing, but I'm not using a joystick or anything and want it work kb/m
same diff, but keyboard will just be 1,0,-1 for each axis. mouse... hmmm not sure there
First time trying to work with root motion as well as being a bit fresh to Unity as well, so trying to come to grips with everything ๐
As for this, what lines would you recommend changing now then?
Mouse isn't a big worry right now, I can ignore camera related movement or such for the moment
I just want to be able to have the smooth animator with wasd for now before I progress
I'm SUPER rusty on animator stuff to be honest, but I know transforms and vectors well enough. inputDirection =Mathf.Atan2(moveInput.x, moveInput.y);
give that a go.. not sure how it'll do, but worth a shot
Sure
// Calculate input magnitude and direction
inputMagnitude = moveInput.magnitude;
Vector3 inputAxisVector = new Vector3(moveInput.x, 0, moveInput.y);
angle = Vector3.SignedAngle(transform.forward, inputAxisVector, Vector3.up);
inputDirection = Mathf.Atan2(moveInput.x, moveInput.y);
Like this then yeah?
will help us figure out what might be wroing if it doesn't
I dont think you need "angle"
just use inputDirection
but yes
https://gyazo.com/d897f4a095fd4fbd7376b3a08ebb3e11
So he's not turning
InputDirection is getting some values, but me holding A gives a -1.5
D = 1.5
And then S at the end seems to be roughly 3
0.7 was the number when I held W & D to go FL
Ohhhh
Okay
So yeah, it looks like that did it for the most part
The character is still "snapping" in movement
Which is a problem
But general trajectory seems to be on point
Not sure the snapping is something I can fix with code or if it is an animator only thing currently
The controller is prebuilt so I imagine, it should be working fine without snaps
I fear that snapping may be outa my skill range- animator stuff. but I'd GUESS it's cuz your using a keybaord. which is gonna be 0 or 1 for any given direction... so even combining keys tere is only like 8 diff dirctions you can go
one option: we can check when a direction key is first pressed, then, over some specified amount of time, drive it from 0 to 1 (while it's held down).
Yeah that sounds like it could be something possibly
^ it : the input(s) to the Atan2 function
we can also try with the mouse.. just need to make sure the value we get from it is somewhere between -1,-1 and 1,1 .. not quite sure how to do that... hmm
is that what the black dot is for?
dragging it to turn and stuff?
Oh na sorry lol, the black dot is actually irrelevant.
It was a placeholder thing for a crosshair and shouldnt be there right now
I've just been ignoring it while trying to do the animations
lol, I do that stuff all the time tooo
Yeah I tried getting rid of it, but it's from cinemachine 3rd person aim script, and I cant quite understand how cinemachine is wanting it to work
Even disabling the original image of that block dot doesnt do anything
As for this, how was you meaning exactly?
Sorry, not too sure what this would look like code wise
this was for driving the input from 0 to 1 over a peroid of time, rather than going from 0 to 1 instantly, like the keyboard currently does. so, right now we are calling Atan2(a,b) with only 1,-1 and 0 as possible values for a and b. If we drive it slowly, we'd pass the slowly driven values into the Atan2 function.
bah.. was that understandable at all?
Yeah that makes perfect sense in the theory. No problem at all, it's just a problem on my end knowing how to implement it ๐
ah! well, step 1- we need to remember what moveInput was LAST frame. then we can see if it's changed.
step 2- when we see a change, we make note of the current Time.time. We'll also need a new member to store how long the change should take.
Every time "Last frame" is mentioned, I feel like I've never quite grasped how people check that
On a side note, just wanted to give you some praise on your knowledge also. Seems like you are really well versed
step 3 - interpolate between the previous moveInput and the current moveInput, over that time period.
oh, I'm an old man now- programming since the 80's ๐
๐
Ah fair enough, I'm still fresh to it myself, only been at it for a couple of years in University. But never get to sit down and spend a long period of time on one language or something in particular
there is just SO MUCH programming stuff to learn out there! I'd be usesless at most of it.
Yeah completely true ๐
It really is a bit overwhelming to look at the broad scope of things
even in JUST unity... animations for example- I'm useless
might be a way to do this over time thing right in there for all I know.
Yeah, I've been following video tutorials for root motion and that for ages now. Even when I fully follow what it shows, I still run into these problems which is usually unexpected
Just realised though, I do have a controller sitting around
whats your major, btw, CS?
So I might quickly try to use the joystick, just to give it a go and see if the outcome differs
Yeah CS
In my final year now, working to make something in Unity is what I wanted to do as a project idea
Anyone else that also picked Unity chose to do a 2D one for theirs though, so I picked a much tougher choice ๐
cool! FYI some joysticks are ALSO digital meaning only 1 or 0, so figers crossed
I'll have to set it up on the input manager also, as I only have my kb map currently
alright bud, I'm out for now- but ping me if ya need!