- Home /
Help with upside-down rotation
TL;DR Here's a video of the issue around the 0:05 mark : https://www.youtube.com/watch?v=YtqWx68WJpQ
I'm just trying to iron out some of the issues I've been running into lately. Not quite sure why the object does a rotation at specific angles, as if it's avoiding crossing certain values or something.
The way I have it set up is that there's a parent which controls the magnetic forces, normal rotation, and other rigidbody forces. On Awake(), a prefab containing the car model and collider is instanced at the origin of the parent.
I'm also running a Cinemachine camera...not sure if that would have any effect on things. If you have any thoughts about this, I'd be happy to hear it!
EDIT: Okay, so I have a few functions that handle rotations:
void Update()
{
//Turning Input
if (Input.GetAxis("Horizontal") != 0)
{
int dir = Input.GetAxis("Horizontal") > 0 ? 1 : -1;
float amount = Mathf.Abs((Input.GetAxis("Horizontal")));
Steer(dir, amount);
}
currentRotate = Mathf.Lerp(currentRotate, rotate, Time.deltaTime * rotSpeed); rotate = 0f;
}
void FixedUpdate()
{
CheckMagnet();
AlignToGround();
Turning();
}
void Turning()
{
//add torque relative to the currentRotate value
rb.AddTorque(transform.up * currentRotate * Time.deltaTime * rotSpeed);
}
public void Steer(int direction, float amount)
{
//calculate angle from current angle in the left or right direction
rotate = (steer * direction) * amount;
}
void CheckMagnet()
{
//Set the mask layer
mask = 1 << LayerMask.NameToLayer("TrackMask");
//Check if there is a track beneath the player
magnetized = Physics.Raycast(transform.position, -transform.up, out magHit, magnetRange, mask);
//Shoot four rays downwards in four directions
Physics.Raycast(transform.position + (transform.up * .1f) + (transform.forward * groundCheckDistance), -transform.up, out hitF, magnetRange, mask);
Physics.Raycast(transform.position + (transform.up * .1f) + (transform.forward * -groundCheckDistance), -transform.up, out hitB, magnetRange, mask);
Physics.Raycast(transform.position + (transform.up * .1f) + (transform.right * -groundCheckDistance), -transform.up, out hitL, magnetRange, mask);
Physics.Raycast(transform.position + (transform.up * .1f) + (transform.right * groundCheckDistance), -transform.up, out hitR, magnetRange, mask);
//Calculate the average of the raycast hit normals
Vector3 avNorm = (hitF.normal + hitB.normal + hitL.normal + hitR.normal) / 4f;
//Store the rotation
rotateToRoad = Quaternion.FromToRotation(transform.up, avNorm) * transform.rotation;
}
void AlignToGround()
{
//If there is track beneath the player
if (magnetized)
{
//move rigidbody to the hover height
rb.MovePosition(Vector3.Lerp(rb.position, transform.up * hoverHeight + magHit.point, hoverSpeed));
//rotate to the surface normal
rb.MoveRotation(Quaternion.Lerp(rb.rotation, rotateToRoad, alignSpeed));
}
else
{
//Fall with normal gravity and orient self
rb.MoveRotation(Quaternion.Slerp(rb.rotation, Quaternion.LookRotation(rb.velocity.normalized, Vector3.up), 0.025f));
rb.AddForce(Vector3.down * fakeGravity, ForceMode.Acceleration);
}
}
The most valuable information you could provide in this situation is how you're rotating your car. While a script sample would be the most direct, it never hurts to add other details where you think they might be applicable.
In short, you're controlling various forces... In what manner? There are numerous ways to control them, and various orders of operations to do so. With that in $$anonymous$$d, in fact, it's actually tough to even know whether it would necessarily be *just* the "turning function" unless any of your other functions also have a direct influence on your rotation.
Thanks for the reply! I just added the relevant code regarding player rotations. Apologies if it's a mess, hopefully the comments help... Believe me, it was much worse earlier on in the project.
Essentially, the object, if it's magnetized, finds the average normal below and rotates to align itself to that while positioning a certain height above the track. It does all of that before executing the turning function where it adds the "yaw" torque force.
Let me know if there's anything else that needs clarifying! One concern that I do have is that there are a lot of crisscrossing functions that all sort of need each other but have to occur in a particular order, so maybe something is going wrong there?
I have not understood it well, you say that it collides and when it bounces it changes direction suddenly?
Thanks for commenting, hopefully I can clarify further! I'm referring to the moment right before hitting the red wall. I made a small gif of the specific issue. This rotation wobble happens any time that the player rotates upside-down for some reason
Are you use addforce and set it on true direction? try to draw line your direction of your addforce, or maybe it your gravity is too high, disable for test.
Answer by Jinkel92 · Feb 09, 2021 at 03:22 AM
That strange wobble is from camera, the cinemachine can follow the player in any options I think. Try adjust the parameters of the cine camera or simply try add your camera as a child of the player without the cinemachine component or parent it and just dismark the follow option.
That's so weird! The culprit was the Y Damping option under the Transposer tab!
As you suggested, I attached a regular camera as a child to the player and that worked perfectly, so I thought that there had to be some setting in Cinemachine that is the meaning of that wobble. Turns out it was a simple answer, AND it helped rid of a lot of jittery-ness as well!
Thanks so much, I really do appreciate the help :)
Answer by Eno-Khaon · Feb 09, 2021 at 04:10 AM
(To note, I don't have experience with the Cinemachine camera, so this perspective doesn't take it into consideration)
On first impression, I suspect that you're getting strange results from angular velocity as you apply your local rotation change through torque. On flat ground, you would see expected results, in that you would ease rotation toward the local right or left facing.
However, this breaks down when your pitch (X-axis rotation) changes, and the angular velocity is no longer aligned to your current flat-level axis. Your rotation from torque, especially when changing orientation rapidly in a loop, can then interfere with your expected rotation. You "correct" most of this by using Rigidbody.MoveRotation(), but that doesn't negate the angular velocity; it just hides most of its influence.
You may want to consider re-orienting your angular velocity before applying the new steering torque, since you're already forcing your rotation before letting torque handle the rest. I'm not in a position to verify this code at the moment, but it would be about as simple as:
// in AlignToGround()
rb.angularVelocity = rotateToRoad * rb.angularVelocity;
Oh, I just updated the answer and saw this suggestion. Thank you for your help, regardless! There definitely are a lot of loose ends/inefficiencies in this movement script, like not addressing the angular velocity in the rotation, or jittery movement over lots of uneven polys, so I appreciate that you spent the time to look over this particular aspect!