szopaw
1
I’m trying to make a battleship with turrets, like this:
I have the code to rotate the turrets to a pointer on the screen, which is this
public float rotationspeed = 200;
public Transform turret;
private Vector3 reticlepos;
public Camera cam;
// Update is called once per frame
void Update()
{
reticle();
Vector3 turretlookdir = reticlepos - turret.position;
turretlookdir.y = 0f;
turret.rotation = Quaternion.LookRotation(turretlookdir);
}
private void OnDrawGizmos()
{
Gizmos.DrawSphere(reticlepos, 0.2f);
}
public void reticle()
{
Ray screenRay = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(screenRay, out hit))
{
reticlepos = hit.point;
}
}
There’s no problem with this script, it works fine when applied without changes to both turrets
Right now they obviously rotate a full 360 and clip through the “tower”.
What I want to do, is to limit the rotation of these turrets to a specific range of angles, let’s say -135 to 135 degrees from their starting position, to imitate the fact that they can NOT clip through the tower. I’d like to be able to make a general solution, one-script-fits-all, that reads the initial rotation of the turret, then applies the limitation. That’s because I plan on having multiple turrets at various locations, with various limits. It would be easier to be able to just change a few variables and have the code read the rest from the object than to try to code each separately, by hand.
I’ve been reading all sorts of discussions on how to Clamp a rotation, but none of them seem to be applicable to LookRotation, I can’t figure out how to insert those angles into this method, since it reads a vector. And if there’s a way to limit this rotation by limiting the Vector, I haven’t found that either.
Calculate the targetRotation using Quaternion.LookRotation then extract the Euler angles from targetRotation and clamp each angle individually to the desired range using Mathf.Clamp. Finally, create a new Quaternion from the clamped Euler angles and assign it to the turret’s rotation.
// Calculate the target rotation using Quaternion.LookRotation
Quaternion targetRotation = Quaternion.LookRotation(turretlookdir);
// Clamp the rotation angles to the desired range
Vector3 euler = targetRotation.eulerAngles;
euler.x = Mathf.Clamp(euler.x, minAngle, maxAngle);
euler.y = Mathf.Clamp(euler.y, minAngle, maxAngle);
euler.z = Mathf.Clamp(euler.z, minAngle, maxAngle);
targetRotation = Quaternion.Euler(euler);
turret.rotation = targetRotation;
szopaw
3
Just in case anyone has a solution that avoids it, Nazirzadeh’s way runs into the issue that when the eulerAngles crosses below zero, it turns straight up to <360, because that’s how that statement works.
So trying to set any minimum value that’s “lower” (i.e. rotates past into “negative”) immediately snaps to the max clamped value (and EXACTLY the max clamped value, in degrees between 0 and 360) instead, like this:
In this case, both turrents are clamping on 135 degrees the moment they cross their individual 0, because that’s the highest allowed value.
I don’t know how else to set the proper values so that it will work for both turrets in one script, because even if I try to “move the zero” behind the turret by appling an additional “fake” angle to the eulerAngles like this:
startrot = turret.localRotation.eulerAngles.y+angle;
Quaternion lookrotation = Quaternion.LookRotation(turretlookdir);
float euler = lookrotation.eulerAngles.y;
euler = Mathf.Clamp(euler+angle, startrot-135f, startrot+135f);
turret.localRotation = Quaternion.Euler(0, euler, 0);
It just misaligns the turrets from LookRotation if it’s anything but a multiple of 360, multiples of 360 have the exact same issue of jumping BY 360.
And even when forcing it to work by also shifting LookRotation to align with the turrets, it only works for ONE turret because the other passes through 0 exactly 180 degrees offset, or when it’s facing it’s own start direction.
The problem here isn’t with the LookRotation itself , i think it’s more of an approach issue.
If you wanna deal with angle comparisons and clamping , i think it’s better to stick to 2D and 3D maths instead of Quaternions (which are 4D) and only use quaternions for what they are best at , lerping towards angles and stacking rotations.
What i would do is i would first project the mouse position on a plane parallel to the towers and then do all my maths and angle rotations on that , pretty much flattening it all onto the plane to do my angle clamping stuff.
Once that’s done you can take the clamped 2D point on the plane and convert it to a 3D vector that you finally plug into LookRotation.
I think the figure i added below should help