Hello everyone,
I have a question regarding the use of Character Controller component. I created a basic movement script which takes the input values and performs a Move() function on a cc component.
cc = GetComponent<CharacterController>();
Vector3 _velocity = Vector3.zero;
_velocity.z = Input.GetAxis("Vertical");
_velocity.x = Input.GetAxis("Horizontal");
_velocity = Vector3.ClampMagnitude(_velocity, 1);
velocity.z = _velocity.z * movementSpeed;
velocity.x = _velocity.x * movementSpeed;
//Applying gravity
if (cc.isGrounded && !jump) { velocity.y = -2; }
else { velocity.y -= 15 * Time.deltaTime; }
cc.Move(transform.TransformVector(velocity) * Time.deltaTime);
It works fine but right know I wanted to extend the functionality of this code and also manipulate the height of the cc collider (e.g. crouching). I am using IK on my character legs and becuase of that I need to adjust the height relative to the lowest feet position. I added this line before performing a Move() function:
cc.height = givenHeight;
cc.Move(transform.TransformVector(velocity) * Time.deltaTime);
And this code works great too… but only when on a flat surface. If the ground beneath the collider is at an angle, changing the height will result in pushing the character in the direction relative to surface normal. I want it to move in Y axis only when changing the height of the cc collider.
To avoid that I decided to change the position of the cc/gameObject, before performing the Move() function:
//I tried also with gameObject.transform.position
cc.transform.position = new Vector3(cc.transform.position.x,
cc.transform.position.y + ((givenHeight - cc.height) / 2),
cc.transform.position.z);
cc.height = givenHeight;
cc.Move(transform.TransformVector(velocity) * Time.deltaTime);
Unfortunately this doesn’t change much and I discovered that performing the Move() function somehow blocks any changes to cc/gameObject position (e.g. to avoid issues with ground check). I couldn’t figure out how to maybe adjust the position of cc/gameObject by calling the Move() function once and not changing how gravity works at a given moment.
I also found that you can change the cc.center value and this works great but not when you are using IK like me. I need to somehow adjust the cc/gameObject position in Y axis only when changing the height of cc collider.
Could You please help me figure out how this could be done correctly? Thank you.
You can just change both the height value and the center position of the character controller component at the same time.
Namely, the center should be at the base of the character controller’s capsule. This is always a y value of half of your height value.
I forgot to add this to the post too I tried also changing the cc.center value instead of the cc.transform.position, there is already a post about this topic. It works great, but does not change the position of the gameObject, but only the height and position of the collider. This is great when You just want to change the collider height and then perform the crouch on the character with animation.
In my case I am also using IK to control leg position apart from the movement code I just showed You. Becuase of that I need to adjust the height of the CC collider so that is shrinks and expands relative to the lowest feet position (without that the feets are floating in the air). Without also adjusting the position of the gameObject, the Move() function does all the translation and thus the issue of pushing the character not only in Y axis appears when standing on a ground that is not flat.
So I’m looking how to somehow adjust the height of CC collider, while changing only the Y position and then perform all of the Move() functionality (effectively making the CC component think it hasn’t even moved).
Wouldn’t IK stuff be separate to the character controller itself? Like if your component with the character controller is also the start of your IK root (or I suppose, the hip joint that starts the IK’s to the legs), then that’s probably not a correct setup. You would probably have your IK root one game object below the character controller component game object.
Thus to crouch, you shrink the controller’s center and the height, and then move the child game object down as well.
I admit I haven’t done IK stuff in Unity, but I imagine it follows the same principles as to when I did 3d animation rigs. You had a root bone (the one you’d use to move the entire rig), with the hip bones a child of that, which you’d use to manipulate the IK’ed legs.
1 Like
I can’t adjust objects (e.g. character joints) inside of the parent object with the cc component on it, because they are controlled by animation (this parent object has also Animator component on it to control whole character movement). The only thing I that is not controlled by animation are the IK controls that I setup for both of the legs.
Since I control my character position by the Move() function anyway (and in the future maybe more complex movement script that relies on cc component), I wanted to adjust the Y position also on the gameObject that uses the cc component.
I will try to change the hierarchy a little bit like You suggested and comeback with a result
That set up still doesn’t seem right. The animator shouldn’t be on the same game object as the controller component. It should be on a child object. Same concept as a 3d animation rig. A top most object moves everything, while objects that need to move in their own way are child objects.
Looking at the character controller I did for a 3d isometric character, the top most game object had the character controller, the next child pivoted the character, and then under that was the actual skeleton with the animator component.
And FWIW, you can just calculate the amount of vertical direction needed to move, and just add that vector to the direction you supply to CharacterController.Move
.
1 Like
You are right that it may seem wrong to use Animator component there, but in my case the Animator component isn’t animating the GameObject it’s attached to anyway (only the bones that are the children of this object), so the CC controls it instead. I wanted to avoid any extra GameObjects beeing used in this character
Big thanks to spiney199. There is no need to even change the height of character controller collider. Instead I put a skeleton root joint (in my case it’s “hips”) into a empty GameObject. Since that object isn’t animated I can safely adjust the position of the whole skeleton:
someEmptyObject.transform.localPosition = new Vector3(0, 0 - givenHeight, 0);
Since I use IK on the legs of my character, adjusting the position of the whole skeleton will result in character go under the ground or fly in the air (the IK won’t keep the feets in it’s position). To prevent that I also control my IK controls the same way, by using an empty GameObject as a parent of these IK controls:
someEmptyIKObject.localPosition = new Vector3(0, 0 + givenHeight, 0);
So with that You can safely separte the code controlling character movement and code controlling e.g. “crouching” with the use of IK. You can even add a Lerp on the givenHeight value to make it go smoothly. Hope this would be helpful for someone
1 Like