Pixel Movement

by Forum_account
Pixel Movement
A pixel movement library for isometric and top-down maps.
ID:1059248
 
Keywords: objs, pixelmovement
I am a tad new to this library, so sorry if this question is obvious and I'm just blind:

I want to change the starting px and py for objs when they are generated on the map. The reason for this is because I've been making a random dungeon generator, and so far it works pretty well, however the issue is that when objs are created (like chests, traps, etc.), they always appear on the bottom left corner as that's how the icon is set up. I have the icon set up that way due to the bounding box mechanics, and the only way I could see to get the bounding box to properly work on the objs is to have their icon on the bottom left of the image. Besides, even if there is a way around this, I would prefer to have their exact px and py randomized because most of these are around 20-30x20-30 pixels, and the icon size I am using is 64x64. It would look stupid to have them in the same exact place on a single tile every time they are created.

For mobs this isn't really an issue, I just have them move slightly when they are generated and as a result they are able to appear truly randomized, HOWEVER...when objs are created I cannot do this. I want them to be able to appear randomized, however whenever one is generated on a corner or edge of a room, they are always an exact distance from said edge, whether it be hugging them or X pixels away. It looks really bad, especially considering they are supposed to be randomly placed anywhere on the map.

So to try and fix this issue, I added the following to my New() for objs:
        
New()
..()
if(src.randomizePLoc)
var/randomPX = rand(0, (PixelMovement.tile_width-src.pwidth))
var/randomPY = rand(0, (PixelMovement.tile_height-src.pheight))
src.px += randomPX
src.py += randomPY


This does nothing. I'm not exactly sure what I'm missing, because px and py are the parameters used to determine pixel location as far as I can see. I tried using several of the procs provided in the Demos, however since the demos use mobs for these types of movements and these are objs, I've hit a standstill.

I've honestly been able to figure out a lot of issues just by going through the demos and the like and learning the library, as I should, however this really has stumped me. I do not know of any of the movement methods that work with objs, I cannot find any. Making things that are objs mobs just so that I can have them shift a little from their default location sounds stupid to me, so I'd rather not do that.

Any help would be greatly appreciated. If screenshots are needed, I can provide them to show exactly what I mean is the problem.
This actually doesn't apply to objs.

Se the thing is, objs don't update with the movement() proc, so it needs to be done manually.

What I also noticed is that generated objects don't have a px or py either. When generated they come out as 0 which has caused me to fly off the map when bumping into them on occasion.

When generating an object you'll want to do is first make the adjustment to pixel_x and pixel_y and then use that to determine it's px and py, it's a bit backwards but it saves a step and some math since they don't auto update through movement(). OR you could do it your way and then adjust the pixel position as well..


in your method...
    New()
..()
px=x*world.icon_size
py=y*world.icon_size //This makes sure that the px and py are properly set ahead of time
if(randomizePLoc)
var/randomPX = rand(0, (PixelMovement.tile_width-pwidth))
var/randomPY = rand(0, (PixelMovement.tile_height-pheight))
px += randomPX
py += randomPY //then we modify the px and py
pixel_x += randomPX
pixel_y += randomPY // and the pixel_x and pixel_y


That should fix the visual issue you get with the icon, but I'm not 100% on this as I can't test it myself without writing up a new environment and I'm pretty lazy, haha.

Now if you get an issue where the physical position and the visual position are different then remove the pixel_x and pixel_y portion as it may just be the fact that the px and py were wrong from the get-go

ALSO quit using " src. " you almost never have to use src. when it comes to DM in general as DM automatically assumes that a variable is referring to src. =P
In response to Bravo1
Bravo1 wrote:
This actually doesn't apply to objs.

Se the thing is, objs don't update with the movement() proc, so it needs to be done manually.

What I also noticed is that generated objects don't have a px or py either. When generated they come out as 0 which has caused me to fly off the map when bumping into them on occasion.

When generating an object you'll want to do is first make the adjustment to pixel_x and pixel_y and then use that to determine it's px and py, it's a bit backwards but it saves a step and some math since they don't auto update through movement(). OR you could do it your way and then adjust the pixel position as well..


in your method...
>     New()
> ..()
> px=x*world.icon_size
> py=y*world.icon_size //This makes sure that the px and py are properly set ahead of time
> if(randomizePLoc)
> var/randomPX = rand(0, (PixelMovement.tile_width-pwidth))
> var/randomPY = rand(0, (PixelMovement.tile_height-pheight))
> px += randomPX
> py += randomPY //then we modify the px and py
> pixel_x += randomPX
> pixel_y += randomPY // and the pixel_x and pixel_y
>
>
>

That should fix the visual issue you get with the icon, but I'm not 100% on this as I can't test it myself without writing up a new environment and I'm pretty lazy, haha.

Now if you get an issue where the physical position and the visual position are different then remove the pixel_x and pixel_y portion as it may just be the fact that the px and py were wrong from the get-go

I will try that out, thanks.

Edit: Okay, so that resulted in some weird issues. I have traps inside of walls, and my chests are nowhere to be seen (probably because they are dense). The traps I can see disappear when I get past a certain point on the X axis...but if I change the view to 35 (was an old verb that I used to check out dungeon designs, to make sure it was working properly), they are visible on the walls.

After some repeated attempts, I got a chest to appear in a hallway (which it shouldn't), and when I got near it it disappeared and I could go through it, but when I moved away from it it appeared again.

Not sure why this would happen, I have nothing changing the px, py, pixel_x, or pixel_y of objs outside of this new code.


Edit 2: Okay I did a silly. I accidentally multiplied PixelMovement.tile_whatever by pwhatever when copying the code you provided (I had deleted it soon after posting the thread, probably should have just commented it out). Half asleep so I misread it.

But, alas, there's still an issue. There's some weird attaching going on to objects that are moved and dense. I added a chest to the base map, and when I hit it from the left side, I get stuck to it, and when trying to get off, eventually I get teleported to the other side of it. I think it has something to do with the bounding box not being changed properly for the object. If the icon is moved too far outside the original corner, I notice that the corner where it starts out is where this glitch is occurring, and I can move straight through the icon.

I shall investigate further, but if you have any insight it would certainly help.

ALSO quit using " src. " you almost never have to use src. when it comes to DM in general as DM automatically assumes that a variable is referring to src. =P

I know I don't. It's personal preference. I know that it makes absolutely no sense to do it because it is defaulted, but it's some personal OCD type thing that I like doing it anyway. It just adds some typing, but otherwise I don't think it really matters in the long run, so meh. Ironically, I don't use the hell out of this in Java, so I'm not really sure why I like using src in BYOND.
It sounds like the icon is shifted away from the physical bounds of the object. Try it without modifying pixel_x and pixel_y and just make sure that the px and py are set properly and then move the px and py to adjust for the change.
Hrm...

If I do not modify pixel_x or pixel_y, nothing changes at all. The icon is still at the lower bounds of the tile along with the bounding box.

So I thought I would try something.
I changed the New() code to the following:
    New()
..()
pixel_x = src.x * world.icon_size
pixel_y = src.y * world.icon_size
px = pixel_x
py = pixel_y
sleep(10)
world << "[src.x],[src.y]"
world << "[src.pixel_x],[src.pixel_y]"


The sleep is there simply so that I actually get output I can see, because the world and obj are generated before my client is connected.

I get the following output:
4,4
256,256

This is correct, as my icon size is 64x64. Here's the weird part: The icon is way up at 512,512, which is 8,8.

Is world.icon_size multiplied by two, because 64x64 is for some reason giving 128 when I pull world.icon_size?

So thinking this, I used PixelMovement.tile_width/height instead of world.icon_size...and got the same result. It shows up at 512,512; 8,8. I'm not really getting the reason why.

I even added an output for px and py, and still get 256,256 for the output...but it's definitely not at 256,256.
It's because you're modifying pixel_x and pixel_y from their starting point which is 4,4 and doubles it to 8,8.

No matter what position your atom is in, pixel_x and pixel_y start at 0 and pixel_movement doesn't modify this. The only point of changing pixel_x and pixel_y in P_M's code is so that it matches the bounding box created by px,py,pwidth and pheight.

Essentially the image is being placed at 4:256,4:256 which equates to 8,8 (visually).

Now what you should do here is, leave pixel_x and pixel_y alone and make px=x*world.icon_size and py=y*world.icon_size. See how that works out
In response to Bravo1
Bravo1 wrote:
It's because you're modifying pixel_x and pixel_y from their starting point which is 4,4 and doubles it to 8,8.

No matter what position your atom is in, pixel_x and pixel_y start at 0 and pixel_movement doesn't modify this. The only point of changing pixel_x and pixel_y in P_M's code is so that it matches the bounding box created by px,py,pwidth and pheight.

Essentially the image is being placed at 4:256,4:256 which equates to 8,8 (visually).

Now what you should do here is, leave pixel_x and pixel_y alone and make px=x*world.icon_size and py=y*world.icon_size. See how that works out

If I only modify px and py, it doesn't move the icon at all. It doesn't move the bounding box either. All it changes is that when I hit the bounding box, it teleports me to the x/y coordinate of where it should be after the changes.

So for example if I do
        px=x*world.icon_size
py=y*world.icon_size
px+=64
py+=64

The icon doesn't move, the bounding box doesn't move either, however if I hit the bounding box on a chest at 4,4, it sends me up to 5,4 or 4,5, depending on which edge I hit. So if I hit the top or bottom, it warps me up to 4,5, and if I hit the right or left side it warps me to 5,4.

I cannot seem to get it to move the bounding box, the icon, and the end location all during runtime like this. All px and py seem to change is the last of the three.

I was looking at bound_x and y, but I'm not sure that those would be helpful in this situation either.

Edit: So I tried messing with step_x/y, bound_x/y, and bound_width/height instead of px/y.

I can get everything to move, but it doesn't really cooperate even though the same values are used.

This is the current code:
    New()
..()
if(randomizePLoc)
var/randomPX = rand(0, (PixelMovement.tile_width-pwidth))
var/randomPY = rand(0, (PixelMovement.tile_height-pheight))
src.step_x += randomPX
src.step_y += randomPY
src.bound_x = 0
src.bound_y = 0
src.bound_width = pwidth
src.bound_height = pheight

I set the step_x/y to the random variables so that the object moves. According to the help files it says that this moves the entire object and everything. So I also made sure that the bound_x/y are 0, because the icon is at the lower left bounds. bound_width/height are set to pwidth and height just in case there's some reason they weren't.

I get the bounding box, icon, and end teleport locations to move, however they do not cooperate with each other. I also get issues where hitting the right side can warp me to the left size and the top can warp me to the bottom, or vice versa. I'm not really sure why this happens.

I intend to later look more into the PixelMovement procs dealing with this stuff in mobs to see if I can just duplicate it for this New proc and get it to work.

Sorry if I'm missing something stupid, pixel movement in BYOND is new to me.
That happened because your objects position is one turf above where it actually is, since you used the full world/icon_size. So basically it exists at x,y but it bumps at x+1,y+1 due to the addition of 64 to py and py.

But..

You know what? Let's just take the think work out of this, haha.

obj
proc
set_pos(nx, ny, nz = 0,map_z = -1)


if(map_z == -1) map_z = z

#ifdef TWO_DIMENSIONAL
var/moved = (nx != px || ny != py || map_z != z)
#else
var/moved = (nx != px || ny != py || nz != pz || map_z != z)
#endif

if(moved)
// If you call set_pos(50.1, 40) it'll ignore the
// decimal, but if you are at (50, 40) and call
// pixel_move(0.1, 0) it'll accumulate the decimal.
px = round(nx)
py = round(ny)
#ifndef TWO_DIMENSIONAL
pz = round(nz)
#endif


var/tx = round((nx + pwidth / 2) / PixelMovement.tile_width)
var/ty = round((ny + pheight / 2) / PixelMovement.tile_height)

var/turf/old_loc = loc
var/turf/new_loc = locate(tx, ty, map_z)
var/area/old_area = loc ? loc:loc : null

if(new_loc != old_loc)

Move(new_loc, dir)

// for some reason this is necessary
if(new_loc)
new_loc.Entered(src)

// In case Move failed we need to update your loc anyway.
// If you want to prevent movement, don't do it through Move()
loc = new_loc

if(new_loc)
var/area/new_area = new_loc.loc

if(old_area != new_area)
if(old_area) old_area.Exited(src)
if(new_area) new_area.Entered(src)

step_x = px - x * PixelMovement.tile_width
step_y = py - y * PixelMovement.tile_height


Here's the set_pos() proc fixed for objects.

All you need to do to create an object is use set_pos(px,py).

To GET px and py, what you want to do is just use what you did before with

px=x*world.icon_size
py=y*world.icon_size


Then you can change px and py as you like, and then use set_pos(px,py) to appropriately set its necessary variables.


Now, after your last post I realized why you were having issues with it (step_x/y not being set properly, the pixel_x/y being offset too much, etc.) but I figured that using a proc made just for this would be best.

Now, personally, I'm not sure why set_pos() isn't an /atom proc in the first place, (besides a few /mob specific checks)

But if you use this version (just for objs) you should be good to go.
Ah yes! It works!

Awesome, I appreciate your help. I'm sorry if I was a tad annoying with all of this, I truly do appreciate everything you've helped me out with.

Just as a note: Initially it did not work, but then I realized that you cannot change px and py as you wish without passing the changes as set_pos(px,py). I'm not sure if that's what you meant, but initially I was doing
px += whatever
py += whatever
set_pos(px,py)
Which of course wouldn't work because of the moved definition. Once I realized this, I simply passed set_pos(px+whatever, py+whatever) and now everything is great.

Once again thanks a lot for your help.
If Forum_account ever comes back (I noticed he hasn't been around for a while going by his member page), I will formally suggest that at least this, but probably most movement procs, get added as atom procs instead to hopefully avoid this issue with other people in the future.