ID:1514979
 
(See the best response by Ter13.)
How would I get an atom's true direction using pixel movement? The code I was using for it does not work anymore (it functions properly, but when you step into the same tile as your target, it bugs up and defaults to EAST). Take a look at that code here.

Regards.
Basic linear algebra and some trig:

Getting the x/y delta between two objects:
var/ax = (a.x - 1) * TILE_WIDTH + a.step_x
var/ay = (a.y - 1) * TILE_HEIGHT + a.step_y
var/bx = (b.x - 1) * TILE_WIDTH + b.step_x
var/by = (b.y - 1) * TILE_HEIGHT + b.step_y

var/dx = bx - ax
var/dy = by - ay


Converting that into linear distance using the distance formula:
var/d = sqrt(dx**2 + dy**2)


Calculating Sine, and Cosine, and Tangent:

"Opposite" = Delta Y
"Adjacent" = Delta X
"Hypotenuse" = sqrt(Delta X**2 + Delta Y**2)


Sine = Opposite / Hypotenuse
Cosine = Adjacent / Hypotenuse
Tangent = Opposite / Adjacent

Remember: Do you even SOH-CAH-TOA, Bro?

Getting the degree value of sine/cosine:
arcsin(Sine)
arccos(Cosine)


Getting the angle between two points:
atan2(deltaX,deltaY)


Where:

proc/atan2(x, y)
if(!x && !y) return 0
return y >= 0 ? arccos(x / sqrt(x**2 + y**2)) : -arccos(x / sqrt(x**2 + y**2))


Check out this post for some decent and fairly optimized functions for you to use:

http://www.byond.com/forum/?post=1289853#comment4842721
Best response
FKI wrote:
when you step into the same tile as your target

I missed this bit earlier.

The reason that it bugs out and defaults to east, is because atan2 can't handle 0 , 0.

FIREKing's stuff is all meant for tile-based games only. You need to add the pixel step offsets into his distance formula in order to get the proper coordinates to test against.

Lemme convert his stuff over to pixel movement enabled stuff real fast:

#define TILE_WIDTH 32 //make sure to set these to your icon width/height
#define TILE_HEIGHT 32

proc/get_dir_adv(atom/ref, atom/target)
//Written by Lummox JR
//Modified by Ter13
//Returns the direction between two atoms more accurately than get_dir()

if(target.z > ref.z) . = UP
if(target.z < ref.z) . = DOWN

. = . | get_dir(ref, target)
if(. & . - 1) // diagonal
var/ax = abs((ref.x - 1) * TILE_WIDTH + ref.step_x - ((target.x - 1) * TILE_WIDTH + target.step_x))
var/ay = abs((ref.y - 1) * TILE_HEIGHT + ref.step_y - ((target.y - 1) * TILE_HEIGHT + target.step_y))
if(ax >= (ay << 1)) return . & (EAST | WEST) // keep east/west (4 and 8)
else if(ay >= (ax << 1)) return . & (NORTH | SOUTH) // keep north/south (1 and 2)
return .

proc/atan2(x, y)
if(!x && !y) return 0
return y >= 0 ? arccos(x / sqrt(x * x + y * y)) : -arccos(x / sqrt(x * x + y * y))

proc/get_angle(atom/a, atom/b)
return atan2((b.y - 1) * TILE_HEIGHT + b.step_y - ((a.y - 1) * TILE_HEIGHT + a.step_y),(b.x - 1) * TILE_WIDTH + b.step_x - ((a.x - 1) * TILE_WIDTH + a.step_x))

proc/get_dir_angle(atom/a, atom/b)
//converts an angle into a direction, for projectile facing
. = get_angle(a, b) + 270
if(. > 360) . = . * 0.0027 + . % 360
if(. >= 337.5 || . <= 22.5) return EAST
if(. >= 22.5 && . <= 67.5) return SOUTHEAST
if(. >= 67.5 && . <= 112.5) return SOUTH
if(. >= 112.5 && . <= 157.5) return SOUTHWEST
if(. >= 157.5 && . <= 202.5) return WEST
if(. >= 202.5 && . <= 247.5) return NORTHWEST
if(. >= 247.5 && . <= 292.5) return NORTH
if(. >= 292.5 && . < 337.5) return NORTHEAST
Much appreciated.