?
Solved

Working out the Angle Off Two Points

Posted on 2003-03-06
19
Medium Priority
?
408 Views
Last Modified: 2010-04-16
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
0
Comment
Question by:Dawid187
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 5
  • 3
  • +2
19 Comments
 
LVL 6

Expert Comment

by:MannSoft
ID: 8089390
Stupid question, but why would you ask for an ASM solution in a Pascal board? :)
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 8091423
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?
0
 

Author Comment

by:Dawid187
ID: 8097139
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
0
On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

 
LVL 49

Expert Comment

by:dbrunton
ID: 8100412
Yes, but using the +ve x axis as zero or the +ve y axis?  Clockwise or anti-clockwise?
0
 

Author Comment

by:Dawid187
ID: 8105532
ClockWise - at the very top-the first thing shows the angles eg 90 degrees is a straight line to the right
Please Help
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 8107401
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.
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 8107419
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.
0
 
LVL 49

Accepted Solution

by:
dbrunton earned 100 total points
ID: 8107769
Sigh.  Here's a more correct version.  Mind worked on this and wouldn't let me sleep.  Found another mistake and corrected it.  It's now a function and returns angle.  You can input all four co-ordinates for testing purposes.  But it's the function you need and you can cut and paste it into your code.

program TestArcTan;
var
  X, MouseX : integer;
  Y, MouseY : integer;

function AngleToTarget(MousePtX, MousePtY, TargetX, TargetY : integer) : real;
var
  TanX, Angle : real;
begin
  MousePtX := MousePtX - TargetX;
  MousePtY := MousePtY - TargetY;
  if (MousePtX = 0) and (MousePtY = 0) then
    Angle := 0
  else if MousePtY = 0 then
    begin
      if MousePtX > 0 then
        Angle := 90
      else
        Angle := 270;
    end
  else if MousePtX = 0 then
    begin
      if MousePtY > 0 then
        Angle := 0
      else
        Angle := 180;
    end
  else
    begin
      TanX := Abs(MousePtX) / Abs(MousePtY);
      TanX := Arctan(TanX);
      Angle := TanX * 180 / Pi;
      if (MousePtX > 0) and (MousePtY < 0) then
        Angle := 180 - Angle
      else if (MousePtX < 0) and (MousePtY < 0) then
        Angle := 180 + Angle
      else if (MousePtX < 0) and (MousePtY > 0) then
        Angle := 360 - Angle;
    end;
  AngleToTarget := Angle;
end;

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

Author Comment

by:Dawid187
ID: 8130903
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



0
 

Author Comment

by:Dawid187
ID: 8130930
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)
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 8131832
Probably about 48 hours away.
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 8144790
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.

0
 

Expert Comment

by:Adam Mason
ID: 8170092
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.
0
 

Expert Comment

by:Adam Mason
ID: 8171516
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. ;)
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 8171937
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.
0
 

Expert Comment

by:CleanupPing
ID: 9314368
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.
0
 
LVL 49

Expert Comment

by:dbrunton
ID: 9316789
Split between dbrunton and majestikm00se
0
 

Expert Comment

by:Adam Mason
ID: 9320859
Give the points to dbrunton.  He seems to be the "expert".  I just answer questions.
0
 

Author Comment

by:Dawid187
ID: 9340568
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
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Check out the latest tech news, community articles, and expert highlights in August's newsletter.
The Summer 2017 Scholarship Winners have been announced!
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Suggested Courses

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question