- Home /
Aligning a rigidbody smoothly with the perpendicular of a vector angle
So I've been struggling a number of hours on this one (however, most of that was due to the fact that I didn't realise Atan2 existed). Anyways, my goal is to be able to keep a rigidbody perpendicular to the vector angle of it's Z-axis, in a way that looks smooth. Particularly, I'd like to be able to change the rigidbody's z-rotation at a rate proportional to the distance between the current z-rotation and the vector-based angle. The end effect should be able to let a player go around a loop (if they have enough momentum) and keep their feet to the floor (think Sonic the hedgehog).
Here's what I have so far (in C#):
public void adjustZRotation(float xVelocity, float yVelocity){
Vector3 newPosition = new Vector3(transform.position.x, transform.position.y - 1.5f, transform.position.z);
//Don't change Z Rotation if there is nothing 1 unit under the player (linecast starts from the middle of player)
if (Physics.Linecast(transform.position, newPosition)){
//Get the angle (in degrees) of the combined x and y vector.
float zAngle = Mathf.Atan2(xVelocity, yVelocity) * 180/Mathf.PI;
//Make zAngle represent a full positive 360 degrees
if(zAngle < 0){
zAngle = -zAngle;
}else{
zAngle = 360.0f - zAngle;
}
//If the player's vector-based z-angle is the same as their real rotation z-angle, then do nothing.
if(zAngle == transform.eulerAngles.z){
return;
}
else{
//Set the new Z-axis rotation perpendicular to the zAngle
transform.rotation = Quaternion.Euler(0, 0, zAngle + 90.0f);
//If possible push against the zAngle for a more gentle change.
//###Currently overshooting desired results###
//if(transform.eulerAngles.z > zAngle){
// Quaternion deltaRotation = Quaternion.Euler(new Vector3(0, ((transform.eulerAngles.z - zAngle) / 2), 0) * Time.deltaTime);
// rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);
//}
//else{
// Quaternion deltaRotation = Quaternion.Euler(new Vector3(0, ((zAngle - transform.eulerAngles.z) / 2), 0) * Time.deltaTime);
// rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);
//}
}
}
}//adjustZRotation
Unfortunately this function doesn't work quite like I'd like. It does keep the rigidbody perpendicular to the angle I want, however it is extremely rigid (no pun intended) and a bit fidgety (although some of that is due to the linecasting I do).
So the question is: Is there a way to do this smoothly? Or am I going about this the wrong way? I added some of my experimental code as a comment, but in it's current state it often rotates the rigidbody too much or too little. On a positive note rigidbody.MoveRotation does seem to take care of the smoothness issue.
Thanks for everything!
I'm not sure if I understand that correctly. When your character runs through a loop, you want his rotation to be aligned with the face normal at that position?
Essentially yes, but I want to do it without the "jerky" look that comes from directly modifying transform.rotation as I currently do.
Would that fit your needs? :
Get the ground normal by casting a ray to character.down (-Vector3.up) and get the normal vector from the hitting face of the ground.
Get the angle of the normal vector by using Vector3.Angle
LerpAngle from the characters rotation to the desired rotation.
And I would say in most cases if you have a rigidbody attached, you want to use $$anonymous$$oveRotation or $$anonymous$$ovePosition ins$$anonymous$$d of the transform values.
Your answer
Follow this Question
Related Questions
How might I rotate rigidbody momentum? 4 Answers
How to make a RigidBody not go into ground when tilted foward? 2 Answers
Undesirable character flipping 0 Answers
Smooth 2D rotation unexpected 1 Answer