3
\$\begingroup\$

enter image description here

I am trying to make a game with unity.

In this game, player uses mouse to rotate a container or box around x and z (rotate to left and right and also toward the camera and opposite).

I used below code to control movement and limit it.

float zRot = transform.eulerAngles.z;
float xRot = transform.eulerAngles.x;
float yRot = transform.eulerAngles.y;
Debug.Log (
  "xDir : "  + xRot.ToString() + 
  " yDir : " + yRot.ToString() + 
  " zDir : " + zRot.ToString() );

if ((xRot >= 330 || xRot <= 30) && (zRot >= 330 || zRot <= 30)) {
  transform.Rotate (Input.GetAxis ("Mouse Y"), 0, -Input.GetAxis ("Mouse X"));
}   
else {
  Debug.Log(xRot.ToString() + "  " + zRot.ToString ());

  transform.Rotate (-transform.rotation.x , transform.rotation.y,-transform.rotation.z );     
} 

The contatiner rotate 60 degrees in x and z and when it gets to the limits it stops, which is what I want. However when I rotate in both direction to the near the limits (330 or 30), the contatiner becomes out of control and it rotates freely and constantly. It's like the contatiner has passed the limits.

The questions are:

  • Did I used a good approach to limit the rotation and how to stop the object completely when it get to the limit of rotation?
  • When and why the object becomes out of control exactly?
\$\endgroup\$
  • 1
    \$\begingroup\$ Surely you will be then within your else statement. What's transform.rotation.x ,. y and .z respectively? Change them to transform.Rotate (0, 0,0 ) and see if the error still persists. If not, it would appear that something changes your transform.rotation, which may be a problem with your code/memory leak etc. My second (long shot) guess is (although it is not clear what you mean with both directions), that once you pass the threshold to one direction, the angle may change to a negative number or a number greater than 360, e.g. 390. Make sure your angle returns the modulus of 360. \$\endgroup\$ – Majte Oct 19 '15 at 23:20
  • \$\begingroup\$ @Matje I think your second guess is nearer to the problem. For example Assume a condition that mouse move to end limit of left side and end limit of up. \$\endgroup\$ – klaymen Oct 20 '15 at 17:55
  • \$\begingroup\$ I have a callback to my mouse to object angle that always goes from 0 to positive 360. Try implementing this, using fmod(angle,360) and if angle<0 angle = 360+angle; \$\endgroup\$ – Majte Oct 20 '15 at 18:18
2
\$\begingroup\$

The issue with using transform.Rotate() is you're cumulating rotations; once the object is rotated on one axis, the other axis then rotates it at an angle which isn't the original intended axis.

It's kinda hard to explain but try this:

  • Take a dice,
  • rotate it forward 90 degrees,
  • then right 90 degrees,
  • then backward 90 degrees,
  • then left 90 degrees

and it's NOT back to the same orientation. For more info see Gimbal lock, there are a lot of issues using Euler angles for doing rotations.

Instead I would use the Transform.LookAt(Vector3 pos, Vector3 Up) or Quaternion.LookRotation function:

float limit_x = 1;
float limit_y = 1;
float mouse_scale = ???; // figure this one out through experimentation

y += Input.GetAxis ("Mouse Y") * mouse_scale;
x += -Input.GetAxis ("Mouse X") * mouse_scale;

x = Mathf.Clamp(x, -limit_x, limit_x);
y = Mathf.Clamp(y, -limit_y, limit_y);

transform.rotation = Quaternion.LookRotation(Vector3.forward + new Vector3(0, x, 0), Vector3.up + new Vector3(y, 0, 0));

What this does is create a rotation where the object's Z axis points at the first parameter (a direction), and the object's Y axis to the second parameter (also a direction, what is "up" for the object). (The X axis automatically point at 90 degrees to both Y and Z.)

We're passing the Z direction as (0, 0, 1) + (0, x, 0) so we're changing "forward" to point slightly up or down.

We're passing the Y direction as (0, 1, 0) + (y, 0, 0) so we're changing "up" to point slightly left or right.

This trick is non-linear and you cannot rotate completely around (in this case I'm limiting to 45 degrees both axis) but for a tilt-box this has worked well enough for me.

If you need proper linear rotation use:

transform.rotation = Quaternion.AngleAxis(x, Vector3.z) * Quaternion.AngleAxis(y, Vector3.x);

y and x are in degrees with this so limit_x and limit_y should be adjusted accordingly (e.g. 45)

Depending on how your world & object are oriented you might need to change the angles of rotation.

\$\endgroup\$
  • \$\begingroup\$ your example about dice show that you understand problem. I should try this. Thanks. \$\endgroup\$ – klaymen Oct 20 '15 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.