ID:841137
 
(See the best response by Forum_account.)
Code:
mob

bound_x = 9
bound_y = 1
bound_height = 16
bound_width = 16
step_size = 16


Problem description:

Hey guys~
I'm having a bit of an issue here, I'll explain what I think is going on.

A normal tile is 32x32, and that's the default step_size. I'm setting it to 16, which is half of the default. This allows, essentially, 2 mobs at least to be on one tile (and since the bound width and height are set to 16, even 4 on one tile I believe).

Now, the mobs start centered on the tile. One step in any direction would put them half on one tile, half on another.

Yet, when you do things like walk into a wall, or another mob for that matter.. you get knocked off center, approximately 8px I believe, off center.

This means you're on literally half a tile at a time. That'd be ok, but the switching around seems buggy when moving.

I read up on Move() a bit, and it says a slide is when you can't complete the full step_size, so you just kinda.. complete what's possible.

Is it possible to simply negate sliding?

In theory this would be possible to accomplish by overriding /atom/movable/Move() and preventing movement if it does not cause you to move the full value of step_size (in your case for mobs it's 16px).

The first thing you'd want to check is if NewLoc is not directly next to the player. If this is the case movement should occur normally, as this is considered a jump.

You will then want to store the current location of the atom + the step_x/step_y variables in a variable for later use.

If not then the movement is considered a slide. You'll then want to check if the player is able to get to that tile. You could do this by performing . = ..().

If the dot variable (.) is not equal to step_size you would move the player back to the old location and reset the step_x/step_y variables to their old values. Then you would return 0 to indicate that the movement has been blocked.

Otherwise, you allow movement to pass through.

AFAIK this would do what you want: if a player can't move the full step_size it would prevent movement. Note that if you use my exact method it would still call procs like Entered and Crossed even if the movement failed.

You may want to take a look at this post which has a soft-coded version of the movement system. Note that this was designed before the introduction of pixel-based movement.
Move() returns the number of pixels that it was able to move. You should be able to check if the move was only a partial one and move the mob back - if you tried to move 16 pixels and only moved 4, move them back 4 pixels to their original position.
    mob/Move()
var/original = loc
if(NewLoc < step_size)
loc = original


I expect this is the idea behind it?
NewLoc isn't a working variable though, I don't really have a clue how to calculate what direction the mob is moving into.
Best response
You can just remember the mob's old loc, step_x, and step_y, then call ..() and revert them back to the old loc/step_x/step_y if the move was smaller than the step_size. Something like this:

mob
Move()
var/old_step_x = step_x
var/old_step_y = step_y
var/old_loc = loc

. = ..()

if(. < step_size)
loc = old_loc
step_x = old_step_x
step_y = old_step_y
return 0
I don't really have a clue how to calculate what direction the mob is moving into.

BYOND provides a variable to tell you this.

Moving east sets your direction to east, moving west, to west, and so on. I believe this happens before any actual movement takes place, but I could be wrong.

Edit: F_A already provided a working solution, I see.
Alright, fair enough.

I've never really used the single dot operator, can someone give me some information about it? it seems like..

. = ..() is.. adding the parent proc's behavior into the child proc.
. is the return value of the current proc. You could do this instead:

mob
Move()
var/old_step_x = step_x
var/old_step_y = step_y
var/old_loc = loc

var/pixels_moved = ..()

if(pixels_moved < step_size)
loc = old_loc
step_x = old_step_x
step_y = old_step_y
return 0

return step_size
Nice! It works great.

There is one thing that bothers me though;
Before this was added, since only the bounds were set to take account for the lower half of the mob, the upper half could be drawn on top of walls and such if you had gotten close enough, it created a certain feeling of depth which I liked.

There should technically still be 16 pixels between the mob and the wall, and then none would be left.. why is it stopping it?
bound_x/y are offsets, so to place the bounding box on the origin you would want a value of 0 and not 1. As it is, your object takes up (in the 'y' direction) pixels 2 to 17 (of an area of 1-32), leaving only 15 pixels for the upper area and not 16.

Set bound_x to 8 and bound_y to 0 and I think it'll work as you expect.
Aha, thank you!