Backlog

by Ter13
Welcome to my brain's backwash
ID:2950754
 

Bounds


Adopting 516 for new users should be pretty seamless if you don't have to pull out a vector library in favor of the built ins BYOND 516 provides. But we do need to talk about some changes to how things work internally that is going to trip up some 515 and before code.

Instead of jumping right into fixing up your project for 516, I think it's important to review why some of these fundamental things that have been part of the language are changing, and why it is for the better. Consensus on how things work, and how they should have always worked is important for buy-in.

When pixel movement was added to BYOND, it was considered to be a new set of rules for how BYOND worked. This thinking was completely understandable, but it did result in some errors in logic. Over time, we've realized that thinking about pixel movement as the special case was a mistake. Recently, we've been talking quite a lot about considering tile movement to be the special case, and considering pixel movement to be the superset from which tile movement derives. This can be a hard adjustment for users to wrap their heads around, but let's consider some facts here:

Looking at tile movement:
  • Tile movers are locked to a grid. For each tile, there is only one valid point on which the object can exist.
  • Collisions can only happen at tile boundaries
  • Movements are limited to discrete jumps between valid points on a tile. Jumping or stepping is determined by step_size, but limited to increments of tile size.
  • A tile mover can squeeze through a corner between tiles that is too small for its bounding box to penetrate, so long as the path between its starting point, and ending point is clear on these valid points.
  • Tile movers can appear to be moving toward their destination, but their bounding box occupies the space before their icon arrives. (gliding)

Looking at pixel movement:
  • Movers can exist at any arbitrary point on a tile, preserving subpixel offsets.
  • Collisions can happen anywhere along the line of motion.
  • Movements can be as short, or as long as you want. Jumping or stepping behavior is determined by step_size.
  • A pixel mover cannot squeeze between spaces smaller than its bounding box. The bounds of a pixel mover have presence at all points along their motion.
  • Pixel movers (prior to BYOND 514) had no gliding behavior and ended a step instantly.
  • Pixel movers have no restrictions on their bound_width or bound_offsets.

As you can see, this ruleset can be filled with a lot of gotchas if you choose to think of them as separate. I believe Kaiochao was the first user on this forum to bring up the inverse way of thinking of these problems. Instead of thinking about tile and pixel movement as distinct things, it was better to think of tile movement as a series of restrictions on pixel movement.

I rolled this idea over in my head for a while, and then requested world.movement_mode to formalize this ruleset and give developers more agency with respect to what happens in their world.

Now, gliding behavior is not limited to tile movement mode. Instead, pixel gliding is based on your glide_size in world.movement_mode = PIXEL_MOVEMENT, the same as in tiled movement (LEGACY_MOVEMENT_MODE and TILE_MOVEMENT_MODE). The restrictions on the position of objects are no longer global. Objects can declare themselves as obeying the rules of tile movement mode using the TILE_MOVER appearance flag, but when the world is in TILE_MOVEMENT_MODE, BYOND stops any movers from disobeying the rules of tile movement.

Thinking of tile movement mode as a series of restrictions has led to much less nuanced behavior in BYOND's movement, and has made discussing what each component of the movement system does much more direct.

What's changing?


Hopefully? Nothing is changing. But also something underpinning how coordinates work in DM is changing. Previously, bound_x and bound_y were considered to be part of an object's physical location in the world. Bound_x and bound_y physically moved the bounding box of an object to the right and upward. This was a problem, because Move()ing an object onto a tile with a step_x or step_y of 0 meant the bottom-left corner of its bounding box would be affected by step_x and step_y. Moving four different objects to the same place, could result in objects being located at four different places. This made calculating exactly where something was in the world for the purposes of free pixel movement much, much harder than it needed to be.

On top of this, movable.New() took a single argument referring to the object's location at creation. So creating an object with a bounding box with bound_x or y offsets would cause the object to potentially not even be on that tile, yet its loc would still count as that tile. The whole way bound_x and bound_y worked was confusing for developers, and led to much more code having to be written to do something that should have been simple.

We realized during the 514/515 cycle that this could be addressed by treating bound_x and bound_y as a visual-only offset of the object's appearance, and for bounding boxes to always declare the actual physical location of the object.



The engine now internally treats bound_x and bound_y as visual, rather than physical offsets. A bound_x of 8, for instance, no longer moves the bounding box right by 8 pixels. Instead, the visual appearance of the object moves 8 pixels to the left. Now, when you create an object that has bound_x or y offsets at a specific tile, its bounding box will be located at the bottom-left corner of that tile.



As you can see, the only change is where the origin point of a movable atom (the hard to see purple dot in these images) is what is changing with 516. When pixel movement in BYOND was first added, an object was always assumed to be at the bottom-left corner of its icon. But adding bounds into the mix, where an object could occupy more, or less space than their icon took up, made this origin point a bad way to put objects on the map. Developers just want to think about the physical bounds of an object when moving around the world, instead of the size of the icon. This change is a good thing for developers, even if it has some ugly externalities on old projects who want to modernize. These days, we don't really care where the graphic is in relation to the bounding box when we're moving, because we're moving little boxes around the world with sprites attached, rather than sprites with little boxes attached. Simplifying the math for calculating where those little boxes are is a no-brainer and makes BYOND much easier to learn and develop for.

BYOND 516 also gives you some powerful tools for placing objects and moving objects around the world with much less code for the developer: It allows you to pass a single argument to New() that determines object's location and step offsets at the same time. Before 516, you could only specify a tile to create an object at, and if you wanted to specify tiles and step positions, you needed to override the New() proc for every object that could do this and pass step offsets in. 516 lets you do all of this at once with no messy initializers:
new/obj(pixloc(128,136,1)) //creates the atom using global pixel coordinates.

//creating an object exactly on top of another:
new/obj(pixloc(another_object))
new/obj(another_object.pixloc)

//creating an object centered on top of another:
new/obj(bound_pixloc(another_object,0) - vector(bound_width / 2,bound_height / 2))

//creating an object using x,y,z, step_x, step_y offsets:
new/obj(pixloc(locate(x,y,z),step_x,step_y))

Move() also supports these pixlocs being passed instead of a location. Check out my 516 introduction on pixlocs and vectors for more examples!

But you said there were changes


Yes! There are actually changes to best practices. bound_x and bound_y should be considered to be deprecated for the purposes of calculating an object's location in the world. Any code that you have that uses bound_x or bound_y in a Move() call, or calculates an object's global pixel coordinates including bound_x and bound_y is going to give you bad information and unexpected results now. For new projects, life just got a whole lot easier, but for existing projects that included code that makes their life easier, there are going to be some speedbumps for adoption.

While bound_x and bound_y's behavior has changed, it has changed toward how it should have always behaved from the beginning. Unfortunately, many of the solutions we, as a community have adopted as a best practice will be broken on 516. So anyone wanting to upgrade to the new version once beta arrives, will need to pore over their source code and remove any of these manual attempts to work and think in global pixel coordinates, and replace them with the new built-in infrastructure.

This should be relatively straightforward. You should essentially just ctrl+f your whole project looking for bound_x and bound_y. If bound_x and bound_y is being set to a value, it is valid. However, if it is being read, and then used to assist in a movement, or to provide a global pixel coordinate for that object, you need to make some changes to your code.

It is highly likely when you open your project in 516, objects will be out of place on your map, and things will not look like how you intended them to. Don't fear! Provided you go in understanding what has changed, you should be able to fix this relatively quickly!

Thank you!


That's about all I have for you guys today. I'm working on few things in the background that I can't release until 516 is out and in the hands of the public. Please, please please consider giving Lummox some love and encouragement (cold hard cash thrown directly into his wallet is very loving and encouraging, but words are good too) for all of these new, great things he's added to the engine. 516 doesn't exactly have a lot of big, sexy things to show off, but these are far and away some of the most important updates that have been made to the engine in the last decade. They are going to massively improve the ease of using BYOND for programmers, and directly increase the quality of the games on the platform as a result. If you have any cool stuff to show off that you've made, or even some corrections and tips for me here, feel free to toss them into the replies.

If you want to see what the community has been up to lately, come join BYONDiscord! and scope out our showcase channel and our hall of fame. We've been cooking some really neat stuff with the alpha, and there's some great people that offer daily support and encouragement to anybody that needs it. Struggling to adopt 516? Stuff on your map is all effed up? We've got some good heads in there that can help you learn some new skills for triaging these changes effectively. Don't worry though, a good old fashioned Developer Help post will show up in our discord too, and summon the troops. We're just here to help the community no strings attached.



Come show us what you've got!