Look At objects using a SNAPPED angle

I’m wondering how I can make a gun turret point at an enemy but only at 90 deg angles and not constantly but every 2 seconds. The 2 second part will be Invoked but on every 2 seconds I want the gun to ‘snap’ to the enemy direction using only 90 degree snapped turns, like North,Nth East, East, South, Sth East etc, and nothing inbetween. Had a quick attempt using a stand-in Cube with Transform.LookAt but the snapping has me stumped.
Any suggestions ?

There are three parts. The easier is, if you have an angle, how do you aim that way:

float A; // some angle we figured out, happens to be 0,45,90...
transform.rotation = Quaternion.Euler(0,A,0);

A harder one is how to figure out the 0-360 angle to your target. One obvious way is with 8 ifs, one for each 45-degree section. The problem is, you can tell between 0 and 90 degrees by whether x or z is larger. Between 0 and 45 degrees, you need to check the tangent to see which side of 22.5 degrees you are on. Ick.

Unity stuff like Quaternion.Angle() gives the “off by” angle – it can’t tell 45 degrees left from 45 degrees right. You could fix that, but may as well use real trig – arc-tangent. That gives the angle, but in radians, aiming 0 degrees right and going clockwise. so, something like:

// direction to target:
Vector3 D = target.position - transform.position;
float A = Mathf.Atan2(D.z, D.x);
// Now convert A to clockwise, degrees, with 0 north:
A = (A*-1) * 180.0f/(Mathf.PI) + 90;

The last part is rounding to the nearest 45. The standard way to round anything into groups is to divide by size, round normally, then expand back out:

float Arounded = Mathf.Round((A/45.0f)*45;

For example, you have 112 degrees: (112/45)=2.48; rounded=2; *45 is 90.

You cant have exact multiple of 45 degree angles cause the enemy character would never be at exact multiple of 45 degress (say 43, or 47). So you need to have 45 plus/minus deltaDegress (lets say deltaDegrees = 3). So the gun will respond if the target is between angles 42 and 48, 87 and 93, 132 and 138 , 177 and 183 and so on. I would solve this problem using basic trigonometry ( never missed math classes ). I’ll assume your enemy is tagged ’ target’.

In the update function, find the local angle between the gun and the target with respect to the gun, assuming the angle variable is ‘angle’

if(((Mathf.Abs(Mathf.sin(angle)) > 0.67 ) && (Mathf.Abs(Mathf.sin(angle)) < 0.743 )) ||  ((Mathf.Abs(Mathf.sin(angle)) > 0.82 ) && (Mathf.Abs(Mathf.sin(angle)) < 0.95 ) ){

    //then rotate the gun directly to the target. If a raycast from the gun in the forward 
    //direction hits an object with tag 'target' then fire


Apart from this u may want that the gun goes back to its initial rotation again. For this you can record the rotation of the gun in the Start function as soon as the gun is initialised and when the target does not make the required angles with the gun, slerp it back to the initial rotation.

Disclaimer : I am better at conceptualizing so I sorry if syntax is wrong, specially the circular bracket in the if statement, I tend to make mistakes with them, Other wise I have used this kind of code before. There might be better ways of doing it :slight_smile: