Tutorial Advanced Object Placement ( zLevel / renderLayer / Spaces / Anchor )

Discussion in 'Starbound Modding' started by Charlatan, Feb 10, 2017.

  1. Charlatan

    Charlatan Parsec Taste Tester

    Advanced Object Placement


    Oi ! I've noticed there are options and tricks available in Starbound modding which people have asked me about repeatedly, some of which you won't come across unless you sift through the game data, or some of the JSON and LUA experts show them to you so I decided to write them up. This deals mostly with the "Orientations" block in the .object files.

    First of all, special thanks to @bk3k who was the one who showed me the renderLayer option when I first asked.


    Content:

    • [ 1 ] - "Anchors" parameter & How to place objects freely, independent of anchor points
    • [ 2 ] - "SpaceScan" + "Spaces" parameter & How to manually decide which blocks/tiles an Object occupies
    • [ 3 ] - "zLevel and "renderLayer" & How to place objects behind / in front of anything else.
    • [ 4 ] - "Collision" parameter & How to make objects collide and let you walk on them

    Introduction

    For this tutorial, I will always use and refer to this object, the 24-slot wooden crate container you find almost everywhere:

    [​IMG]


    Code:
    {
      "objectName" : "woodencrate2",
      "colonyTags" : ["naturalcave","storage","commerce"],
      "printable" : false,
      "rarity" : "Common",
      "objectType" : "container",
      "tooltipKind" : "container",
    
      "category" : "storage",
      "price" : 25,
      "description" : "A mysterious wooden crate.",
      "shortdescription" : "Large Wooden Crate",
      "race" : "generic",
      "health" : 1.5,
    
      "apexDescription" : "A wooden crate.",
      "avianDescription" : "A storage box.",
      "floranDescription" : "Box!",
      "glitchDescription" : "Curious. Is there anything inside?",
      "humanDescription" : "A wooden crate. It's open.",
      "hylotlDescription" : "An open crate.",
      "novakidDescription" : "A regular wooden crate.",
    
      "inventoryIcon" : "woodencrate2icon.png",
      "orientations" : [
           {
                "image" : "woodencrate2.png:default",
                "direction" : "left",
                "flipImages" : true,
    
                "imagePosition" : [-16, 0],
                "frames" : 1,
                "animationCycle" : 0.5,
    
                "spaceScan" : 0.1,
                "anchors" : [ "bottom" ],
                "collision" : "platform"
          },
          "{
                "image" : "woodencrate2.png:default",
                "direction" : "right",
    
                "imagePosition" : [-16, 0],
                "frames" : 1,
                "animationCycle" : 0.5,
    
                "spaceScan" : 0.1,
                "anchors" : [ "bottom" ],
                "collision" : "platform"
      }
      ],
    
      "openSounds" : [ "/sfx/objects/woodenbox_open.ogg" ],
      "closeSounds" : [ "/sfx/objects/woodenbox_close.ogg" ],
      "slotCount" : 24,
      "uiConfig" : "/interface/chests/chest<slots>.config",
      "frameCooldown" : 5,
      "autoCloseCooldown" : 3600
    }


    This is how the game applies coordinates to the blocks/tiles an object uses. This will be referred to by most of the sections below !
    0, 0 is in the middle bottom, because in the .object file "imageposition" is set to:

    1 block equals 8 pixels, so two steps towards the middle of the box is "-16" in this case.


    [​IMG]






    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-



    [ 1 ] - Anchors

    This is by far the most simple and straightforward part of this tutorial. As you surely know already "Anchors" tells the object where in the world it can be attached. The possible options: "Top" "Bottom" "Background" are all self-explanatory, however, there is a little tidbit by keeping the entry empty:

    Code:
    "anchors" : [ ],


    --- Keeping "Anchors" empty ---

    Result: The box can be freely placed anywhere, basically floating. It wouldn't need any background blocks either.
    [​IMG]


    Another optional way to treat Anchors is done by using coordinates. Instead of "Anchors" you instead use either "fgAnchors" for attaching the object to the foreground, or "bgAnchors" if it should look for background blocks instead.

    It is written in this format - refer to the image about how the game handles coordinates to understand the numbers:



    Code:
    "orientations" : [
          {
                "image" : "woodencrate2.png:default",
                "direction" : "left",
                "flipImages" : true,
    
                "imagePosition" : [-16, 0],
                "frames" : 1,
                "animationCycle" : 0.5,
    
                "spaceScan" : 0.1,
                "fgAnchors" : [ [-1, 3], [0, 3] ]
                "collision" : "platform"
          },
          {
                "image" : "woodencrate2.png:default",
                "direction" : "right",
    
                "imagePosition" : [-16, 0],
                "frames" : 1,
                "animationCycle" : 0.5,
    
                "spaceScan" : 0.1,
                "fgAnchors" : [ [-1, 3], [0, 3] ]
                "collision" : "platform"
           }
      ],

    With this alternative, the logic of attaching is the same as usual:
    In the case of "fgAnchors" the blocks the object attaches to must be adjacent blocks/tiles, "touching" it.
    In the case of "bgAnchors" it must be blocks/tiles directly underneath or "behind" the object.

    In the example I have written above, the box attaches to the two middle tiles at the top of it, as shown in the left image you will find below.



    --- Using "fgAnchors" and "bgAnchors" ---
    Left: "fgAnchors" is set up like in the example above - the box only attaches to the two middle top tiles
    Right: Using "bgAnchors" set up to attach to the boxes' topmost blocks: "bgAnchors" : [ [-2, 2], [-1, 2], [0, 2], [1, 2] ]

    [​IMG]






    [ 2 ] - SpaceScan & Spaces

    > spaceScan

    The "spaceScan" entry in the .object file handles how the game understands what space (blocks, also called tiles) an object occupies. The size you set for an image in the .frames file does not matter here - even if it says the dimensions are 32x24, like in the case of this crate, it doesn't mean the object uses up all of them, instead, spaceScan handles this.

    This value is a Threshold, basically telling the game "if the image/sprite of the object covers a 8x8 pixel tile (in other words 1 block) more than this value, then this tile is occupied"

    For example, the default value "spaceScan : 0.1" means, if an object's image fills up a 8x8 tile by more than 10%, then the place is occupied and cannot be used. If you set it to 0.5, the tile can be used as long as the sprite doesn't cover more than 50%, and so on. When you set spaceScan to 0.99, you can use the tile as long as it isn't completely covered.


    --- Normal behavior with spaceScan : 0.1 ---
    Left: 2x2 blocks are completely empty and can be used for something else
    Right: The image spreads slightly into the bordering fields, thus the leaf blocks couldn't be placed

    [​IMG]

    --- How spaceScan changes as you change the value ---

    Left: Using the default value 0.1, the almost fully occupied tiles don't work, of course
    Right: With spaceScan set to 0.99, even the almost completely covered tiles can be used
    [​IMG]


    > spaces


    "spaces" is an exclusive alternative to spaceScan and pretty much replaces it's function.
    While "spaceScan" is automatic, "spaces" wil
    l let you manually set the exact tiles your object occupies, through the use of a grid of X Y coordinates.


    If you scroll up to the image about how the game handles coordinates, here are the occupied spaces of the crate, how it would be written in the .object file, replacing "spacescan":
    Let's say we now want the right half of the box to be free for other blocks and other objects you want to put on top:


    --- Manipulating spaces manually ---
    Left: The crate, with the spaceScan manually replaced with spaces, is just using the spaces written above
    Right: [0,0], [1,0], [0,1], [1,1], [0,2], [1,2], were deleted from the spaces option.

    [​IMG]



    > removing both spaces and spaceScan

    You can simply delete the spaceScan entry from your .object file completely - it is fully optional. What happens if you do that is this:


    --- Simply deleting the spaces or spaceScan entry completely ---
    Left: The box is placed without any space parameters and we are going to plaster a convenient block over it to check what happens
    Right: Only the center tile on which the object is placed is occupied, the rest can simply overlap

    [​IMG]






    [ 3 ] - zLevel & renderLayer


    "zLevel" and "renderLayer" are different things, but handle the same matter: what is in the front, what is in the background? Does your character walk before an object, or can your character walk behind it?

    Basically, it can be explained by this image:


    [​IMG]


    The renderLayers lie on-top of each other in a fixed state. The simplest example you know is how you can place blocks in the front and the background. Inside each renderLayer, there is a so-called zLevel. zLevel is simply a number which decides what is closer to you in the 2D game world, and what is further away, creating a kind of pseudo 3D.


    > zLevel


    The parameter zLevel is simple: Within it's renderLayer, whatever has the highest zLevel appears first, as in "closest" to the screen. Everything else follows in order highest to lowest.

    Please note that in the .object file, zLevel is not necessarily written in the orientations block, you can simply put it anywhere outside.



    Code:
    : 
    {
      "objectName" : "woodencrate2",
      "colonyTags" : ["naturalcave","storage","commerce"],
      "printable" : false,
      "rarity" : "Common",
      "objectType" : "container",
      "tooltipKind" : "container",
      "zlevel" : 1,
      ...
      ...
      ...
    


    --- Placing objects with different zLevels ---
    Result: 3 duplicate objects of the woodencrate2 with zLevels from left to right: 3, 2, 1.
    [​IMG]


    zLevel can also be defined in the .animation file, specifically for each part of the object. As an example, here is the normal copper lantern you can craft on the workbench, in which "BG" (Background, the glowing light) has no zLevel and "FG" (Foreground, the copper chasis which does not glow) has zLevel: 1, so that the non-glowing chasis is above the lightbulb:


    Code:
    : 
    {
      "animatedParts" : {
           "stateTypes" : {
                "light" : {
                "default" : "off",
                "states" : {
                     "off" : {
                     "},
                     "on" : {
                     "frames" : 2,
                     "cycle" : 0.4,
                     "mode" : "loop"
                  }
               }
           "}
      "},
    
      "parts" : {
            "bg" : {
                 "properties" : {
                      "centered" : false
                  },
    
                 "partStates" : {
                      "light" : {
                           "off" : {
                                "properties" : {
                                     "image" : "<partImage>:<color>.off"
                                }
                           },
    
                           "on" : {
                                "properties" : {
                                     "image" : "<partImage>:<color>.<frame>",
                                     "fullbright" : true
                                }
                           }
                      }
                 }
            },
            "fg" : {
                 "properties" : {
                      "centered" : false
                      "zLevel" : 1
                },
    
    
                 "partStates" : {
                      "light" : {
                           "off" : {
                                "properties" : {
                                     "image" : "<partImage>:<color>.off"
                                }
                           },
    
                           "on" : {
                                "properties" : {
                                     "image" : "<partImage>:<color>.<frame>",
                                }
                           }
                      }
                 }
              },
           }
       }
    }
    



    > renderLayer


    The renderLayer is an option which can be added to the orientations block, though it is not normally used in the vanilla game beside a few exceptions.



    Code:
    "orientations" : [
          {
                "image" : "woodencrate2.png:default",
                "direction" : "left",
                "flipImages" : true,
    
                "imagePosition" : [-16, 0],
                "frames" : 1,
                "animationCycle" : 0.5,
    
                "spaces" : [ [-2, 0], [-1, 0], [0, 0], [1, 0], [-2, 1], [-1, 1], [0, 1], [1, 1], [-2, 2], [-1, 2], [0, 2], [1, 2] ],
                "anchors" : [ ],
                "collision" : "platform",
                "renderLayer" : "player+1"
          },
          {
                "image" : "woodencrate2.png:default",
                "direction" : "right",
    
                "imagePosition" : [-16, 0],
                "frames" : 1,
                "animationCycle" : 0.5,
    
                "spaces" : [ [-2, 0], [-1, 0], [0, 0], [1, 0], [-2, 1], [-1, 1], [0, 1], [1, 1], [-2, 2], [-1, 2], [0, 2], [1, 2] ],
                "anchors" : [ ],
                "collision" : "platform",
                "renderLayer" : "player+1"
           }
      ],
    

    --- Using renderLayer for more versatile object placement ---
    Left: With renderLayer set to "player+1" the box is in front of the characters
    Right: Together with the use of spaces, setting it to "foregroundentity+1" places the box even in front of regular blocks

    [​IMG]


    This is a list of options for renderLayer I discovered up to now, in the order which comes above the rest (upper entries mean they appear in the front, lower ones come behind):

    • foregroundEntity
    • FrontParticle
    • ItemDrop
    • player
    • monster
    • Projectile
    • MiddleParticle
    • BackParticle
    • Object
    • platform
    • backgroundoverlay






    [ 4 ] - Collision


    "collision" is typically either not set in an object at all, or set to the value "platform". As you can see, that is the case in the woodencrate2 object we use as an example, making it possible for you to both walk past the object or stand on top of it. There are 4 options for this:

    (don't use "collision" at all): The object is in the background and won't get in your way at all.
    "collision" : "platform" = The object works exactly like a platform block, the surface being the top of the object's shape in the image/sprite.
    "collision" : "solid" = The object will collide with you like any solid block does.

    "collisionSpaces" : [ [x, y], [x, y]... ] = Used together with "collision". This applies the collision method above only to the coordinates you set. Refer to the image about how the game handles coordinates to understand how to use the coordinates.


    --- Differences when using "Collision" and "CollisionSpaces" ---
    Left: The box is set to be "solid" and is now an obstacle and collides with any player, entity, bullets, etc.
    Right: The visually changed box has "platform" collision and uses collisionSpaces, it now has multiple layers of walkable surfaces. The coordinates used were:
    "collisionSpaces" : [ [-4, 1], [-3, 1], [-2, 1], [-1, 1], [1, 1], [2, 1], [3, 1], [-4, 3], [-3, 3], [-2, 3], [-1, 3], [1, 3], [2, 3], [3, 3] ]
    [​IMG]




    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


    This concludes my tutorial. If anything is unclear, I will make corrections or provide additional visual aid.

     
    Last edited: Nov 7, 2018
    boo buu, rin_elyran, qs820 and 12 others like this.
  2. Cyel

    Cyel Scruffy Nerf-Herder

    The most unclear thing to me is the text color - (with the default theme at least,) it's gray on white, and it's pretty hard to read.
    sorryformostlyunrelatedcommentbutlisibilityaaa

    Also in the Content section thingy:
    [ 2 ] - "SpaceScan" & "Spaces" parameter & How to manually which blocks an Object occupies
    missing word

    The spoilers with code could use a code tag to preserve indenting too

    Are there limits to the zIndex values, and I assume the player's one is 0?
     
    Last edited: Feb 10, 2017
  3. Charlatan

    Charlatan Parsec Taste Tester

    I'm afraid thats impossible to solve, as one Forum Theme is dark grey, while the other is white. :/

    Fixed, thanks for the pointer!

    zLevel doesnt directly relate to the player, only renderLayer does => The exact spot the Player occupies basically is renderLayer "player" without any adjustment or zLevel. There should be no limit btw.
     
    Last edited: Feb 11, 2017
  4. bk3k

    bk3k Oxygen Tank

    A few things I would add. You can actually change the zLevel on a part-by-part basis. A good example is
    \objects\biome\tentacle\bosstentacle\bosstentacle.animation
    I wonder(haven't tried) if you can set the "renderLayer" of parts in the .animation files.

    Some alternative anchor options
    Code:
    "fgAnchors" : [ [-2, 1], [-1, 1], [0, 1], [1, 1] ]
    foreground tile anchoring
    Code:
    "bgAnchors" : [ [-2, 1], [-1, 1], [0, 1], [1, 1] ]
    background tile anchoring

    They use an array of [x, y] coordinates (as already explained in this thread) so you can get VERY specific with your anchors.

    You can add collisions to your objects without need of LUA code(but what fun is that?)
    "collision" : "solid"
    "collision" : "platform"
    etc

    After adding that, it would automatically determine the appropriate spaces(the top). If you've defined "spaces" manually you can obviously affect this outcome. But... you can do better than that! After defining your collision type
    Code:
    "collisionSpaces" : [ [-3, 0], [-2, 0], [-1, 0], [0, 0], [1, 0], [2, 0] ]
    This also seems to be an option for platforms
    Code:
    "platformSpaces" : [ [3,0], [3,1], [3,2] ]
    "orientations" actually provide more interesting options than you might think. Although counter-intuitive you can place most any attribute in or out of orientations. If placed at the base level, then you could only have one possible variant of the attribute, but if in an orientation you could have several
    { "onePer" : "orientation_ofCourse" }

    Typically this is used for different anchor choices, direction, etc. But you could place the wire node position on the other side of a reversed object, have different spaces and/or collision spaces defined, different light colors, etc. I guess you could have different slot counts for wall mounted versus floor mounted, point to different "uiConfig" even. Like I say, you can use it for most everything if you really wanted. I have an object I made(for a ship mod I'm restoring) that adds an additional status for the wall mounting option I added.

    And despite what you'd assume, moving things from/to base level/orientations doesn't cause any difference when reading a "nameSpace" via config.getParameter("nameSpace", "default_if_undefined"). So you can even define alternate LUA parameters via your orientations.

    I read it just fine but I'm using the old forum theme. Anyhow...

    The "zLevel" is shall we say... less powerful than render layer. "Player" renders ahead of "Object" but renders behind "Player+2"
    I forget where I saw the list of layers(need to find that!), but I think I recall a "Parallax" layer too and maybe a few more. Now while the objects would normally render on "Objects" that can be over-written.
     
    Last edited: Feb 10, 2017
    Charlatan likes this.
  5. Charlatan

    Charlatan Parsec Taste Tester

    Thanks for the details b3k3, It took a while to write all this up and make the screens, so I'll add the missing bits a bit later!

    I tried around with it a bit, but didnt find a solution yet.

    It's the main obstacle in my mod at the moment. People have repeatedly requested that they want more objects to be put into the foreground above the player, and I have a GUI with persistent options to toggle it between player+1 and player-1.

    I'm only stuck with finding a way to use renderLayer in LUA or .animation
     
    Last edited: Feb 10, 2017
  6. Cyel

    Cyel Scruffy Nerf-Herder

    Why would it not be possible to solve when the rest of your posts are in black?
     
  7. Charlatan

    Charlatan Parsec Taste Tester

    I don't know what you mean. Are you saying my other posts automatically pick a black font color when you use that white forum theme ?

    PS: I switched to a darker grey which should work for both themes.
     
    Last edited: Feb 10, 2017
  8. Cyel

    Cyel Scruffy Nerf-Herder

    @Charlatan yes, all of your posts use a black font color -for me, except that first post. ¯\_(ツ)_/¯
     
  9. Charlatan

    Charlatan Parsec Taste Tester

    @bk3k 's suggested additions are now also featured !

    Is it better now ? ^^
     
    Last edited: Feb 11, 2017
  10. Cyel

    Cyel Scruffy Nerf-Herder

    Wellyes

    butwouldbebetterallblack
     
  11. amirmiked12

    amirmiked12 Parsec Taste Tester

    awesome tutorial.
    but i dont understand one thing.
    im made an objects and i wanna make it act like background tile like you can place another object over it.
    how can i do it?
     
  12. Charlatan

    Charlatan Parsec Taste Tester

    Thanks, from what I gathered an object still needs to have at least one tile of space it attaches to. If you delete everything else, its the central tile at the bottom, depends on the object.
    In short, you simply couldn't place two identical objects ontop of each other.

    See here? [​IMG]

    If there is another solution later I'll gladly add it, but right now the problem is: Even if we found a way to get rid of that last 8x8 block, the object should no longer react to the matter manipulator.
    This could potentially make glitched objects which need scripted methods to get rid of.

    But, as long as each object just occupied their own single tile in the game world, you can use "renderlayer" parameter described above to place objects above/behind each other, until you run out of tiles.

    By the way, I'm still looking at a way to make objects behave like the grasses/bushes in the background. That could solve our issue here.
     
  13. amirmiked12

    amirmiked12 Parsec Taste Tester

    tnx.but if we could do that it would be awesome
     
  14. amirmiked12

    amirmiked12 Parsec Taste Tester

    i set my collision to platform and then this happened,every thing is ok but this ?
    should it be the problem with png itself ?
    look
    MY FRAME

    {

    "frameGrid" : {
    "size" : [55, 12],
    "dimensions" : [1, 1],
    "names" : [
    [ "default" ]
    ]

    }
    }

    MY OBJECTS

    {
    "objectName" : "logsit",
    "colonyTags" : ["nature"],
    "printable" : false,
    "rarity" : "Common",
    "category" : "decorative",
    "price" : 50,
    "description" : "Nice decoration.",
    "shortdescription" : "log",
    "race" : "generic",

    /*
    "apexDescription" : "a log",
    "avianDescription" : "a log",
    "floranDescription" : "a log",
    "glitchDescription" : "a log",
    "humanDescription" : "a log",
    "hylotlDescription" : "a log",
    "novakidDescription": "a log",
    */
    "inventoryIcon" : "logsiteicon.png",
    "orientations" : [
    {
    "image" : "logsit.png:<color>",
    "imagePosition" : [-8, 0],
    "direction" : "left",
    "flipImages" : true,

    "spaceScan" : 0.1,
    "anchors" : [ "bottom" ],
    "collision" : "platform"
    },
    {
    "image" : "logsit.png:<color>",
    "imagePosition" : [-8, 0],
    "direction" : "right",

    "spaceScan" : 0.1,
    "anchors" : [ "bottom" ],
    "collision" : "platform"
    }
    ]
    }

    [​IMG]

    EDIT: now im started to thinking that my object high is 1.3 tile but the game will use 1 block and 2 and 3 and 4 and so on.
    is it the problem?
     
    Last edited: Apr 18, 2017
  15. Charlatan

    Charlatan Parsec Taste Tester

    Yes indeed! Unless told otherwise, the game always "scans" for which pixels in the PNG are used, and which are empty. That's why, if a default object has a full 1x1 tile gap, you could place a 1x1 object in there, without having to change any settings.

    For occupying tiles for other objects, its shown well in the spaceScan section in the tutorial - I didn't yet try with part-tile-sized platforms tho, I'll be back here in a moment.

    EDIT:

    Yeah, no partial collision spaces by normal means. Neither spaceScan nor setting collisionspaces to for example "[0, 1.5]" will work. it'll round the number back down to 1 tile height then.
    I'm always open to controversial methods tho. When I'm less busy I'll look at the moving platform systems and see if there's something to be found there that could be used.
     
    Last edited: Apr 19, 2017
  16. amirmiked12

    amirmiked12 Parsec Taste Tester

    Can u help meto fix my objects collision?
    I would appreciate it
     
  17. Charlatan

    Charlatan Parsec Taste Tester

    Yes, but, as said above, colliding as a platform halfway through a tile doesn't seem to be a thing yet, without further research.

    ATM it would be best to first either adjust the image to fill up to a 16 pixel height, or trim it down to just 8 pixel height.
    I recommend 16. If your log is just 1 tile high, and acts as a platform, your character will automatically run over it instead of past it.

    When I am less busy, we can check if there's some missing info, because I got a feeling I missed something very simple here.
     
  18. amirmiked12

    amirmiked12 Parsec Taste Tester

    Tnx its better I change the size
     
  19. Charlatan

    Charlatan Parsec Taste Tester

    Do that for now - after my little break, I'll look if we can make it work with the size you wanted !
     
  20. Erazil

    Erazil Subatomic Cosmonaut

    just for say Thanks you for this guide very useful :)
     
    AmazonValkyrie and Charlatan like this.

Share This Page