Turret defense with rotation limits

Hi
For rotating and for the limiting the turret I’m using this script:

FixedUpdate
Vector3 targetDir = ShootingTarget.position - this.transform.position;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, RotationSpeed * Time.deltaTime, 0.0f);
float newAngle = Vector3.Angle(this.transform.parent.transform.forward, newDir);
if (newAngle > MaxRotationAngle) return;
transform.rotation = Quaternion.LookRotation(newDir);

(transform.parent is a base of the turret so is a limit at for example 150 degree)

Everything is working like a charm but is a problem…

Imagine that turret is rotated 140 to the right, when new target will come from 140 on the left then shortest way is to turn 80 more to the right but it can’t because of the limit.
How to implement is some easiest / fastest way to let the turret know it should rotate 280 in opposite direction in such cases?

Any ideas ?

First check out ‘SignedAngle’:

This will give you the angle and direction.

Next, measure the angle off the parent’s forward towards the new target using this signed angle. And move from the current signed angle off parent’s forward towards that angle, as long as that target angle is in range -140 to +140.

Hi
You didn’t even read my post to the end am I right ? :slight_smile: (i know about SignedAngle)
Problem is with rotate towarrd which always roatating object with shortest way.
My best approach so far looks like this, but not working well (combined with oryginal code from the first post)

float rotFactor =1;
float currAngle= Vector3.SignedAngle(this.transform.parent.transform.forward, this.transform.forward, Vector3.up);
float targetAngle = Vector3.SignedAngle(this.transform.forward, shootingTarget.position, Vector3.up);
if (Mathf.Abs(currAngle + targetAngle) > 180) rotFactor = -1;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, RotationSpeed * rotFactor * Time.deltaTime, 0.0f);

I’m not the Picasso - sorry :slight_smile: link to image: Pic hosted at ImgBB — ImgBB

Yes, I did read your post. And there’s nothing about your post that says you knew about ‘SignedAngle’, nor what your previous knowledge of it has to do with my reading your post. Nor in your post do you suggest you knew the problem is with RotateTowards.

I suspect what you meant by if I read your post is that my answer was not satisfactory because I didn’t give you example code or something.

But yeah, don’t use Vector3.RotateTowards.

Get the signed angular direction, and rotate by that.

If you don’t know how to rotate by a signed angle… well there’s lots of ways to. I use Quaternions personally:

        //get targAngle
        var dirOfTarget = (target.position - this.transform.position);
        dirOfTarget.y = 0f; //remove any vertical
        float targAngle = Vector3.SignedAngle(dirOfTarget, this.transform.parent.forward, Vector3.up);

        //clamp targAngle
        if (targAngle < -this.angularRange) targAngle = -this.angularRange;
        if (targAngle > this.angularRange) targAngle = this.angularRange;

        //get currentAngle
        float currentAngle = Vector3.SignedAngle(this.transform.forward, this.transform.parent.forward, Vector3.up);

        //find our delta from current to targ
        var delta = targAngle - currentAngle;

        //get a speed to move in that direction smoothly
        delta = Mathf.Min(this.turnSpeed * Time.deltaTime, Mathf.Abs(delta)) * Mathf.Sign(delta);

        //rotate towards
        this.transform.localRotation*= Quaternion.Euler(0f, -delta, 0f); //we have to negate delta because annoyingly Unity has SignedAngle upside down

If you need a forward vector. Like in your code… that last line could be:

Vector3 newDir = Quaternion.Euler(0f, -delta, 0f) * this.transform.forward;

The fundamental concept is like.

Think of a number line:

-5 . . . . . 0 . . . . 5

If I want to go from 4 to -3, how much do I have to move by (add to 4) to get to -3. Well it’s:
3 + x = -4
x = -4 - 3
x = -7

Or effectively it’s:
delta = targ - current

So we move 7 places left (-) from 4 to -3.

Well… all we need to do with the angles is unravel the rotation into a number line (hence the SignedAngle). Get the delta. And rotate to the target by that delta.

Sir, yes sir!
Problem was to stick with RotateTowards and keep trying to find a way to give opposite rotation if needed.
Was “just” about to change mindset to quaternion.euler and delta.
Ps - thought you didn’t read because you wrote about rotate towards what I was already doing without success when target is “closer” on f.g. right side but it’s on opposite side of the limit so closer way was a wrong way.
Thank you for clear and nice solution. How I love Unity community… :stuck_out_tongue: