- Home /
Constraining turret rotation in local space
Ok, I've been banging my head against the wall for a while with this. My understanding of quaternions and rotations is poor at best, so I'm looking to get some input.
Essentially, I have a physically simulated player-controlled spaceship (in full3d space) with a bunch of turrets all over it. These are aimed around at an aim target box which changes location based on mouse position. So far so good - I can aim my turrets pretty well.
However, my turrets need to be constrained, so that the base only rotates (yaws) and the barrel only pitches. Additionally, there should be some way to constrain these rotations so that a turret doesn't point, say, into the ship.
This is how it works right now: On start, I set up the turret by getting its local rotations in the rest position.
function Start() { rb = rigidbody;
// set up barrel and muzzle
for (var child : Transform in turretBody) {
turretBarrel = child;
}
for (var child : Transform in turretBarrel) {
turretMuzzle = child;
}
// set up base turret orientation
turretXLocked = turretBody.localRotation.eulerAngles.x;
turretZLocked = turretBody.localRotation.eulerAngles.z;
barrelYLocked = turretBarrel.localRotation.eulerAngles.y;
barrelZLocked = turretBarrel.localRotation.eulerAngles.z;
print (turretXLocked);
print (turretZLocked);
}
I then run this in Update:
function Update() {
AimTurretBase();
AimTurretBarrel();
if(Input.GetMouseButton(0) && timer == 0) {
PlayMuzzleFX(turretMuzzle.position,turretMuzzle.rotation);
FireWeapon(turretMuzzle.position,turretMuzzle.rotation);
StartReloadTimer();
}
}
I'll just post AimTurretBase here as AimTurretBarrel is essentially the same.
So here I get my AimTarget and turret base position, then create a rotation to point the turret at it. Then I rotate the turret, but set the X and Z rotation to zero so that it only rotates in the Y space.
function AimTurretBase() { var origPos:Vector3 = turretBody.position; var targetPos:Vector3 = aimTarget.position; var rotGoal = Quaternion.LookRotation(targetPos - origPos);
var actualGoal = rotGoal;
var curRot = Quaternion.Slerp(turretBody.rotation,actualGoal,Time.deltaTime*turretTurnRate);
// always clamp the turret to the ship
turretBody.localRotation.eulerAngles.z = turretZLocked;
turretBody.localRotation.eulerAngles.x = turretXLocked;
}
So this... kinda works. If the turret is in the same axal plane as the ship, flawless clamping of the turret to the ship occurs. However, if i rotate the turret so it's on an angle, like on the side of the ship, it breaks down. I have been debugging for a while and have no clue why - I suspect my method is somehow flawed.
So Question 1: how do I lock an object's rotation in some axes to a ship?
Then we also have Question 2: once that's done, how can I limit the axis that is free such that it can only rotate, say, 60 degrees in either direction?
Oh, and I'd rather not use joints. Mainly because I want to get good at this stuff and that's the easy way out.
Help is super appreciated!
Answer by synapsemassage · Apr 13, 2011 at 07:14 PM
localRotation is relative to the parent. I guess the parent for your turret is the ship? Placing your turret on your ship by moving and rotating will change its localPosition and localRotation relative to the ship. A simple workaround should be an empty GameObject as a dummy with the turret as child. Create the dummy at same position/rotation like the turret in its default position/rotation. The turrets localRotation will be relative to the dummy. When placing the dummy on the ship the turret should rotate correctly. Make the dummy a child of the ship: ship/dummy/child.
Quaternions are not intuitive at all, a PIA. The whole rotation thing is not intuitive, even not with Unity ;-). As space doesn't care about orientation but humans do,it's a good idea to think in reference systems, means the dummy is your reference system to orient your object relatively.
Try calling AimTurretBase() + AimTurretBarrel() also(!) in Start().
var rb:Rigidbody; var child:Transform; var turretMuzzle:Transform;
function Start(){ // set up barrel and muzzle for (child in turretBody) { turretBarrel = child; } for (child in turretBarrel) { turretMuzzle = child; }
// set up base turret orientation turretXLocked = turretBody.localRotation.eulerAngles.x; turretZLocked = turretBody.localRotation.eulerAngles.z; barrelYLocked = turretBarrel.localRotation.eulerAngles.y; barrelZLocked = turretBarrel.localRotation.eulerAngles.z;
AimTurretBase(); AimTurretBarrel(); }
BTW avoid dynamic typing for performance reasons: "var rotGoal" should be "var rotGoal:Quaternion". Also prefer for performance reasons defining variables outside Update-related functions like:
var origPos : Vector3; var targetPos : Vector3; var rotGoal : Quaternion; var actualGoal : Quaternion;
function AimTurretBase(); { origPos = turretBody.position; targetPos = aimTarget.position; rotGoal = Quaternion.LookRotation(targetPos - origPos);
// and so on
}
This seems to help significantly, thanks! Now the turrets rotate correctly. They don't, however, aim correctly anymore - though each turret is supposed to point at the aimTarget, they point at slightly different locations around it
Presumably this is due to the change in reference positions... my previous code looked from turretBody.position to aimTarget. position in world space. so would I now want to move aimTarget into local space, then point the local rotation at that?
If so, how do I do that?
Not sure if I got you right, actually I expected it to work. What do you mean with "slightly different positions around it", almost pointing correctly at the target? Are you sure that dummy and turret were at (0,0,0) on creation?
I checked the zeros and did some debugging, everything is zeroes and seems fine. A more precise description is that the bottom turrets get to the target eventually, but they overshoot and have to track back. The top ones don't do this.
Try calling AimTurretBase() + AimTurretBarrel() also(!) in Start(). see above.
D'oh! $$anonymous$$y barrel wasn't restricted, and had a faster turn rate than the turret, so the barrel was 'helping' turn on the y-axis. Of course, it overshot and the attempts at correction resultingly just caused an oscillation.
Thanks for the help!
Your answer
Follow this Question
Related Questions
Slerp Z and X axis only 1 Answer
Constraints on rotation axis in c# 1 Answer
How to rotate cannon by angles on top of a turret 1 Answer
itween path restrict rotation on TWO axis 0 Answers
Help clamping a Rotation 1 Answer