ID:1304911
 
(See the best response by Kaiochao.)
Problem description:
So I have my mob's bound_y set significantly lower than their bound_x to create an overlaying effect. It wouldn't make any sense if a mob was moving south towards another mob and the his feet bumped into the other mob's head. It has a significantly more appealing look, and it's a much desired effect. However...

It only works half of the time. The last mob to move, always winds up on top. How do I fix this?

Either use the SIDE_MAP map_format (which is pretty glitchy), or use a custom layering system that adjusts your layer according to your vertical position.
turf
Enter()
..()
for(var/atom/movable/M in obounds(src,x,-16,0,0))
M.layer ++


Exit()
..()
if(usr.layer > 4)
usr.layer = 4


So this is what I came up with. I was pretty confident about it, but it's halted all movement. >.>
In response to Khye
Best response
Your code halts movement because you're overriding the proc whose return value determines whether something can enter or exit a certain turf, and you don't return the proper value. It's wrong because it's not the right place for that particular code, and the code itself is not robust.

Here's what I came up with.
atom
var standing = FALSE

proc/update_layer() if(standing)

// If you're using pixel movement:
var const/tile_height = 32
layer = MOB_LAYER - (tile_height * (y - 1) + bound_y + step_y) / (tile_height * world.maxy)

// If not:
layer = MOB_LAYER - y / world.maxy

// Either way:
mob
standing = TRUE
Move()
. = ..()
. && standing && update_layer()

Atoms with "standing = TRUE", such as mobs, trees, pillars, etc. will have a higher layer than other standers farther north than them.
Lol this is what I had gotten to before I read you last post:

Move()
if(layer > 4)
layer = 4
if(dir == SOUTH)
for(var/atom/movable/M in obounds(src,-16,-16,0,0))
M.layer ++
if(dir == EAST)
for(var/atom/movable/M in obounds(src,16,-16,0,0))
M.layer ++
if(dir == WEST)
for(var/atom/movable/M in obounds(src,-16,-16,0,0))
M.layer ++
..()


Wasn't working like I hoped. Yours works great. ^^ Thank you. You don't think it'll create a lot of overhead though do you?
In response to Kaiochao
Kaiochao wrote:
Your code halts movement because you're overriding the proc whose return value determines whether something can enter or exit a certain turf, and you don't return the proper value. It's wrong because it's not the right place for that particular code, and the code itself is not robust.

Here's what I came up with.
> atom
> var standing = FALSE
>
> proc/update_layer() if(standing)
>
> // If you're using pixel movement:
> var const/tile_height = 32
> layer = MOB_LAYER - (tile_height * (y - 1) + bound_y + step_y) / (tile_height * world.maxy)
>
> // If not:
> layer = MOB_LAYER - y / world.maxy
>
> // Either way:
> mob
> standing = TRUE
> Move()
> . = ..()
> . && standing && update_layer()
>

Atoms with "standing = TRUE", such as mobs, trees, pillars, etc. will have a higher layer than other standers farther north than them.

I've been trying to get this to work with an object that is made of many parts to form its "stance"... but I'm not having any luck. Any hints?
In response to FIREking
Many parts? With like, overlays with negative layer?

This is just designed for individual objects of any size. It's as if the objects are "standing up" in 3D space, with the bottom edge of their bounding box as the base.
In response to Kaiochao
Kaiochao wrote:
Many parts? With like, overlays with negative layer?

This is just designed for individual objects of any size. It's as if the objects are "standing up" in 3D space, with the bottom edge of their bounding box as the base.

Like lets say a pillar just for basic example, which is able to be "knocked over" so it is made up of 3 or 4 "tiles" as opposed to a single tall icon.
In response to FIREking
Oh, so you'd want something like a "height" offset, because the parts of the pillar are supposed to be stacked on top of each other.

//  This would be a 3D z-offset, or something.
// The higher something is, the lower its layer should be,
// because its base is actually lower than it appears.

atom
var pz = 0

// In pixel movement:
layer = MOB_LAYER - (tile_height * (y - 1) + bound_y + step_y - pz) / (tile_height * world.maxy)

// In tile movement:
var const/tile_height = 32
layer = MOB_LAYER - (y - pz) / (tile_height * world.maxy)

With this, you'd have to set the pz of each piece of the pillar.

Edit: I meant for pz in the "tile movement" example to be in "pixels" like the first example, but I guess it makes more sense this way.
Cool, this worked for me once I put some parenthesis in there:

atom
var standing = 0
var pz = 0

proc/update_layer()
if(standing)
layer = MOB_LAYER - ((y - pz) / 64) / world.maxy

New()
..()
update_layer()

mob
standing = 1
Move()
. = ..()
. && standing && update_layer()


//example
turf/pillar/bottom
standing = 1
pz = 0
turf/pillar/middle
standing = 1
pz = 1
turf/pillar/top
standing = 1
pz = 2
In response to FIREking
The difference between these lines:
(y - pz / tile_height) / world.maxy

and

(y - pz) / world.maxy (FIREking should use this)

...is that the pz in the first is supposed to be in pixels (so it's divided by tile_height to get it on the same scale as y), while the pz in the second is in tiles (which is already in the same scale as y).

Scaling with tile_height when everything is already in tiles is pointless, too.
So the full corrected version is
atom
var standing = 0
var pz = 0

proc/update_layer()
if(standing)
//for tile_based worlds
layer = MOB_LAYER - (y - pz) / world.maxy

New()
..()
update_layer()

mob
standing = 1
Move()
. = ..()
. && standing && update_layer()