ID:2107399
 
I want to start with a precursor: I've been around the block with BYOND and programming in general (5+ years), so I'd say I have at least intermediate-level knowledge/understanding of DM. That said, my latest project is my first time not ignoring Pixel Movement since its inclusion, so I've been asking lots of questions and approaching things as a newbie.

tl;dr: bear with me

As for the actual question:
How would one display/place/etc. things relative to the bounding box of an atom? With Pixel Movement allowing things to essentially be between tiles or within 2 turfs' locs at once, I'm finding myself in unfamiliar territory. To elaborate, in comfy pre-pixel movement land, if I wanted, say, a box to appear in front of the player, I'd just set its loc to get_step(player,player.dir); simple. While this technically still works, visually the box would be displaced due to the player's positioning (step_x/y n all that). So yeah, is there a proc I can call to get that bounding box information, and if not, what would be a good way to go about making my own getter?

Here's one way to do it (without using any library):
var forward = 0 // how far away (from touching, in pixels)
var right = 0 // how far off-center (in pixels)
b.loc = a.loc
b.step_x = ((a.dir & 12) ? ((a.dir & 4) ? 1 : -1) * ((a.bound_width + b.bound_width ) / 2 + forward) : (a.dir & 1) ? right : -right) + a.step_x + a.bound_x - b.bound_x + (a.bound_width - b.bound_width ) / 2
b.step_y = ((a.dir & 3) ? ((a.dir & 1) ? 1 : -1) * ((a.bound_height + b.bound_height) / 2 + forward) : (a.dir & 4) ? -right : right) + a.step_y + a.bound_y - b.bound_y + (a.bound_height - b.bound_height) / 2

Basically, this puts object 'b' at a position in front of object 'a' where they're both touching and 'b' is aligned with the center of 'a'. You can add a distance between them using 'forward', and a perpendicular offset using 'right'.

The part starting at a.step_x is the b.step_x required to align their centers horizontally, and same for a.step_y. The stuff before a.step_x and a.step_y is the relative offset.

(probably doesn't play nicely with diagonal directions)
In response to Kaiochao
FKI wrote:
Try this: http://www.byond.com/developer/Kaiochao/absolutepositions

Kaiochao wrote:
Here's one way to do it (without using any library):
> var forward = 0 // how far away (from touching, in pixels)
> var right = 0 // how far off-center (in pixels)
> b.loc = a.loc
> b.step_x = ((a.dir & 12) ? ((a.dir & 4) ? 1 : -1) * ((a.bound_width + b.bound_width ) / 2 + forward) : (a.dir & 1) ? right : -right) + a.step_x + a.bound_x - b.bound_x + (a.bound_width - b.bound_width ) / 2
> b.step_y = ((a.dir & 3) ? ((a.dir & 1) ? 1 : -1) * ((a.bound_height + b.bound_height) / 2 + forward) : (a.dir & 4) ? -right : right) + a.step_y + a.bound_y - b.bound_y + (a.bound_height - b.bound_height) / 2
>

Basically, this puts object 'b' at a position in front of object 'a' where they're both touching and 'b' is aligned with the center of 'a'. You can add a distance between them using 'forward', and a perpendicular offset using 'right'.

The part starting at a.step_x is the b.step_x required to align their centers horizontally, and same for a.step_y. The stuff before a.step_x and a.step_y is the relative offset.

(probably doesn't play nicely with diagonal directions)

Didn't expect this to be as complicated as it appears at a glance to be honest... Kind of begs the question of why institute pixel movement into DM only to half-bake it and not update existing positioning procs to support these displacements...
To be fair, get_step() by itself doesn't quite cut it in tile movement either, when the objects aren't the same size. You'd still end up using the code I wrote, even in tile movement, if you didn't want overlap with objects that aren't just 1 tile big.

If everything is 1 tile big with no bound_x/y offsets, you can use get_step():
b.loc = get_step(a, a.dir)
b.step_x = a.step_x
b.step_y = a.step_y

The code I wrote before accounts for different bound_x/y and bound_width/height between both objects, but it simplifies to this if everything's equal.
In response to Kaiochao
Kaiochao wrote:
To be fair, get_step() by itself doesn't quite cut it in tile movement either, when the objects aren't the same size. You'd still end up using the code I wrote, even in tile movement, if you didn't want overlap with objects that aren't just 1 tile big.

If everything is 1 tile big with no bound_x/y offsets, you can use get_step():
> b.loc = get_step(a, a.dir)
> b.step_x = a.step_x
> b.step_y = a.step_y
>

The code I wrote before accounts for different bound_x/y and bound_width/height between both objects, but it simplifies to this if everything's equal.

Yeah I was able to successfully implement your first example into a universal proc (thanks much), I was just complaining about the fact that there's no in-built proc(s) for this already as it's definitely something that will be necessary/used a lot
There's not a built in for tile based movement either. It's not a strictly required game development tool, more abstract than that.
In pixel movement, it's better to completely ignore the tile system by using procs that deal only in absolute pixel coordinates or relative pixel offsets, such as the ones in my Absolute Positions library. The procs I use from there most often are atom.Cx(), atom.Cy(), movable.SetCenter(), and movable.Translate(). Here's my first snippet in terms of those procs (and expanded for readability):
// place 'src' in front of 'M'
atom/movable/proc/MoveToFront(atom/movable/M, ExtraForward = 0, ExtraRight = 0)
var
// the new center position of src to be calculated
// starting from the center of M
new_center_x = M.Cx()
new_center_y = M.Cy()

// the vector that points in the direction of M
// each component is either 0, 1, or -1
// (this is typically made into a proc)
forward_dx = M.dir & (EAST|WEST) && (M.dir & EAST ? 1 : -1)
forward_dy = M.dir & (NORTH|SOUTH) && (M.dir & NORTH ? 1 : -1)

// the vector that points to the right of M
// used to apply the ExtraRight offset
right_dx = forward_dy
right_dy = -forward_dx

// move src in M's direction to avoid overlap after being centered
new_center_x += forward_dx * (M.bound_width + bound_width) / 2
new_center_y += forward_dy * (M.bound_height + bound_height) / 2

// apply ExtraForward
new_center_x += forward_dx * ExtraForward
new_center_y += forward_dy * ExtraForward

// apply ExtraRight
new_center_x += right_dx * ExtraRight
new_center_y += right_dy * ExtraRight

SetCenter(new_center_x, new_center_y, M.z)

It's the same calculations, but you don't need to directly deal with loc, step_x, step_y, bound_x, or bound_y.
In response to Kaiochao
Kaiochao wrote:
In pixel movement, it's better to completely ignore the tile system by using procs that deal only in absolute pixel coordinates or relative pixel offsets, such as the ones in my Absolute Positions library.

I only glanced at the library's code when you first linked it, but now that my understanding of pixel movement is growing (thanks to you guys' help) I'm going to set aside some time today to try and fully digest the library.