- Home /
Make the turret automatically rotate to look at where the crosshair is aimed at.
Here's the idea: I want to create a tank with a turret, which does not turn as I rotate it around the Y axis with my mouse, but rather, make it aim at where I am pointing the camera at. For example, I have a turret, and I use the camera to look at a point on a cube. I want the turret to gradually rotate on its own Y axis to that direction until it faces this point on the cube. Same goes for rotating the gun so it aims at this point in preparation to fire. How can I do this? If possible please keep the script as simple as possible because I am using this as a learning material and I am currently rather bad at Java Scripting.
Answer by robertbu · Jan 28, 2013 at 02:13 AM
I'm not exactly sure what you want from your description, but here are two scripts that combined will have a gun on a turret pointing at a specified game object. As the game object moves, it will track the object. Tracking speed is controlled by the maxDegreesPerSecond parameter. For smaller values and/or larger target movements, the gun will lag behind the target. The gun must be a child object of the turret, and the gun barrel must point forward (i.e. down the Z axis). In the inspector, drag the target object to the GoTarget parameter in both scripts.
--- Turret script ---
var goTarget : GameObject;
var maxDegreesPerSecond : float = 30.0;
private var qTo : Quaternion;
function Start () {
qTo = goTarget.transform.localRotation;
}
function Update () {
var v3T = goTarget.transform.position - transform.position;
v3T.y = transform.position.y;
qTo = Quaternion.LookRotation(v3T, Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, qTo, maxDegreesPerSecond * Time.deltaTime);
}
--- Gun Script ---
var goTarget : GameObject;
var maxDegreesPerSecond : float = 30.0;
private var qTo : Quaternion;
function Start () {
qTo = goTarget.transform.localRotation;
}
function Update () {
var v3T = goTarget.transform.position - transform.position;
var v3Aim : Vector3;
v3Aim.x = 0.0;
v3Aim.y = v3T.y;
v3T.y = 0.0;
v3Aim.z = v3T.magnitude;
qTo = Quaternion.LookRotation(v3Aim, Vector3.up);
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, qTo, maxDegreesPerSecond * Time.deltaTime);
}
Thank you. By your description it is near to what I have in $$anonymous$$d but not exactly it. What I am trying to do is replicating World of Tank's ai$$anonymous$$g system. I believe to achieve such thing I will have to use raycasting.
I would try something like:
RaycastHit hit; // declare the RaycastHit variable
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit)) {
// what ever lookat(hit.point);
}
I know this is C# but this is what I'm equipped with
The code above uses the position of a game object. To get what you want, you can either 1) place an empty game object where you want the gun to aim or 2) rewrite the code above so that it tracks a Vector3 ins$$anonymous$$d of a game object.
As @sdgd mentions above, you will need to raycast into the scene from the center of the crosshairs to find the hit point. The RaycastHit.point will be the location to use.
Note I watched a couple of videos of World of Tank's on YouTube. What is going on there is more complicated than the simple code above. One example is that the projectiles follow a parabolic path.
Hi
Would anyone be so kind and convert the script into C# in order to help those of us who are trying to learn C# - I'm sure that I certainly won't be the only one who would benefit from this.
Thank you in advance
ps. a few comments in the script wouldn't hurt either !
This is an interesting approach, I agree with Viking, I'd love to see some more comments. This script however only works if your turret is at 0,0,0. As soon as it's not in the center anymore the x rotation shifts to something around 350. I tried parenting thus keeping it's local position 0,0,0, but that doesn't work either. Am I missing something?
Answer by DarthDisembowel · Jul 31, 2014 at 05:24 AM
Here's some C# code I use for spaceship turrets. I feel this could be simplified a bit but I was never able to get it to work without saving the local rotation and reapplying them to the axes I don't want to rotate. Works no matter how the vehicle is oriented.
The barrels need to be a child of the rotating turret base. The script is a component of the turret base. This code is in the update function (I declare all the variables beforehand to reduce garbage collection).
The turret will traverse on the local Y-axis, and the barrels will pitch on the local X-axis.
//rotate turret
tmpRotation = transform.localRotation; //preserves the local rotation since we only want to rotate on local Y axis
leadTargetPosition = FirstOrderIntercept(transform.position,Vector3.zero,laserParticleLeft.particleEmitter.localVelocity.z,target.transform.position,target.rigidbody.velocity);
targetPointTurret = (leadTargetPosition - transform.position).normalized; //get normalized vector toward target
targetRotationTurret = Quaternion.LookRotation (targetPointTurret, parent.transform.up); //get a rotation for the turret that looks toward the target
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotationTurret, Time.deltaTime * turnSpeed); //gradually turn towards the target at the specified turnSpeed
transform.localRotation = Quaternion.Euler( tmpRotation.eulerAngles.x, transform.localRotation.eulerAngles.y, tmpRotation.eulerAngles.z); //reset x and z rotations and only rotates the y on its local axis
//rotate barrels
tmpRotation = barrels.transform.localRotation; //preserves the local rotation since we only want to rotate on local x axis
targetPointBarrels = (leadTargetPosition - barrels.transform.position).normalized; //get a normalized vector towards the target
targetRotationBarrels = Quaternion.LookRotation (targetPointBarrels, parent.transform.up); //get a rotation that looks at the target
barrels.transform.rotation = Quaternion.Slerp(barrels.transform.rotation, targetRotationBarrels, Time.deltaTime * turnSpeed); //gradually turn towards the target as the specified turnSpeed
barrels.transform.localRotation = Quaternion.Euler( barrels.transform.localRotation.eulerAngles.x, tmpRotation.eulerAngles.y, tmpRotation.eulerAngles.z); //reset y and z rotations and only rotates the x on its local axis
Thanks, that worked grand ! i had to put it on a child component, i.e the turret itself as i was unable to call it from the ship script itself...
awesome, 3 nights of Quaternion's for me and i think i have unlearned stuff but your post saved my sanity.
Answer by eliteforcevn · Jul 08, 2021 at 02:20 PM
Thanks DarthDisembowel edited some word:D
Quaternion tmpRotation = turretGO.transform.localRotation;
Vector3 targetPointTurret = (lookAtTarget.transform.position - turretGO.transform.position).normalized;
Quaternion targetRotationTurret = Quaternion.LookRotation(targetPointTurret, turretGO.transform.up);
turretGO.transform.rotation = Quaternion.Slerp(transform.rotation, targetRotationTurret, 1f);
//replace 1f = Time.deltaTime * turnSpeed if u want a delay time
turretGO.transform.localRotation = Quaternion.Euler(tmpRotation.eulerAngles.x, turretGO.transform.localRotation.eulerAngles.y, tmpRotation.eulerAngles.z);
/////////////////////////////////////////
tmpRotation = gunGO.transform.localRotation;
Vector3 targetPointBarrels = (lookAtTarget.transform.position - gunGO.transform.position).normalized;
Quaternion targetRotationBarrels = Quaternion.LookRotation(targetPointBarrels, transform.up);
gunGO.transform.rotation = Quaternion.Slerp(gunGO.transform.rotation, targetRotationBarrels, 1f);
//replace 1f = Time.deltaTime * turnSpeed if u want a delay time
gunGO.transform.localRotation = Quaternion.Euler(gunGO.transform.localRotation.eulerAngles.x, tmpRotation.eulerAngles.y, tmpRotation.eulerAngles.z);
Your answer
Follow this Question
Related Questions
target tracking with lead time 1 Answer
multipe targets 1 Answer
Look at issues 1 Answer
Syncing 2-part turret design with mouse on rotating patform 1 Answer
Turret aimming is off. 1 Answer