Link to home
Start Free TrialLog in
Avatar of Dawid187
Dawid187

asked on

Working out the Angle Off Two Points

Ok Here it is, im coding a strategy game and for the movement i need to workout the Angle of the mouse towards the Units X/Y pos

Lets Say
X:=320
Y:=240
MouseX:=260;
MouseY:=600;
Angle:=???

I need the code to work out the angle for that assuming that straight up is angle 0 Eg
                     315      0      45
                              |
                              |
                     270------|------90
                              |     *
                              |    
                              |
                     225     180     132

I need A procedure that is very fast - In ASM if possible
Avatar of MannSoft
MannSoft

Stupid question, but why would you ask for an ASM solution in a Pascal board? :)
Avatar of dbrunton
The start of the solution is to zero the Units postion thus

MouseX  :=  MouseX - X;
MouseY  :=  MouseY - Y;

Now treat the X and Y as zero.   You state you want an angle, but referring to what axes?
Avatar of Dawid187

ASKER

Um Ok So We Treat X - Y as Zero thus
IF (MouseX > 0) And (MouseY > 0) Then ;The Angle Should be between 90 - 180 right

-- But thats Just What I Got
-- Need Code To return a accurate value of 360 cause im not working with just 8 Angles
Yes, but using the +ve x axis as zero or the +ve y axis?  Clockwise or anti-clockwise?
ClockWise - at the very top-the first thing shows the angles eg 90 degrees is a straight line to the right
Please Help
program TestArcTan;
var

X, MouseX : real;
Y, MouseY : real;

Angle : real;  {* in degrees *}
TanX : real;

begin
  Writeln('For testing purposes the Mouse is assumed to be at 0, 0');
  Writeln('Enter the X point');
  Readln(X);
  Writeln('Enter the Y point');
  Readln(Y);
  MouseX := 0;
  MouseY := 0;
  MouseX := X - MouseX;
  MouseY := Y - MouseY;
  if (MouseX = 0) and (MouseY = 0) then
    Angle := 0
  else if MouseY = 0 then
    begin
      if MouseX > 0 then
        Angle := 90
      else
        Angle := 270;
    end
  else if MouseX = 0 then
    begin
      if MouseY > 0 then
        Angle := 0
      else
        Angle := 180;
    end
  else
    begin
      TanX := MouseX / MouseY;
      TanX := Arctan(TanX);
      Angle := TanX * 180 / Pi;
      if (MouseX > 0) and (MouseY < 0) then
        Angle := 180 - Angle
      else if (MouseX < 0) and (MouseY < 0) then
        Angle := 180 + Angle
      else if (MouseX < 0) and (MouseY > 0) then
        Angle := 360 - Angle;
    end;
  Writeln('Angle to mouse is ', Angle:3:2);
end.


Assembler not possible.  I have a life to lead.  Test this code out.  Seems to work for me.
MouseX := X - MouseX;
MouseY := Y - MouseY;

should be

MouseX := MouseX - X;
MouseY := MouseY - Y;

if you drop in numbers for MouseX and MouseY.

But as it is it works because the MouseX and MouseY got zeroed beforehand.
ASKER CERTIFIED SOLUTION
Avatar of dbrunton
dbrunton
Flag of New Zealand image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
yo very thank u just two problems
then ill select urs as the answer
First 0 is at the bottom, i fixed it by changing the first thing
MousePtX := MousePtX - TargetX;
MousePtY := MousePtY - TargetY;
to
MousePtX := TargetX - MousePtX;
MousePtY := TargetY - MousePtY;
--- IS THIS WRONG ---
Then the second problem is the angle goes CCW
Eg 90 Degrees would be a horizontal line to the left where as i need it to the right
--- HERES WHAT I GOT   ------
            0/360 Degrees
             |
             |
             |
             |
             |
90_______________________270
             |
             |
             |
             |
             |
             180 Degrees
----- Heres What I need -----
            0/360 Degrees
             |
             |
             |
             |
             |
270_____________________90
             |
             |
             |
             |
             |
             180 Degrees
Thus in 3d it would be a axact 180 degrees rotation in X or in 2d Horizontal Inversion/Fliping Horizontally
I flipped it Veritacally by changing the first to lines of the code - but how do i flip it horizontally

JUST I WAS WRITTIN THIS I GOT A SOLUTION

 -- MousePtX := MousePtX - TargetX; --
 -- MousePtY := TargetY - MousePtY; --
Now This is how it looks
       0/360 Degrees
             |
             |
             |
             |
             |
270_____________________90
             |
             |
             |
             |
             |
             180 Degrees
Thanxs dbrunton but then there is the third problem
is i must work out XSPeed,YSpeed Depending upon the angle
thus if angle = 90 xspeed:=1;
thus if angle = 270 xspeed:=-1;
thus if angle = 180 yspeed:=1;
thus if angle = 0 yspeed:=-1;
thus if angle = 45 xspeed:=0.5,yspeed:=-0.5
thus if angle = 135 xspeed:=0.5,yspeed:=0.5
.......
but i need it more accurate - give me that solution and i will have my entire qeustion answerd and thank u very much
Dawid



Ohh and just for the record (the reason i had to ask this qeustion in the first place) im 14 thus i dont know trigonometry or what ever it u use to do these stuff i also dont have a big mind for these 2d,3d stuff , as soon as my game is finished i will post it here for u to dl
Oh and im writing it in Free Pascal(800*600*16bits yeah)
Probably about 48 hours away.
This should do it

program GetSpeed;
var
  Angle : real;


function CalculateXSpeed(TheAngle : real) : real;
begin
 TheAngle := TheAngle / 180 * Pi;
 CalculateXSpeed := Sin(TheAngle);
end;

function CalculateYSpeed(TheAngle : real) : real;
begin
  TheAngle := TheAngle / 180 * Pi;
  CalculateYSpeed := Cos(TheAngle);
end;

begin
  Writeln('Enter angle in degrees: ');
  Readln(Angle);
  if Angle >= 360 then
    Angle := 360 - Angle;
  Writeln('X speed is : ', CalculateXSpeed(Angle):2:2);
  Writeln('Y speed is : ', CalculateYSpeed(Angle):2:2);
end.

OK, not to be a "negative nancy" but you have to be careful when using TAN (really when dividing by SIN or COS) since this can give you a "divide by zero" error.
I assume that this is for moving from point A to point B, and you want to click & move?  Here's some "tighter" code building on dbrunton:

program TestArcTan;

var
  TargetX,TargetY :integer;
  MousePtX, MousePtY :integer;

function AngleToTarget:real;
{you don't need to pass global variables, but to use it "properly" as a function you should}
var
  angle:real;
begin
  MousePtX:=TargetX-MousePtX;
  MousePtY:=TargetY-MousePtY;

  if (MousePtX=0) or (MousePtY=0) then begin
    if (MousePtX=0) then
      if (MousePtY>0) then angle:=0 else angle:=180;
    if (MousePtY=0) then
      if (MousePtX>0) then angle:=270 else angle:=90;
    if (MousePtX=0) and (MousePtY=0) then angle:=360; {this signals you that there is an error}
  end
  else begin
    angle:=arctan(MousePtY/MousePtX)*180/pi+90;    
    if (abs(MousePtX)=MousePtX) then angle:=angle+180;
  end;
  AngleToTarget:=angle;
end;

begin
Writeln('Enter the X point of target');
Readln(TargetX);
Writeln('Enter the Y point of target');
Readln(TargetY);
Writeln('Enter the MouseX point');
Readln(MousePtX);
Writeln('Enter the MouseY point');
Readln(MousePtY);
Writeln('Angle of mouse to target is ', AngleToTarget:3:2);
Readln;
end.

Then use this code for the X & Y speeds (again, thanks to dbrunton, but you're making it WAY too complicated):

program GetSpeed;
{again, to use as a function, pass variables}
var
 Angle : real;

begin
  Writeln('Enter angle in degrees: ');
  Readln(Angle);
  if Angle>=360 then Angle := Angle-360; {(NOT 360-Angle)}
  Angle:=Angle/180*pi;
  Writeln('X speed is : ', (sin(Angle)):2:2);
  Writeln('Y speed is : ', -(cos(Angle)):2:2);
end.

NOTE: when moving at a 45 degree angle, the speed is half the square root of 2 (.71), NOT .5 as you had.

If you want the code to run faster, use radians instead of degrees. This will save several cycles on calculations to and from degrees.

If you don't know trig, I assume you don't know radians so here's a crash course:
There are 2 pi (~6.28) radians in a full circle, as opposed to 360 degrees.  So:
(radians) = (degrees)
2*pi = 360
pi = 180
pi/2 = 90
etc.

To stay with radians, leave the "*180/pi" off the calculations in the first part and the "/180*pi" in the second part, and when adding/subtracting, use the above equivalents.

Good luck.  Let me know when you get this thing finished too, I'd really like to play it.

P.S. dbrunton, quit losing sleep over this stuff, it ain't worth it. ;)
if Angle>=360 then Angle := Angle-360; {(NOT 360-Angle)}

Yep, missed that.  Only did it for the reason that Pascal treats 360 different from 0.   Really should have a loop that keeps going until the angle gets under 360 degrees in case someone drops in 720 degrees.



I think you'll find my original code takes care of all cases where you could possibly divide by zero.  All the zero cases are checked first.

 

Radians are faster but I left it as degrees as easier to bug test.  I know what 30 degrees is, and sin 30 and cos 60.  What that is in radians I wouldn't have a clue.



if (MousePtX=0) and (MousePtY=0) then angle:=360; {this signals you that there is an error}
I would suggest that this means the person is on the target and not an error.  I called this angle zero.



>>> {you don't need to pass global variables, but to use it "properly" as a function you should}
Habits developed from University.  Insisted we pass all variables into procedures and functions.  Yep, it slows code down but I found it's saved my butt a few times.  Plus looks nicer.





And nope, I won't lose sleep.  Interesting exercise.
Dawid187:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
Split between dbrunton and majestikm00se
Give the points to dbrunton.  He seems to be the "expert".  I just answer questions.
Okay I am very sorry about not posting for long, its just that they stole my computer and i lost the game(And source) but im doing something easier now which uses this same routine Thanxs Guys - the points goes do dburton for losing sleep

The new game im making is like Real Robots you look from the top and instead of playing the game you write your bot's ai before the time and then compete against each other

Thanxs alot for the Radian summary now i know that radians are and all fo that

The Question i have is done thanxs