Finding the angle between two sprites

Started by
15 comments, last by randomDecay 21 years, 8 months ago
OK thanks waverider -- here''s what I came up with (looks very good to me, what do you think?)


  	DWORD time = CGameTime::Elapsed();			float dirX = (p_playerX - GetXPos());	float dirY = (p_playerY - GetYPos());	float dt = ( static_cast<float>(time) - static_cast<float>(GetLastTimeMoved()) ) / 1000.0f;	SetXPos( GetXPos() + ( dirX * dt ) );	SetYPos( GetYPos() + ( dirY * dt ) );	SetLastTimeMoved( time );  
Advertisement
Just have a function that gets the time elapsed between each frame in milliseconds. You shouldn't limit your framerates just to sync movement, it'll never work unless you set a really low limit.

Let's say you want to move the vehicle at a rate of 10 units per second. You have the DeltaY and DeltaX, the difference in x and y between the two points. Basically, you have a 2D vector. Normalize this vector to get a unit vector. Now you have directional vector of length one. Since you want to move the vehicle 10 units per second, you want to make sure that per 1000 ms, it moves 10 units. So per N ms, it moves N*10/1000 = N*1/100 of a unit. Let's say 30 ms has elapsed since the last frame. You would multiply the x and y offsets by 30*.01 = .3. Since the x and y offsets form a unit vector(vector length one), you will effectively move the vehicle exactly .3 units over the course of 30 ms. If the next time elapsed is 60 ms, you would make up for the lost time and move .6 and in the course of one second, you will have moved exactly 10 units. Sound good?

Btw, with the angles, if you wanted to figure out which direction the vehicle were facing(i.e. for sprite rendering) you would still need angles. To get the angle from A to B you have to make DeltaX = Bx - Ax, and DeltaY = By - Ay(Not Ax - Bx or Ay - By). Otherwise, the angle that comes out will be opposite of what you want(This is the also an answer to the other question of why the directional offsets of enemyX and Y came out wrong at first).Use atan2(x,y)//not y,x, to get the angle in radians. To convert to degrees, multiply this by 57.295f(approx.). Now, the resulting angle CAN be negative! So you'll have to do this:
if(ResultAngle < 0)ResultAngle += 360;
This should get you the precise angle to turn to.
If the turn is delayed, meaning, its not an instantaneous turn, you should make it so that the vehicle takes the shortest time to turn, and not pull a near 360 to head in a certain direction.

-=~''^''~=-.,_Wicked_,.-=~''^''~=-

[edited by - Wicked Ewok on August 15, 2002 4:48:43 PM]
-=~''^''~=-.,_Wicked_,.-=~''^''~=-
The problem I see with that code is, assuming GetXPos() and GetYPos() return the position of the enemy, then the overall offsets from player could be large or small, affecting the movment rate. Which I assume is not what you want.

Directly after you calculate dirX and dirY, do this:

float denom = sqrt(dirX * dirX + dirY * dirY );
dirX = dirX / denom;
dirY = dirY / denom;

That way dirX and dirY represent a direction vector (unit length 1) instead of being the actual offset from the enemy to the player. And you will get a consistent movement rate.

Watch out for the enemy being right on top of the player though, that would make denom = 0 and you''ll get a division error!
It's not what you're taught, it's what you learn.
Here's what I have now --


    	DWORD time = CGameTime::Elapsed();			float dirX = (p_playerX - GetXPos());	float dirY = (p_playerY - GetYPos());	float denom = sqrt( (dirX * dirX) + (dirY * dirY) );	dirX = dirX / denom;	dirY = dirY / denom;	float dt = ( static_cast<float>(time) - static_cast<float>(GetLastTimeMoved()) ) / 10.0f;	SetXPos( GetXPos() + ( dirX * dt ) );	SetYPos( GetYPos() + ( dirY * dt ) );	SetLastTimeMoved( time );    


If dirX and dirY are 1 why even include them? I changed 1000.0f to 10.0f because he was moving ultra slow until I changed it.

So, finally, this code will make the enemy move the exact same rate on totally different machines and the enemy won't be moving at different speeds on the same machines like my code did earlier.

Am I right?

EDIT -- OK I left out the divide by zero error check, but other than that, that's what I have.

[edited by - randomDecay on August 15, 2002 5:01:06 PM]
Should work. Will you need the actual angle later ro render the sprites facing the right directions? Because if you''re going to get the angle of the sprites, there''s a faster way to move, using that angle, than to have to seperately calculate the directional vector with a sqrt formula. Just this:
Xoffset = SIN[ int(angle) ]*Speed*Time_Elapsed;
Yoffset = COS[ int(angle) ]*Speed*Time_Elapsed;
where SIN[] and COS[] are prebuilt arrays of 360 size of sin and cos values. Since both spew out values between -1 and 1, you will find that they work very well with what you need to do. So if you already need to find the angle for sprite rendering. Just use that method.

By the way, DirX and DirY being a unit vector doesn''t mean that their values are one. It means that the hypotenuse formed by X and Y was the sides is equal to 1. DirX and DirY will be < 1, but they will still point somewhere.

-=~''''^''''~=-.,_Wicked_,.-=~''''^''''~=-
-=~''^''~=-.,_Wicked_,.-=~''^''~=-
dirX and dirY aren't 1. dirX^2 + dirY^2 is 1. The VECTOR is length 1.

The only other possible problem I see is that dt must be reliably set to the amount of elapsed time between frames (I'm not sure if your calculation for dt accomplishes that), and maybe the 1000.0f could be changed to a different constant, depending on how fast you would like everything to move.

If CGameTime::Elapsed() returns the amount of time passed since last frame, you could just set dt to CGameTime::Elapsed() / 1000.0f, and do away with the SetLastTimeMoved() call.


[edited by - Waverider on August 15, 2002 5:23:11 PM]
It's not what you're taught, it's what you learn.
Kind of redundant now, but atan2 does work, but you have to negate the result:

angle = -(atan2(var,var))*(180/PI)

I had the exact same problem when not using the negated atan2 and it drove me nuts while everyone threw a multitude of different and usually much more long winded methods. AFAIK the -(atan2()) method is one of the fastest angle determination methods available.
------------------------------------------[New Delta Games] | [Sliders]

This topic is closed to new replies.

Advertisement