Advertisement

rotation tracking

Started by August 07, 2002 05:47 PM
17 comments, last by stf 22 years, 6 months ago
I''m working on a 2d vertical scroller shoot-em-up game and I''m trying to implement turrets and enemy ships that track the player through rotation (they both rotate so that they are always facing the player''s ship). I''ve searched through the archives of this forum to see if I could find a method of tracking and I think I have found a look up table that will work perfect for both. Unfortunately I need a little clarification on how to implement it. I believe this was posted by Timkin:
quote:
Psi: anglular displacement of ship Theta: angular displacement of turret Case 1: Psi +ve, Theta +ve, Psi>=Theta Action: turret turns anti-clockwise Case 2: Psi +ve, Theta +ve, Psi<theta: Action: turret turns clockwise Case 3: Psi +ve, Theta -ve, |Psi-Theta|>=PI: Action: turret turns clockwise Case 4: Psi +ve, Theta -ve, |Psi-Theta|Action: turret turns anti-clockwise Case 5: Psi -ve, Theta +ve, |Psi-Theta|>=PI: Action: turret turns anti-clockwise Case 6: Psi -ve, Theta +ve, |Psi-Theta|Action: turret turns clockwise Case 7: Psi -ve, Theta -ve, Psi>=Theta: Action: turret turns anti-clockwise Case 8: Psi -ve, Theta -ve, Psi<theta: Action: turret turns clockwise
Basically I''m getting confused on how I would get the angular displacements of the ship/turret (or values of Psi/Theta). Could anyone give me an example? Thanks, stf
Ok, I'm just about the worst person to get math advice from but here goes :

The best way to do it imo is not to use degrees, but instead just use vectors (where a vector is described as an x component and a y component).

Your gun presumably shoots where ever it is pointing. So for example your gun vector goes from the point at the start of the barrel to the point at the end of the barrel. If we pretend that your gun is pointing at a 45 degree angle up from right (standard origin), then the gun vector can be described by (for example) x component 1 and y component -1 (since any shot from the gun will pass the point 1 across and 1 up from where the gun is (if we use the standard where y decreases going up)).

Now take the right perpendicular (90 degrees clockwise) of this vector by making a new vector with the x component equal to the y component of the original vector and the y component equal to negative of the original x component.

Then check to see if the dot product of the right perpendicular gun vector (which you just worked out) and the vector to the ship is positive. If it is then turn clockwise, if not turn counter-clockwise.

The vector to the ship is defined as :
Vector vectorGunToShip = new Vector( (ship.x - gun.x) , (ship.y - gun.y) );

The dot product of two vectors is :
public static int dotProduct(Vector v1 , Vector v2) {
return (v1.getXComponent() * v2.getXComponent()) + (v1.getYComponent() * v2.getYComponent());
}

This is fairly fast I think, and may even work Hope it helps.

EDIT : formatting


[edited by - Argus on August 7, 2002 8:10:36 PM]
Advertisement
Argus, did you perchance mean ''take the cross product of the vectors''? The dot product wont tell you the angular orientation between two vectors (the handedness of the vector basis formed by those two vectors), but the cross product will.

The use of the angle lookup table uses vector relationships as well but hides the cross product check... I seem to recall offering the lookup table because someone wanted a nice lookup table. The cross product method would be just as valid (although I don''t see the need to find the vector perpendicular to the barrel vector... perhaps you could explain that one please Argus).

Anyway, to answer your question...

Just pick a reference direction... positive x is standard. The angles Psi and Theta are measured from the axis of rotation of the turret. If dx and dy are the displacements of the ship from the turret (so add dx and dy to the turret''s coordinates and you should get the ship''s coordinates) then
Psi = tan-1(dy/dx) 
.

Now, theta is the angle that the barrel is currently at. You might assume that the turret has a fixed angular velocity of (+/-) dtheta degrees per frame, so that
th(frame i) = th(frame i-1) (+/-)dtheta 
.

So now it''s the ''+'' or ''-'' that the lookup table provides, based on the orientation of theta and psi relative to each other. Anticlockwise means plus and clockwise means minus.

I hope that clarifies things.

Just a final point... the lookup table isn''t the only way to solve the problem... it''s just a relatively easy way to code and understand. This problem has been tackled in the Maths & Physics forum many times, so you might want to search through that archive as well if you decide you don''t like this method.

Cheers,

Timkin
The dot product between two 3D vectors will give the cosine of the angle between the the two vectors.

The cross product between two vectors will give a vector at 90 degrees to both the vectors.

I thought I would clarify that.
According to my sources, a positive dot product indicates that the vectors are heading in somewhat the same direction. So one checks if the right perpendicular is heading in somewhat the same direction and if so, rotate clockwise.

It should be quite a bit faster than alternative methods.

If the turret is always facing the ship, then the solution is quite simple. Don''t use the actual orientation of the turret; simply find the ''absolute'' angle:

angle = atan(dy/dx)

Beware that atan always returns an angle in the range [-PI/2, PI/2] (I think... Or is it 0, PI?).

Cédric
Advertisement
You can get round the problem with atan by using atan2, which takes the numerator and the denominator as seperate arguments so can tell which quadrant the line is in.

I think atan( x / y ) translates into atan2( y , x)
Thanks for all the helpful replies everyone. I already had some of the look up table coded so I''m going to try out this method first.

Here is my code at the moment:


  dx = player->m_PosX - tt->m_PosX;dy = player->m_PosY - tt->m_PosY;		psi = atan(dy/dx);		if((psi>0)&&(theta>0)&&(psi>=theta))		{			if(tt->m_Frame != 0)			{				tt->m_Frame--;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=15;				EvalTheta(theta,tt);			}		}		else if((psi>0)&&(theta>0)&&(psi<theta))		{			if(tt->m_Frame != 15)			{				tt->m_Frame++;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=0;				EvalTheta(theta,tt);			}		}		else if((psi>0)&&(theta<0)&&(abs(psi-theta)>=PI))		{			if(tt->m_Frame != 15)			{				tt->m_Frame++;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=0;				EvalTheta(theta,tt);			}		}		else if((psi>0)&&(theta<0)&&(abs(psi-theta)))		{			if(tt->m_Frame != 0)			{				tt->m_Frame--;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=15;				EvalTheta(theta,tt);			}		}		else if((psi<0)&&(theta>0)&&(abs(psi-theta)>=PI))		{			if(tt->m_Frame != 0)			{				tt->m_Frame--;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=15;				EvalTheta(theta,tt);			}		}		else if((psi<0)&&(theta>0)&&(abs(psi-theta)))		{			if(tt->m_Frame != 15)			{				tt->m_Frame++;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=0;				EvalTheta(theta,tt);			}		}		else if((psi<0)&&(theta<0)&&(psi>=theta))		{			if(tt->m_Frame != 15)			{				tt->m_Frame--;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=0;				EvalTheta(theta,tt);			}		}		else if((psi<0)&&(theta<0)&&(psi<theta))		{			if(tt->m_Frame != 15)			{				tt->m_Frame++;				EvalTheta(theta,tt);			}			else			{				tt->m_Frame=0;				EvalTheta(theta,tt);			}		}  


Theta is initially set at the radian for 90 degrees (since the first frame is the turret gun pointing straight up). EvalTheta() simply looks up which frame the turret (tt) is on and sets theta to the correct radian for that angle.

Unfortunately at the moment all the turret does is turn 4 times clockwise (so that its pointing straight right) and stay there no matter where I move the player''s ship around it. I''ve figured out that once its in that position the values of psi/theta aren''t meeting any of the cases above so it does nothing. Does anyone see an error in the code above or my reasoning?

Thanks,
stf
A couple of points...

atan2 only returns an angle between -pi/2 and pi/2. Hence the lookup table to determine the relative angular displacements using the atan2 result. Of course I should have said that tan-1(dy/dx) was atan2 and not atan (I never use atan!)... my bad.

Argus, yes you are correct, a positive dot product means that the component of one vector in the direction of the other is indeed positive and hence the vectors are in the same half space (think of it as within 180 degrees of each other). The problem is, it doesn't tell you whether the barrel is pointing left of the target or right of the target. However, taking the cross product between the barrel vector and the turret-ship vector will give a signed result, dependant on the relative angular position of the vectors to one another.

Finally, stf... I seem to recall that there was a special case for Psi equals zero mentioned in the original post. It would be 'turn the opposite direction from the sign of theta'. If it was ommitted from that post, it would just be my mistake. My apologies if it is... and you can stick it in now!

Cheers,

Timkin



[edited by - Timkin on August 8, 2002 8:27:29 PM]
Timkin - that''s why I took the vector 90 degrees clockwise from the facing of the gun.

In which case a positive dot product means that the ship is to the right, so we know to turn clockwise.

This topic is closed to new replies.

Advertisement