SRL Archive - OSR Help

Working with ArcTan


Runescapian321

2010-06-13 00:45:42

I'm trying to make a function in reflection (so I'm using Simba) that finds the camera angle that you need to use to point towards a certain tile.

Here is what I have (technically it should be fully functional):

function GetTileDir(Tile: TTile): Extended;
var
Adjacent, Opposite: extended;
MyPos, MyTile: TPoint;
begin
MyPos := TileToPoint(GetMyPos);
MyTile := TileToPoint(Tile);
Adjacent := Abs(MyPos.y - MyTile.y);
Opposite := Abs(MyPos.x-MyTile.x);
result := ArcTan2(Opposite, Adjacent)*(180/Pi);
writeln('result = '+floattostr(result));
if MyPos.x > MyTile.x then
begin
if MyPos.y > MyTile.y then
result := 90 + result;
end else
if MyPos.y > MyTile.y then
result := 180 + result
else
result := 270 + result;
end;

I've tried testing, and it works most of the time, except when you're northeast or southeast of the tile. For example, I'm 4 spaces south and 2 spaces west of the tile. The function tells me the angle is about 18 degrees and thus shifts the compass to 288 degrees (north east east), when it clearly should be much closer to 360 degrees and north north east. Something is probably wrong with my math leading up to the ArcTan, anyone see the problem?

EDIT: Tested some more and it seems being directly south and directly east to the tile also don't work

Method

2010-06-13 01:09:40

First off, I believe you're passing the opposite values to ArcTan2. The y difference should be the opposite side, and the x difference the adjacent side. Try switching those and see how it works.

Also, you should account for cases where the x or y differences are zero and you can pinpoint the direction to 0, 90, 180, or 270 degrees.

edit: Actually, ArcTan2 may account for those cases. Try it out and see.

Runescapian321

2010-06-13 01:51:23

From: Method
First off, I believe you're passing the opposite values to ArcTan2. The y difference should be the opposite side, and the x difference the adjacent side. Try switching those and see how it works.


Well the parameters are ArcTan2(y, x: extended), so it would make sense that y is the opposite and x is the adjacent for this.

ArcTan2(1, Sqrt(3)) returns .5235…. (which is equivalent to Pi/6), which confirms it.


Also, you should account for cases where the x or y differences are zero and you can pinpoint the direction to 0, 90, 180, or 270 degrees.

edit: Actually, ArcTan2 may account for those cases. Try it out and see.


ArcTan2(0, 2) returns 0 (0 degrees)
ArcTan2(2, 0) returns 1.57 (Pi/2 or 90 degrees)

Then for 180: Pos.x = Tile.x and Pos.y > Tile.y so it should go result := result + 180
For 270: Pos.x < Tile.x and Pos.y = Tile.y so it should go result := result + 270

So that seems to be correct :\

By the way, since when did compass degrees begin going counter clockwise?

Method

2010-06-13 01:54:28

I've always known zero to be on the positive x-axis. Going counterclockwise from there, 90 is on the positive y-axis, 180 on the negative x-axis, and so on.

Runescapian321

2010-06-13 02:43:46

From: Method
I've always known zero to be on the positive x-axis. Going counterclockwise from there, 90 is on the positive y-axis, 180 on the negative x-axis, and so on.


Yes, that's the way I learned in math too, but apparently the compass directions are now…

case (LowerCase(setAngle)) of
'n': DirectionDeg := -1;
'w': DirectionDeg := 90;
's': DirectionDeg := 180;
'e': DirectionDeg := 270;
end;

EDIT: Oh wait, that's only reflection… Color is still

case LowerCase(Direction) of
'n': DirectionDeg := 0;
'w': DirectionDeg := 270;
's': DirectionDeg := 180;
'e': DirectionDeg := 90;
'random', 'rand': DirectionDeg := RandomRange(0, 360);
end;

Well that's a problem.

Narcle

2010-06-13 02:46:27

Your forgetting to get the current compass angle. I'd done this in my fighters using just minimap coords. I change my function over to Tiles this should work for it:

Function GetTileAngle(Tile: TTile): Integer;
var
M: TTile;
begin
M := GetMyPos;
Result := Round(Degrees(ArcTan2(Tile.y - M.y, Tile.x - M.x)) + 90 + rs_GetCompassAngleDegrees);
if (Result < 0) then
Result := Result + 360;
if (Result > 360) then
Result := Result - 360;
end;

Returns degrees atm, but u can change to Radians.

Runescapian321

2010-06-13 02:58:25

From: Narcle
Your forgetting to get the current compass angle. I'd done this in my fighters using just minimap coords. I change my function over to Tiles this should work for it:

Function GetTileAngle(Tile: TTile): Integer;
var
M: TTile;
begin
M := GetMyPos;
Result := Round(Degrees(ArcTan2(Tile.y - M.y, Tile.x - M.x)) + 90 + rs_GetCompassAngleDegrees);
if (Result < 0) then
Result := Result + 360;
if (Result > 360) then
Result := Result - 360;
end;

Returns degrees atm, but u can change to Radians.


I think your function is a little different than mine. Yours finds the location of a tile by degrees relative to your current position, right? I was trying to find the direction (in compass degrees) that I need to turn towards to face a tile. Therefore I don't believe I need the current compass angle, unless I misunderstood something.

I'm going to sleep, maybe my head will be clearer in the morning.

Narcle

2010-06-13 03:25:49

From: Tad
I think your function is a little different than mine. Yours finds the location of a tile by degrees relative to your current position, right? I was trying to find the direction (in compass degrees) that I need to turn towards to face a tile. Therefore I don't believe I need the current compass angle, unless I misunderstood something.

I'm going to sleep, maybe my head will be clearer in the morning.


Oh yes your correct. In that case just have to remove the rs_GetCompassAngleDegrees part and it should return the correct angle (for SRL's MakeCompass). The compass in game is different. 0 is South, 90 is West, 180 is North, 270 is East for in-game degrees.

Runescapian321

2010-06-13 16:36:20

From: Narcle
Oh yes your correct. In that case just have to remove the rs_GetCompassAngleDegrees part and it should return the correct angle (for SRL's MakeCompass). The compass in game is different. 0 is South, 90 is West, 180 is North, 270 is East for in-game degrees.


Hmm, I still had some problems using yours, but I figured out what I was doing wrong with mine.

I failed to realize that when you use arctan to figure out the angle of a 170 degree angle (in terms of reflection compass degrees), it will return 10 (not 80), something which I overlooked and tried simply adding 90 to (giving a result of 100, giving a south-west-west result instead of 170, a south-south-west result).

Here's the working function (I didn't change much from the original except for manipulating the angles at the end):

function T_R_GetTileDir(Tile: TTile): Extended; //Returns the Refleciton compass direction you must turn to face a tile
var
MyPos, MyTile: TPoint;
begin
MyPos := TileToPoint(GetMyPos);
MyTile := TileToPoint(Tile);
result := Degrees(ArcTan2(Abs(MyPos.x-MyTile.x), Abs(MyPos.y - MyTile.y))); //Finds the angle based on the closest y axis
if MyPos.x > MyTile.x then
begin
if MyPos.y > MyTile.y then
result := 180 - result; //If the tile is located south west of the player
end else
if MyPos.y > MyTile.y then
result := 180 + result //If the tile is located south east of the player
else
result := 360 - result; //If the tile is located north east of the player
end;

Thanks for the help.