#14260 - Lord Graga - Sat Jan 03, 2004 3:00 pm
Hey all.
Today I was contacted my a dude who wanted me to do a game for him. His game includes two main objects: A player and an enemy.
The enemy would fly above him, and he would be jumping around on the ground, shooting the enemy. It's a port of a pc game where it's possible to aim with the mouse, but as it's not possible on GBA, I would need to add autoaim.
And now is the questions:
- How do I calculate the angle between the two sprites?
- How do I move a bullet in the direction of the angle?
#14267 - tepples - Sat Jan 03, 2004 4:25 pm
To calculate the angle between east and a vector, use the arctan2() function from the BIOS. Then use sine and cosine tables to calculate the trajectory of the bullet.
However, you may want to "lead" the shot. This would require a bit more trig and possibly calculus and would also need a bit of experimentation based on other factors of your game design.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#14269 - poslundc - Sat Jan 03, 2004 4:33 pm
Well, the angle depends on the origin and axis you are measuring from. Either way it's just simple trig, though. Best advice is to get out a ruler and start drawing some triangles to find out what you are looking for.
If you want the angle that the top sprite makes with the bottom sprite from the vertical axis, for example, then it's the inverse tangent (arctangent) of (xdifference / ydifference).
As for how to move a bullet in that direction, the easiest way is to use fixed-point math and calculate an x and y velocity based on that angle. Then each frame you add the x-velocity to the sprite's x-location, and the y-velocity to the y-location. To get these velocities, you use a uniform bullet speed which is the hypotenuse of your triangle. (This should be the velocity your bullet would fire at if you were just firing vertically.) Then (using the above calculated angle), y-velocity = speed * cos(angle), and x-velocity = speed * sin(angle).
If you want, you could even use rot-sprites to make the bullet actually point in the direction being fired.
I'll warn you right now, though, if you try to go ahead with coding this and aren't already comfortable with trigonometry then you are cruising for a bruising.
EDIT: Tepples' suggestion of using arctan2 is much better (unless your y-distance is constant, in which case a LUT is probably much, much faster), as you don't have to divide.
Dan.
#14289 - Miked0801 - Sat Jan 03, 2004 10:48 pm
To do a simple linear aim routine, jsut you the law of Sines to get your lead angle. I've done this a number of times and can post if needed - It's used all the time in RoboCode (Java Robot fun.)
#14354 - johnny_north - Mon Jan 05, 2004 7:27 pm
Code: |
A
| \
| \ c
b | \
|_______\ B
C a |
Mike ? I was interested in how the law of sines would work (assuming some sin/cos lut). Say B is the cannon, A is the space ship.
Law of sines: a/SinA = b/SinB
SinB/b = SinA/a
SinB = b(SinA/a) but SinA/a = 1/c so:
B = arcsin(b/c)
Then: dx = COS[B]; dy = SIN[B];
Then take each of these times a scalar velocity?
However, using arctan:
Tan B = sinB/cosB
B = arctan(sinB/cosB) = arctan((b/c)/(a/c)) = arctan(b/a)
Then: dx = COS[B]; dy = SIN[B];
I guess that since c is probably not =1 we can?t lut the trig values until the end. My math might be a bit rusty, but which is faster; an implementation of arcsin or arctan? I suppose arctan because of its inclusion in the Bios.
#14358 - poslundc - Mon Jan 05, 2004 8:06 pm
I can't comment on how efficient the BIOS algorithm is (perhaps someone else can?), but generally the arctan2 function is really good for situations like this because it takes two parameters (the numerator and denominator) so that you don't have to divide (which is the real speed-killer on ARM).
Only preferable situation is if you've got a fixed length for one of the sides (as is the probable case in this situation, where you've got the player at the bottom of the screen and enemy at the top, and the vertical distance between them is probably constant), in which case you may as well just use a LUT.
Dan.
#14368 - johnny_north - Mon Jan 05, 2004 9:42 pm
BTW - if anyone is trying to follow this post, the arctan2 swi returns an angle between 0 and 2 pi radians. Make sure you convert this number to degrees before using it to dereference a trig look up table.
#14398 - Miked0801 - Tue Jan 06, 2004 12:23 am
Ok, here's the code to do it (cut and paste from my Java Robot and editted to make sense)
first, get the bearing to the target you are aiming at. I'll use absoluteBearing.
Now, find the target's velocity / your projectile's velocity. I'll call that VRatio.
So then the formula becomes direction = absoluteBearing + ArcSin(VRatio * Sin(EnemyHeading - absoluteBearing));
Why this works:
The law of sines states that the length of a sides of a triangle divided by the angle of the angle opposite to that side are equal.
So form the following triangle using the target's velocity and the projectile's velocity as length of a connected triange (Beware, ASCII art follows!):
Target----->
| /
| /bullet velocity
Me
So I can form the ratio:
TargetVelocity Bullet Velocity
---------------- = -----------------
Sin(LeadAngle) Sin(TargetHeading - bearing)
Solving for LeadAngle yields: LeadAngle = ArcSin(Sin(TargetHeading - bearing) * TargetVelocity / BulletVelocity)
Beware the bearing subtract is needed to make the heading relative to the direction you are looking. Also notice that the distance between the target and yourself is not needed for this calculation - just velocities. Also note that if the value instead the arcSin is greater than 1, there is no solution (the bullet can't get there as the target is moving too fast!)
Trig/Physics 101 for today is now complete :)
Mike