ID:1957391
 
(See the best response by Ter13.)
Problem description:

I am sure the title sounds silly, but I am rather new to Dream Maker and while I'm making clear progress, there are some things that seem like they might be simple but I'm not quite yet able to figure out.

One of them is this... rather elusive tree...

So I want an object, such as this tree, that the player can walk behind/under.
In other words, the bottom half of the tree would be dense, but the top half would be drawn over the player as he walks "behind" the tree.

Whether this can be done with one object or must be done with two objects (one for the bottom half and the other for the top half) is fine, I'll work with either, but I'm not quite sure how to do it (if it's possible).

To add to the complication, I (much) later plan to give the player the ability to chop down the tree to obtain wood. In which case, I'd be changing the tree's icon to become a treestump.
However, I'm also not sure for if the tree WAS in fact made of two separate objects, how to make the top half disappear at the same time the bottom half is turned into a stump.

P.S.
I do have one other smaller issue: I notice by default, the game allows the player to move freely between pixels as opposed to on a grid. I see that you can change the rate of which the player moves but I was wondering if there was a way to lock them to a (say, 32 x 32) grid? It tends to make collisions less obtrusive.
Best response
Not even necessary to do all that crossing and whatnot.

#define TILE_HEIGHT 32 //you may need to adjust this
#define LAYER_BASE 1 //you shouldn't need to adjust this
#define PIXEL_LAYER 0.00001 //you shouldn't need to adjust this either.

atom
var
standing = 0 //set to 1 to adjust the layer based on the y position of this object
base_layer //the default layer
y_offset = 0 //number of pixels to offset the layering by
proc
UpdateLayer()
if(standing)
layer = base_layer + LAYER_BASE - ((y-1)*TILE_HEIGHT + y_offset)*PIXEL_LAYER
else if(layer!=base_layer) //only reset the layer when needed
layer = base_layer

New()
base_layer = layer
if(standing) UpdateLayer()
..()

movable
UpdateLayer()
if(loc&&standing) //only update the layer when we're on the map
layer = base_layer + LAYER_BASE - ((y-1)*TILE_HEIGHT + step_y + bound_y + y_offset)*PIXEL_LAYER
else if(layer!=base_layer) //only reset the layer when needed
layer = base_layer

Move()
. = ..()
UpdateLayer() //update the layer after the movable has moved


Any objects that are marked standing will always adjust their layers based on their bounding box's bottom y position in the world. This will only be updated when an object moves, or when it's initialized.

GreatPirateEra's solution is going to be ridiculously complex to get working right. The above is incredibly simple and works very, very well.
Alright, so I'm trying to learn from this here, so bear with me. (I should also probably add that not only am I new to DM, but programming in general. Though I did learn some DM around 6 years ago(?), I haven't used it in a long time and have mostly forgotten it.)

We defined the tile height (32, as the majority of my icons are 32x32), and the base/default layer (1). I'm not sure what "PIXEL_LAYER" is quite yet.

We created variable representing the base layer, as well as a variable determining whether to enact this effect (standing), and the y-offset variable which I assume determines how the layering occurs.

Then we created the procedure for it to happen.
If the subject is standing (standing = 1?)
There's that formula.... which I'm having a little bit of difficulty breaking down.

I imagine "base_layer" is the layer that the subject is already on. So there layer becomes base + 1...
- ((y-1) * 32 + 0) * 0.00001

I'm not sure what y-1 is in this scenario, or how the y_offset should work, or why the PIXEL_LAYER is such a tiny decimal.

And then I understand that if the player is not standing, then if the layer isn't the base_layer, make it the base_layer.

I now notice base_layer doesn't mean the layer they were currently on. (Otherwise, layer would always = base_layer).
So I suppose it's the default layer DM uses, unless I choose to change it?

From here on, things get a little more confusing.
I'm not sure what New() does, though I imagine this is what occurs when an object is loaded into the world?
I suppose that sets it apart from Login(), which only effects the current player who just logged in.

It... defines base_layer.

.... Okay, so I was wrong again. "base_layer" refers to the layer the object was in when it was first created. Got it.
If the subject is standing, run the Update Layer procedure. Got it.

Then it further defines the procedure for subjects that can move. (?)

If the subject is on the map, and is "standing"
Then there layer = the formula:
(base + 1 - ((y-1)*32 + step_y + bound_y + 0) * 0.00001

Where as I still do not know (y-1) (though where I previously was looking at it like an algebraic variable, I'm starting to realize it refers to the coordinates the subject is on?)
I also do not know step_y and bound_y, where I should probably take some of GreatPirateEra's advice and look up bounds so I can understand what they are.

Then, if the movable is not on the map OR not "standing", and the layer is not already the base_layer, make the subject's layer the base_layer.

Also, run UpdateLayer every time the subject moves.

Okay.
That's what I got from all that.

So then here's where I flop and make everyone facepalm (if I haven't already):

Since I don't understand the formula too well, but understand it requires "standing" to be active, I wrote "standing = 1" under mob. This had no effect, as I still walked on top of the top half of the tree.

I then deleted that from the mob, and wrote it on the tree. "standing = 1". It still seemed to have no effect.

Can someone help me break this down further, help explain the bits I did not understand, and how to implement this code effectively?

ALSO: I imagine what this does is keep the bottom 32 pixels dense while the rest goes over the player. I may be wrong on that as well.

This also makes me worry about larger objects, that aren't 32x64. Say, a house, or a bigger tree.

However, if it does the opposite, and keeps the top 32 pixels layered over and the rest dense, that works fine for most things except say, lampposts.

LASTLY: I'm still looking on how to confine movement to a 32x32 grid.
Both your player and your tree should be set to standing, and both should have the same layer variable.

What the UpdateLayer() proc does, is modify the layer variable of the player based on their y distance from the bottom of the map. This makes it so that objects closer to y 1 are layered slightly in front of objects further from 1 on the map.

the LAYER_BASE variable is mostly irrelevant. It just means that there will be a variance of 1 integer value on standing objects. This is really meaningless and the only time you would need to adjust this is if your map is absurdly big.

The PIXEL_LAYER variable is multiplied against the y position of the player. The Y position is calculated based on their:

y coordinate minus 1 * pixel height of tiles (converts y tile coordinate into pixels) +
y_offset + (the next two are only for movable atoms)
bound_y +
step_y

This is how you calculate where the base of the object is on the y coordinate. Objects that are further forward will layer over objects that are further back. It's pretty simple. y_offset is for cases where you want the layering to be moved up or down a little bit to make things look right without disturbing the other location variables.

base_layer is used to track what the normal layer of the object is. If you want to change the layer of something, you should change base_layer then call UpdateLayer(). Any time an object is moved, you want to call UpdateLayer(). Any time an object is created and it is standing, you want to call UpdateLayer().

To implement this in your case:

mob
standing = 1

obj
tree
icon = 'tree.dmi' //let's say it's a 96x96 icon
bound_width = 32 //adjust the bounds
bound_height = 32
bound_x = 32
standing = 1 //set it to standing
layer = MOB_LAYER //make sure it's on the same layer as the mob
y_offset = 16 //let's make it layer like it's 16 pixels above where it's actually based


That's all there is to it. This will make it so that players will actually appear behind things when they are north of them, but in front of them when they are south of them. All without having to deal with any messy Cross()/Crossed() business or dicking around with per-player image objects.

Let me know if you have any other questions.
Aha!
It's working!
I've learned a lot through this so thank you!

GreatPirateEra
That seems to have worked, but now the player is moving across the map at breakneck speeds. Is it possible to slow him/her down while keeping 32-pixel movement?

You both are amazing, thank you so much~
Is it possible to slow him/her down while keeping 32-pixel movement?

Yes. Look up Move(). You'll want to override move. When you override something, you can call the default behavior using "..()" (supercall). Move() has to return a value, so you want to use ". = ..()" or "return ..()" (return supercall) to preserve the default behavior. Look up "..()" and "." in the reference while you are at it.

You can cancel a movement by returning 0 before performing the supercall. My advice would be to store the time of the next allowed movement in a variable on the movable. You can set this time simply by using "next_move = world.time + move_delay".

At the beginning of the movement, simply check if "next_move>=world.time" to return zero.
In response to Ter13
Ter13 wrote:
Look up Move().

Look up "..()" and "." in the reference while you are at it.

You know...
I keep seeing this "reference" be referenced. And there's even a sticky post about improving the "reference". It sounds like something very necessary in learning this whole thing, and incredibly helpful.

The problem is, I don't know what it is, and where to find it. Which makes me feel especially silly because I bet it's been right in front of me the whole time. But I'm looking everywhere for it and I can't seem to find it...

If someone might point the way, that'd be perfect. I have a lot of studying to do! Haha.

EDIT:
No worries, I found it pretty much immediately after posting.

Thank you so much everyone, and I shall be looking into it!
In response to OroCrimson
Press F1 in Dream Maker. There's also a web version, but the former is better IMO since you can highlight terms (or even place your cursor in the middle of one) and go to the exact term, or a term close to it (if an exact isn't found) very easily.
In response to FKI
Oh, it's built into Dream Maker? That's something I didn't know either.

Thank you!