Turret rotation based on its own local rotation.
Hello,
I have been searching for a long while now and i did nto find any anwser to my issue so i thought lets ask for help.
I have a turret [Turret and gun is one mesh, no seperate rotation] and i want it to rotate towards the targets.
This is pretty easy and not a problem, but i want to be able to place the turret anywhere i want.
For example on the walls/roofs/ diagonal areas.
This changed the situation, as the rotation takes the world coordinates instead of the local rotation.
For example if the turret is placed on the wall it should have its base against the wall at all times, instead it rotates like it was on a flat surface.
As shown in the image below, the turret should also have a limit of how far up and down it can aim.
The turrets can rotate all around but should be limited to the up and down movement/aiming.
And all this should be done in the local rotation as the it should stick to the [wall/ground/vehicle]
I hope anyone can help me out on this or point me in the right direction.
Thanks and regards
Sound like you are almost there, let me know if this answer helps you figure it out: http://answers.unity3d.com/questions/275565/what-is-the-rotation-equivalent-of-inversetransfor.html
@Glurth Thank you for the reply. I have looked into it and it does not seem to be the anwser i am looking for i'm afraid.
If can check the local euler and see that the X value goes up and down when the target moves up and down, so that works as it should but then i need to limit the angles so it wont rotate along the z axis and it can not move further up and down than lets say 20 degrees along the X axis.
Once doing that it only rotates towards the target along the Y axis and it does not rotate up and down with a limit, It seems it would need all the axis to be able to rotate that way.
I hope i can get some more information to point me in the right direction.
Thank you in advance
Hmm, I'm a little confused now, I though you DID have it working properly when working with localCoordiates. If this is the case, you just need to use targetLocalPosition=turret.transform.InverseTransform(target.transform.position);
to convert your target from global to turret-local coordinates. You can then feed this into the code you already have working.
I'm not sure what to suggest regarding the limited movement of each turret (so many options), did you have this working right in local coordinate too?
very simple. first of all your turret has to be a seperate mesh so it can move independantly. it should be a child object of whatever its connected to. and then only deal with local rotation for turret scripts!
Answer by Noxury · Jan 15, 2018 at 11:14 PM
Get the direction,
Calculate the rotation with tanks' body as upwards,
Slerp over time to the direction,
Constrain the local xz angles after aligning the desired rotation.
Attach this to the root where you control the tank. This way your tower rotates only on its local Y, which will calculate the angle to face the target.
void RotateTo(Transform target, float rotationSpeed)
{
Vector3 dir = (target.position - tower.position).normalized;
Quaternion newRot = Quaternion.LookRotation(dir, transform.up);
tower.rotation = Quaternion.Slerp(tower.rotation, newRot,
rotationSpeed * Time.deltaTime);
tower.localEulerAngles = new Vector3(0f, tower.localEulerAngles.y, 0f);
}
Answer by StefanoDC · Mar 15, 2016 at 12:55 AM
Edit: I know see that this doesn't fully address your problem. This only constrains the the turret to not aim into the wall/surface, and doesn't place a restriction relative the tangent of the surface you are attached to (the left most and right most example in your image). It would probably be better to take a bit of a different approach to do that, rather than just extending my solution. I may edit this with a more relevant solution, or I may just leave this as is in case it's still useful to people anyway.
--
Hopefully the comments in the code sample explain it well enough so I don't have to explain it again (not sure about answer guidelines here though, since this is my first).
In case it's not clear, the "normal" should be the normal of the surface the turret is on, in my test code I just set it to be the initial forward direction, so the turret will be constrained to [maxAngle] degrees from the original forward direction.
using UnityEngine;
using System.Collections;
public class Turret : MonoBehaviour {
public Transform target;
public float maxAngle;
Vector3 normal;
void Start () {
normal = transform.forward;
}
void Update () {
//Get the vector pointing from this transform to the target position
Vector3 toTarget = target.position - transform.position;
Debug.DrawRay(transform.position, toTarget, Color.blue);
//Find the angle between the normal and the vector towards the target
float angle = Vector3.Angle(normal, toTarget.normalized);
//Find the axis which we would rotate around to go from our normal toward the target
Vector3 axis = Vector3.Cross(normal, toTarget.normalized);
Debug.DrawRay(transform.position, axis, Color.green);
//Rotate the normal around our found axis, clamping the angle to our defined maxAngle
Vector3 targetDir = Quaternion.AngleAxis(Mathf.Clamp(angle, 0, maxAngle), axis) * normal;
Debug.DrawRay(transform.position, targetDir, Color.red);
//Rotate our transform to face the new target direction
Quaternion targetRotation = Quaternion.LookRotation(targetDir);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 1 * Time.deltaTime);
}
}
Answer by gneissler · Dec 18, 2020 at 05:50 PM
hey, i thought i share my solution as well. its kinda next level because it rotates on 2 axis without a lerp on a fixed rotationspeed takin its local rotation into a count. it took me a long while to figure this one out, because like you said its a kinda difficult topic, without any hints on how to do it exactly. so here you go.
using UnityEngine;
public class RotateToTarget : MonoBehaviour {
public Transform gun; // the part of the Turret you want to rotate UP/Down "the barrel for example"
public float turretDegreesPerSecond = 45.0f; // this is the left right rotation speed (put the script on this object)
public float gunDegreesPerSecond = 45.0f; // this is the rotation speed (its for the gun or the part you want to rotate Up and Down)
// those are not to modify
private Quaternion qTurret,qGun,qGunStart;
private Transform trans;
void Start()
{
trans = transform;
qGunStart = gun.transform.localRotation;
}
public void RotateAtTarget(Transform f) // "f" is the focuspoint or "target". you can call this function from another script "if(target) -> RotateToTarget(TargetFocus);"
{
float distanceToPlane = Vector3.Dot(trans.up, f.position - trans.position);
Vector3 planePoint = f.position - trans.up * distanceToPlane;
qTurret = Quaternion.LookRotation(planePoint - trans.position, transform.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, qTurret, turretDegreesPerSecond * Time.deltaTime);
Vector3 v3 = new Vector3(0.0f, distanceToPlane, (planePoint - transform.position).magnitude);
qGun = Quaternion.LookRotation(v3);
gun.localRotation = Quaternion.RotateTowards(gun.localRotation, qGun, gunDegreesPerSecond * Time.deltaTime);
}
}
Your answer
Follow this Question
Related Questions
Applying a rotation relative to the object's starting rotation 0 Answers
Get rotation of a randomly rotating turret on a moving tank (to Spawn missiles in that direction) 2 Answers
Problem with projectile rotation - 2D 0 Answers
Rotation and Gravity Relative to the Center of an Object 0 Answers
LookAt only on local Z Axis 0 Answers