Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
Solved

# Working out the Angle Off Two Points

Posted on 2003-03-06
Medium Priority
409 Views
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
Question by:Dawid187
• 9
• 5
• 3
• +2

LVL 6

Expert Comment

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

LVL 50

Expert Comment

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

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

LVL 50

Expert Comment

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

Author Comment

ID: 8105532
ClockWise - at the very top-the first thing shows the angles eg 90 degrees is a straight line to the right
0

LVL 50

Expert Comment

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');
Writeln('Enter the Y point');
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 50

Expert Comment

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 50

Accepted Solution

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');
Writeln('Enter the Y point of target');
Writeln('Enter the MouseX point');
Writeln('Enter the MouseY point');
Writeln('Angle of mouse to target is ', AngleToTarget(MouseX, MouseY, X, Y):3:2);
end.
0

Author Comment

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

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 50

Expert Comment

ID: 8131832
0

LVL 50

Expert Comment

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: ');
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

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

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');
Writeln('Enter the Y point of target');
Writeln('Enter the MouseX point');
Writeln('Enter the MouseY point');
Writeln('Angle of mouse to target is ', AngleToTarget:3:2);
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: ');
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:
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 50

Expert Comment

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

ID: 9314368
Dawid187:
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
0

LVL 50

Expert Comment

ID: 9316789
Split between dbrunton and majestikm00se
0

Expert Comment

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

Author Comment

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

Question has a verified solution.

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

Welcome to 2018! Exciting things lie ahead in the world of tech. To start things off, we compiled great member articles on how to stay safe, ways to learn, and much more! Read on to start your new year right.
How do you create a user-centered user experience on your website? And what are some things you should consider in the process?
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calculâ€¦
Enter Foreign and Special Characters Enter characters you can't find on a keyboard using its ASCII code ... and learn how to make a handy reference for yourself using Excel ~ Use these codes in any Windows application! ... whether it is a Micrâ€¦
###### Suggested Courses
Course of the Month13 days, 9 hours left to enroll