I have a planet that I want to allow the player to rotate (with the camera in a fixed position). The player is able to rotate the planet freely horizontally, so they can spin it as much as they want. However, I want to limit how far they can rotate the planet vertically to keep the player from turning the planet upside down. The following code does what I want for the limit on vertical rotation, but it also resets the horizontal rotation back to where it was when the game started:
if (tiltAngle > 45.0f) { // If tiltAngle is greater than 45 degrees...
if (tiltAngle * sign < 0.0f) { // ...and if tiltAngle is negative...
transform.eulerAngles = new Vector3(-45.0f, 0.0f, 0.0f); // Set rotation to -45 degrees.
}
else if (tiltAngle * sign > 0.0f) { // ...else if tiltAngle is positive...
transform.eulerAngles = new Vector3(45.0f, 0.0f, 0.0f); // Set rotation to 45 degrees.
}
}
I tried changing the code to the following, but that just made really weird stuff happen to the planet when the limit was reached (including allowing the player to rotate vertically beyond the set limit):
if (tiltAngle > 45.0f) { // If tiltAngle is greater than 45 degrees...
if (tiltAngle * sign < 0.0f) { // ...and if tiltAngle is negative...
transform.eulerAngles = new Vector3(-45.0f, transform.localEulerAngles.x, transform.localEulerAngles.y); // Set rotation to -45 degrees.
}
else if (tiltAngle * sign > 0.0f) { // ...else if tiltAngle is positive...
transform.eulerAngles = new Vector3(45.0f, transform.localEulerAngles.x, transform.localEulerAngles.y); // Set rotation to 45 degrees.
}
}
I am obviously missing something (and it is probably something incredibly simple). I am just wondering how I can reliably limit the planet’s vertical rotation while still keeping the horizontal rotation where it currently is.
Update I came back to this script and did some more fiddling. I now have it working better, though the vertical rotation is rather jerky around the limits as the script fights against the player’s input to keep the rotation within limits. I am currently thinking about a way to pre-qualify the vertical rotation input to make sure it won’t put the planet outside of the limits instead of trying to correct the rotation after it has already gone out of the limits.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PlanetController : MonoBehaviour {
public float rotationSpeed; // Modifier for the speed at which the planet will rotate.
private float tiltAngle; // Stores how far the planet has been tilted.
void Start() {
tiltAngle = 0.0f;
}
void Update() {
}
// RotatePlanet() is called to rotate the planet. It receives a Vector2 value indicating the player's input since the last
// update.
public void RotatePlanet(Vector2 deltaMove) {
transform.Rotate(0.0f, deltaMove.x * rotationSpeed * -1.0f, 0.0f, Space.Self); // Allow horizontal input to rotate only
// around the planet's vertical axis.
tiltAngle = Vector3.Angle(Vector3.up, transform.up); // Calculate how far the planet has been tilted.
if (tiltAngle < 45.0f && deltaMove.y != 0.0f) {
transform.Rotate(deltaMove.y * rotationSpeed, 0.0f, 0.0f, Space.World); // Allow vertical input to rotate around the
// game world's horizontal axis.
}
else if (tiltAngle >= 45.0f) { // If the planet has been tilted to or past 45 degrees...
float sign = Mathf.Sign(Vector3.Dot(Vector3.right, Vector3.Cross(Vector3.up, transform.up))); // Calculate
// which direction the planet has been tilted.
if (tiltAngle * sign < 0.0f) { // If tiltAngle is negative...
transform.Rotate(rotationSpeed, 0.0f, 0.0f, Space.World); // Rotate planet back within limits.
}
else if (tiltAngle * sign >= 0.0f) { // ...else if tiltAngle is positive...
transform.Rotate(-rotationSpeed, 0.0f, 0.0f, Space.World); // Rotate planet back within limits.
}
}
}
}
My apologies for not including more of the code. The entire script is fairly short, so I will include it here*. I am not using tiltAngle to rotate the planet, but just to see how far it has rotated. If I use Mathf.Clamp on tiltAngle, how would I then send the result back into the planet's transform? Everything works as I need it to with the exception of the limiting aspect to the vertical rotation. Edit Moved the full code for my script into my question.
– Tim_LAh I see, yes Clamp probably wouldn't work for that. I actually think the only problem is actually that you have x and y euler angles in the y and z spots.
– TehJusticeHmm, it's probably that you're cancelling out the transform.Rotate calls when you set the eulerAngles. You may need to rework it so that you only vertical rotate between the two numbers and just get rid of the eulerangles. some pseudocode: if (tiltAngle > 45 && deltaMove.y > 0) { transform.RotateVertical(...); } if (tiltAngle < -45 && deltaMove.y < 0 { transform.RotateVertical(...); }
– TehJusticeThat might work, though I need to make the rotation in order to check how far the planet has tilted. Although, it may work just as well using the tiltAngle information from the previous update... I'll play around with it some more when I get in tomorrow. Unity just crashed on me, so I think I'm at a good stopping point. :)
– Tim_LI re-wrote the script to incorporate your idea and, while the rotation is working better now, it is still somewhat unpredictable when rotating to the vertical limits. I am not too worried about it right now, but I can see that I will need to spend some time on this when I move from prototyping to development. The problem does not seem to be with the script's ability to catch when the vertical rotation goes out of limits. It is when I try to nudge the rotation back within the limits that the problem starts to occur.
– Tim_L