- Home /
Flight control without torque/force
The goal:
No physics flying object rotating around it's local z and x axis based on joystick input. So if I pull back, it goes back by a fixed angle. If I push right, it rolls right by fixed angle increments. I don't want to use forces since I want the controls to feel very "tight" without having to counteract all the forces to straighten out the object.
The problem:
I can get it to work along their independent axis. If I push only right at the start, it rotates correctly. If I push only back, it does it correctly. When I start combining the two (doing a bank turn for example) it all goes wack.
I've been hammering away for a while trying to get this to work right, but it just doesn't seem to want to work as expected. For some reason when the transform's "forward" is no longer along the z plane, pulling back has very different behavior than just pulling back. Gifs for reference (you'll note in the second gif, I get off the x and z plane, and when pulling straight back or forward, left or right (values at bottom left of recording) the square moves completely off axis.):
Irregular movements when two axis are combined
The code:
public Rigidbody body;
public int SPEED = 20;
public float tiltAngle = .5f;
public Text debugText;
private float previousX;
private float previousY;
private float previousZ;
....
void FixedUpdate() {
Vector3 forward = body.transform.forward;
Vector3 right = body.transform.right;
// static forward movement (working fine)
body.velocity = new Vector3(SPEED * forward.x, SPEED * forward.y, SPEED * forward.z);
// Inverse tilt angle so it matches with roll left - left on thumbstick
float tiltAroundZ = Input.GetAxis("Horizontal") * -tiltAngle;
float tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
// Modifying tilt around axis to be relative to transforms local axis by
// using it's identity vectors. Likely where the issue is.
previousX += (tiltAroundX * right.x) + (tiltAroundZ * forward.x);
previousY += (tiltAroundX * right.y) + (tiltAroundZ * forward.y);
previousZ += (tiltAroundX * right.z) + (tiltAroundZ * forward.z);
Quaternion target = Quaternion.Euler(previousX, previousY, previousZ);
// Removed slerp since I felt the imprecision might build up from it's actual position
// and the previous x/y/z. Am I wrong in this assumption?
transform.rotation = target;
}
Oh shoot, and now I'm not at my computer that has the other image. I'll try to update it tonight.
Answer by Claite · Oct 14, 2015 at 09:48 AM
Alright, for posterity here's what I eventually settled on. Quaternions weren't working, and I think it's because I kept hitting the gimbal lock problem since my math is bad.
I turned to torque like I had originally ignored, but to get the behavior I want, I reset angular velocity back to 0 every frame. This gives me the sharp start and stop rotation around the appropriate axis without the constant rolling of using forces.
Here's the working code:
void FixedUpdate() {
Vector3 forward = body.transform.forward;
Vector3 right = body.transform.right;
body.velocity = new Vector3(SPEED * forward.x, SPEED * forward.y, SPEED * forward.z);
float tiltAroundZ = Input.GetAxis("Roll") * -tiltAngle;
float tiltAroundY = Input.GetAxis("Horizontal") * tiltAngle;
float tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
body.angularVelocity = Vector3.zero;
body.AddRelativeTorque(tiltAroundX, tiltAroundY, tiltAroundZ);
}
No more needing to save values from previous frames. Thanks for the help.
Answer by FortisVenaliter · Oct 09, 2015 at 02:36 PM
Okay, so for full rotation around all three axes, you're going to need a more elegant solution than euler angles.
What I would recommend is to use the euler angles to make a quaternion for DELTA rotation, or change in rotation. Then simply multiply that on top of your existing rotation quaternion.
So, basically, you want to keep your rotation stored as a quaternion, rather than component euler floats.
Just read up on quaternion multiplication and this seems like it'll be the right answer. From a quick search:
The multiplication of quaternions represents composing the two rotations: perform one rotation and then perform the other one.
Since I'm not at the appropriate computer right computer right now, I won't be able to verify till tonight, but will accept this answer if all goes as expected.
Ok, after working through this, it didn't seem to work. Here's what I had tried:
private Quaternion previous;
void FixedUpdate() {
Vector3 forward = body.transform.forward;
Vector3 right = body.transform.right;
body.velocity = new Vector3(SPEED * forward.x, SPEED * forward.y, SPEED * forward.z);
float tiltAroundZ = Input.GetAxis("Horizontal") * -tiltAngle;
float tiltAroundX = Input.GetAxis("Vertical") * tiltAngle;
float deltaX = (tiltAroundX * right.x) + (tiltAroundZ * forward.x);
float deltaY = (tiltAroundX * right.y) + (tiltAroundZ * forward.y);
float deltaZ = (tiltAroundX * right.z) + (tiltAroundZ * forward.z);
Quaternion target = Quaternion.Euler(deltaX, deltaY, deltaZ);
if (previous != null) {
target = previous * target;
previous = target;
}
transform.rotation = target;
}
Unfortunately, this didn't move the object at all. With several prints, I noticed it was trying to rotate by about 6 degrees, but that's it. I want the object to continue rotating around the axis, so I believe I need incrementing values. The multiplication doesn't seem to be additive, so here's what happens:
previous = (10, 0, 0, 1) target = (10, 0, 0, 1) previous * target = rotate to 10 on x axis, then rotate to 10 on x axis (already there)
So it just rotates to 10. I want it to rotate to 20, which my old code does correctly. The issue is when my deltas for pulling back aren't along the respective planes like (10, 0 ,0) but ins$$anonymous$$d at some off angle like (5, 2, 4) or something.
Thoughts?
Edit: Here is the correct gif of showing the awkward behavior: imgur
Your answer
Follow this Question
Related Questions
How to change controls in-game? 0 Answers
Dampen Flight Controls 1 Answer
Boat's rotation in relation to the rudder 1 Answer
Spaceship Control Help 2 Answers
How to check rigid body vector movement? 0 Answers