Manipulating individual components of a quaternion is almost never what you want to do.
The three imaginary components of the quaternion (x, y, z) describe your axis of rotation, and the real component (w) describes how much to rotate around it, subject to the constraint that the whole 4-vector has a length of 1 (so as you change the rotation angle, the axis vector grows and shrinks). So changing just one component doesn't make sense - the different parts of the quaternion have to change in concert.
Instead, you generally want to use the convenience methods of the Quaternion
class to do your operations - which ends up making for much clearer and more intuitive code, as a bonus.
Quaternion ClampRoll(Quaternion orientation, float minRoll, float maxRoll) {
// Find which direction the z+ axis of this orientation points in the world.
Vector3 forward = orientation * Vector3.forward;
// Form a reference orientation with no roll, looking in that direction.
Quaternion noRoll = Quaternion.LookRotation(forward, Vector3.up);
// Use this to isolate just the roll part of our orientation, removing everything else.
Quaternion rollAlone = orientation * Quaternion.Inverse(noRoll);
// Now we know we have the z angles alone, with no other confounding factors.
// Use DeltaAngle to get it in the range -180...180
float rollAngle = Mathf.DeltaAngle(0, orientation.eulerAngles.z);
// Now we can clamp it into our desired range.
float clamped = Mathf.Clamp(rollAngle, minRoll, maxRoll);
// And fold it back into our roll-free rotation to finish the job.
return noRoll * Quaternion.Euler(0, 0, clamped);
}
You might be able to skip the first few steps there, but myself I don't trust the way Euler angles wrap around, which can lead to unexpected behaviour. So I like to isolate just the rotation angle I care about, relative to the identity orientation, to minimize the potential for surprises in a corner case I didn't think about. ;)