- Home /
Rotating Turret Base and Barrel
I have looked all over and can't find anything that works for me. The closest I got to seperately rotating the base and barrel of a turret was something I found on here from a few years back.
But it makes them all jittery and they don't look anywhere near their target. Just a mess. And I just can't figure it out :(
I have a turret, on a ship. It has a base and a barrel object. The script I found buried in here I converted from JS to C#:
using UnityEngine;
using System.Collections;
public class PSK_Turret : MonoBehaviour {
public Transform turretBase;
public Transform turretBarrel;
public float baseRotateSpeed;
public float barrelRotateSpeed;
public Transform target;
// Update is called once per frame
void Update () {
if (target != null) {
Quaternion tmpBaseRot = turretBase.localRotation;
Vector3 targetPointTurret = (target.position - turretBase.position); //get normalized vector toward target
Quaternion targetRotationTurret = Quaternion.LookRotation (targetPointTurret, turretBase.up); //get a rotation for the turret that looks toward the target
turretBase.rotation = Quaternion.Slerp(transform.rotation, targetRotationTurret, Time.deltaTime * baseRotateSpeed); //gradually turn towards the target at the specified turnSpeed
turretBase.localRotation = Quaternion.Euler( tmpBaseRot.eulerAngles.x, turretBase.localRotation.eulerAngles.y, tmpBaseRot.eulerAngles.z); //reset x and z rotations and only rotates the y on its local axis
Quaternion tmpBarrelRot = turretBarrel.localRotation; //preserves the local rotation since we only want to rotate on local x axis
Vector3 targetPointBarrels = (target.position - turretBarrel.position); //get a normalized vector towards the target
Quaternion targetRotationBarrels = Quaternion.LookRotation (targetPointBarrels, turretBarrel.up); //get a rotation that looks at the target
turretBarrel.rotation = Quaternion.Slerp(turretBarrel.rotation, targetRotationBarrels, Time.deltaTime * barrelRotateSpeed); //gradually turn towards the target as the specified turnSpeed
turretBarrel.localRotation = Quaternion.Euler( turretBarrel.localRotation.eulerAngles.x, tmpBarrelRot.eulerAngles.y, tmpBarrelRot.eulerAngles.z); //reset y and z rotations and only rotates the x on its local axis
}
}
}
Does not work though :/ Does anybody have a good easy solution for aiming a turret properly at a target? I know I can use LookAt to make the whole thing rotate at the target.. but that doesnt work right either. I did get a good base rotation with LookAt, but the turret itself had to be upright, if I rotated it sideways it would rotate itself back flat..
Any help would be greatly appreciated. Trying to figure this out has been killing me.
Answer by robertbu · Nov 19, 2014 at 10:24 PM
If you turrent is axes aligned, you can do something simple like this the two scripts here:
http://answers.unity3d.com/questions/388185/make-the-turret-automatically-rotate-to-look-at-wh.html
But if your turret will have arbitrary rotations like if it was on the side of a space ship or on a tank running across a terrain, then go to this answer:
http://answers.unity3d.com/questions/562443/turret-slerp-rotation-and-clamping.html
...and open up the comment on my answer. You will find a short script that handles both rotations.
Unfortunately, both scripts are Javascript. If you have problems translating to C#, let me know.
It works better than the last two I've tried, except the barrel aims in the opposite direction from the target.
A C conversion would be nice.
This is the one I believe you wanted me to find:
#pragma strict
var target : Transform;
var gun : Transform;
var turretDegreesPerSecond : float = 45.0;
var gunDegreesPerSecond : float = 45.0;
var maxGunAngle = 45.0;
private var qTurret : Quaternion;
private var qGun : Quaternion;
private var qGunStart : Quaternion;
private var trans : Transform;
function Start() {
trans = transform;
qGunStart = gun.transform.localRotation;
}
function Update () {
var distanceToPlane = Vector3.Dot(trans.up, target.position - trans.position);
var planePoint = target.position - trans.up * distanceToPlane;
qTurret = Quaternion.LookRotation(planePoint - trans.position, transform.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, qTurret, turretDegreesPerSecond * Time.deltaTime);
var v3 = Vector3(0.0, distanceToPlane, (planePoint - transform.position).magnitude);
qGun = Quaternion.LookRotation(v3);
if (Quaternion.Angle(qGunStart, qGun) <= maxGunAngle)
gun.localRotation = Quaternion.RotateTowards(gun.localRotation, qGun, gunDegreesPerSecond * Time.deltaTime);
else
Debug.Log("Target beyond gun range");
}
And it's still not quite right, if I turn off the script and reverse the rotation, its ai$$anonymous$$g about 2m in front of the transform.
I ran some decent tests on the code before I posted it originally, so I know it works correctly at least for the my test setup. $$anonymous$$y first guess is that the issue is related to either the pivot point of the objects. Note that you should do a Debug.DrawRay() and view the results in the Scene view. Things in 3D space can look screwy even when they are pointed correctly. If you post a link to a package containing your geometry, I'll be glad to take a look at see if I cannot figure out the problem. Don't need your full app, just the turret and gun barrel.
The code expects the geometry to be created a specific way. The turret needs to rotate around its local 'Y' axis, and the local forward of the gun barrel needs to be the direction to use in angle calculations. Neither of your objects match is criteria. You solved the turret issue with the use of an empty game object. You could solve the gun barrel in the same way. Ins$$anonymous$$d, in order to test things, I use the Rotate$$anonymous$$esh Editor script and reoriented both the turret and gun. Here is a package:
www.laughingloops.com/Turret3.unitypackage
And here is a C# translation of the script:
using UnityEngine;
using System.Collections;
public class Turret_CS : $$anonymous$$onoBehaviour {
public Transform target;
public Transform gun;
public float turretDegreesPerSecond = 45.0f;
public float gunDegreesPerSecond = 45.0f;
public float maxGunAngle = 45.0f;
private Quaternion qTurret;
private Quaternion qGun;
private Quaternion qGunStart;
private Transform trans ;
void Start() {
trans = transform;
qGunStart = gun.transform.localRotation;
}
void Update () {
Debug.DrawRay(gun.position, gun.forward * 20.0f);
float distanceToPlane = Vector3.Dot(trans.up, target.position - trans.position);
Vector3 planePoint = target.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);
if (Quaternion.Angle(qGunStart, qGun) <= maxGunAngle)
gun.localRotation = Quaternion.RotateTowards(gun.localRotation, qGun, gunDegreesPerSecond * Time.deltaTime);
else
Debug.Log("Target beyond gun range");
}
}
Answer by J_Troher · Nov 20, 2014 at 06:55 AM
It works very well. I do get some points where the barrel will aim down through the base.. I'm not sure why. Maybe because its on a ship that moves freely in 3d space. But I could simply add some code that won't allow it to shoot itself. And it gives me something to go on :) thank you much
Things in 3D space can look screwy even when they are pointed correctly. If you post a link to a package containing your geometry, I'll be glad to take a look at see if I cannot figure out the problem. Don't need your full app, just the turret and gun barrel. DGCustomerFirst
Answer by eliteforcevn · Jul 08, 2021 at 02:22 PM
here is some code
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
How can I rotate a tank's turret back to the starting turret position? 2 Answers
localposition not working? Calculating a vector in front of an object. Picture and code included 1 Answer
Turrets |Aiming don't work 1 Answer
Editor windows disappear on play in Unity 5.5.2f1 1 Answer
problems with quaternion rotations 4 Answers