Question: STI and Windfield: Building Polygon Objects from Tables

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Kubba
Prole
Posts: 4
Joined: Tue Mar 16, 2021 1:53 am

Question: STI and Windfield: Building Polygon Objects from Tables

Post by Kubba »

Hello,

For a few hours now, I have been attempting to build static collider boxes in Windfield using object layers created in Tiled (so I'm using STI).
I can make rectangles easily enough, but polygons are giving me trouble because they take vertices (x1, y1, x2, y2, etc), but the lua file with those vertices has those values nested inside of other tables:

Code: Select all

objects = {
          id = 42,
          name = "",
          type = "",
          shape = "polygon",
          x = 269,
          y = 640,
          width = 0,
          height = 0,
          rotation = 0,
          visible = true,
          polygon = {
            { x = 0, y = 0 },
            { x = -12, y = 0 },
            { x = 51, y = -63 },
            { x = 51, y = -52 }
          },
          properties = {}
        },
etc, etc

I'm after the polygon table data so I can build shapes using Windfield's world:newPolygonCollider function.

I have tried various methods for grabbing nested tables, but haven't managed to get the x and y values I need. I'll just post my original code:

This code runs for each object in the object table above, then passes the x and y coords along with the polygon table to a function:

Code: Select all

	for i, par in pairs(levelMap.layers["semiSolidSlope"].objects) do
        spawnSemiSolidSlope(par.x, par.y, par.polygon)
    end
This function attempts to create a polygon (note, I have not factored in the x and y coords just yet, but will need to add those to each set of verticies):

Code: Select all

function spawnSemiSolidSlope(x, y, polyTable) 
   local semiPlatform = world:newPolygonCollider(x, y, polyTable, {collision_class = "semiSolid"})
    semiSlopePlatform:setType('static')
    table.insert(semiSlopePlatforms, semiSlopePlatform)]]
end
I've messed around with unpacking the polygon table myself (two for loops to iterate through each table and their nested tables) and passing them to a new table that can be read directly by love.graphics.newPolygonShape in Windfield, but I only get as far as passing 2 vertices and getting an error.

tldr; I need to take the values from tables within tables:

Code: Select all

objects = {
	obj = {
		{x=1,y-3},
		{x=-2,y=4},
		{x=6,y=8},
		{x=8,y=8}
		},{
		etc
		}
}
and turn it into values I can pass like this:

Code: Select all

world:newPolygonCollider(x1, y1, x2, y2, x3, y3, etc)
I think I've been on the right track (above code not withstanding), but I need someone to set me straight on tables within tables and how to pull their values out.
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by pgimeno »

I think you're confusing your table syntax.

Doing {"a","b","c"} is equivalent to: {[1]="a", [2]="b", [3]="c"}

On the other hand, doing {obj="a"} is equivalent to: {["obj"]="a"}

In other words, when you specify a field name, that entry uses a string key, and when you don't, it's implicitly a numeric key starting with 1. That's true even when mixing both, as you're doing.

So, when you do this:
Kubba wrote: Tue Mar 16, 2021 2:59 am

Code: Select all

objects = {
	obj = {
		{x=1,y-3},
		{x=-2,y=4},
		{x=6,y=8},
		{x=8,y=8}
		},{
		etc
		}
}
what you're actually doing "internally" is:

Code: Select all

objects = {
        ["obj"] = {
                {["x"]=1,["y"]=3},
                {["x"]=-2,["y"]=4},
                {["x"]=6,["y"]=8},
                {["x"]=8,["y"]=8}
        },
        [1] = {
                etc.
        }
}
Note how doing {obj={...},{...}} is equivalent to {["obj"]={...}, [1]={...}} which is a problem for iterating.

Since you seem to want to group all objects in a single table, I'd suggest to drop the 'obj =' part and use implicit numeric indexes for all entries, like this:

Code: Select all

objects = {
        {
                {x=1,y=3},
                {x=-2,y=4},
                {x=6,y=8},
                {x=8,y=8}
        },
        {
		etc
        }
}
Now you can iterate through these with two nested loops. The outer loop will read all objects and the inner loop will read all points of each object. For example, in pseudocode:

Code: Select all

    for numobj = 1, #objects do
        create polygon
        for point = 1, #objects[numobj] do
            add point objects[numobj][point].x, objects[numobj][point].y to the polygon
        end
    end
Kubba
Prole
Posts: 4
Joined: Tue Mar 16, 2021 1:53 am

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by Kubba »

Thanks for the reply,

Going in, I was concerned that modifying Tiled's generated files would cause issues and it appears I was right. I attempted the solution and changed the table structures and this results in an error. There is another aspect of STI (STI's init.lua) that expects to find the nested tables as they are, so I am unable to modify them.

Is there another way to access the table data I need? If not, I may need to resort to another collision system, or find one that will play nice with Windfield.
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by pgimeno »

Can you show a specific example of a Lua map file with these polygons? Taking your first code block at face value, there is only one polygon, and the values can be accessed this way:

Code: Select all

  for num = 1, #objects.polygon do
    add objects.polygon[num].x, objects.polygon[num].y to the polygon
  end
Here's a tested example that works, which uses a copy of your code literally except for the last comma and prints the coordinates:

Code: Select all

objects = {
          id = 42,
          name = "",
          type = "",
          shape = "polygon",
          x = 269,
          y = 640,
          width = 0,
          height = 0,
          rotation = 0,
          visible = true,
          polygon = {
            { x = 0, y = 0 },
            { x = -12, y = 0 },
            { x = 51, y = -63 },
            { x = 51, y = -52 }
          },
          properties = {}
        }

for num = 1, #objects.polygon do
  print(objects.polygon[num].x, objects.polygon[num].y)
end
Kubba
Prole
Posts: 4
Joined: Tue Mar 16, 2021 1:53 am

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by Kubba »

The lua with the tables can be found here: https://github.com/KubbaYioka/Kubba-Gam ... tLevel.lua

The tables themselves begin on line 1604 and end on 1738.
User avatar
darkfrei
Party member
Posts: 1197
Joined: Sat Feb 08, 2020 11:09 pm

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by darkfrei »

Kubba wrote: Tue Mar 16, 2021 2:59 am and turn it into values I can pass like this:

Code: Select all

world:newPolygonCollider(x1, y1, x2, y2, x3, y3, etc)
Can it be called as one table argument?

Code: Select all

world:newPolygonCollider({x1, y1, x2, y2, x3, y3}) -- note { and }
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by pgimeno »

Ahh, you have omitted a '{' in the part that you've copied, hence the confusion.

OK, assuming that 'map' is the result of 'require "testLevel"', and that layernum is the layer number of the layer with the objects that you want to add (7 for the layer that starts in line 1594), you would access them like this:

Code: Select all

  for objnum = 1, #map.layers[layernum].objects do
    create a new polygon
    for pointnum = 1, #map.layers[layernum].objects[objnum].polygon do
      add map.layers[layernum].objects[objnum].polygon[pointnum].x and ...y to the polygon
    end
  end
This can be simplified a lot with locals, which I didn't before because it wasn't too long, to avoid confusing you, but it starts being far too long:

Code: Select all

  local layer_objects = map.layers[layernum].objects
  for objnum = 1, #layer_objects do
    create a new polygon
    local object_polygon = layer_objects[objnum].polygon
    for pointnum = 1, #object_polygon do
      local point = object_polygon[pointnum]
      add point.x and point.y to the polygon
    end
  end
Kubba
Prole
Posts: 4
Joined: Tue Mar 16, 2021 1:53 am

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by Kubba »

Well that certainly did the trick.

Code: Select all

    
    local semiSlope = levelMap.layers["semiSolidSlope"].objects
    for objnum = 1, #semiSlope do
        local polygons = {}
        local polyObj = semiSlope[objnum].polygon
        for vertNum = 1, #polyObj do
            local vert = polyObj[vertNum]
            table.insert(polygons, vert.x) 
            table.insert(polygons, vert.y)
        end
        spawnSemiSolidSlope(polygons) 
    end
So if I'm reading this correctly, the number of objects within a table is used to iterate through the table rather than using pairs\ipairs. I didn't know you could do it that way. At any rate, the above code creates polygons where I need them. Now I just need to change my physics so that every polygon isn't a slip n slide.

Thanks for your help, everyone!
User avatar
darkfrei
Party member
Posts: 1197
Joined: Sat Feb 08, 2020 11:09 pm

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by darkfrei »

It works with the pairs/ipairs too:

Code: Select all

local polygon={}
for i, vert in pairs(object.polygon) do
  table.insert(polygon, vert.x) 
  table.insert(polygon, vert.y)
end
-- use polygon

Code: Select all

local polygons={}
for i, object in pairs (objects) do
  local polygon={}
  for j, vert in pairs (object.polygon) do
    table.insert(polygon, vert.x) 
    table.insert(polygon, vert.y)
  end
  table.insert(polygons, polygon)
end
-- use polygons
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Question: STI and Windfield: Building Polygon Objects from Tables

Post by pgimeno »

Kubba wrote: Tue Mar 16, 2021 10:37 pm So if I'm reading this correctly, the number of objects within a table is used to iterate through the table rather than using pairs\ipairs. I didn't know you could do it that way.
It's just another way of doing it. pairs uses an undefined order, and it also iterates over the non-numeric elements if there are any. ipairs is guaranteed to stop at the first nil, while the method I've used is only guaranteed to stop at some nil. However, in my experiments ipairs tends to be slower than the length method, so when it's guaranteed that there are no holes, I prefer it. But as darkfrei said, in this case you could use ipairs() as well. I'm not sure you can safely use pairs() though, due to the importance of order.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 6 guests