Log In  

Introduction

I'm trying to implement my "map to table" conversion as proposed in my previous forum post. To this end I created two functions: one for iterating over the map and storing it in a multi-dimensional table (generate_world()) and one for iterating over that table and placing the sprites (build_world()).

Problem

I get it to nicely iterate through the map, print out the tiles it finds and (presumably) store it in a table. However, when iterating over the table things get awry. I do get it to iterate over the first dimension (when printing it returns [table]), but when iterating over the second dimension it's empty (doesn't print anything).

All help would be greatly appreciated!

Code

function generate_world()
    world={}

    t_x=0
    t_y=0
    max_x=48
    max_y=16

    print "generating world ..."
    for x=0,max_x do
        world[x]={}
        for y=0,max_y do
            sp=mget(x,y)
            if sp != 0 then
                print("tile: "..x..","..y..": "..sp)
                world[x][y] = sp
            end
        end
    end
    print "done"
end

function build_world()
    for x in all(world) do
        for y in all(x) do
            print(y)
            -- this actually never gets executed
        end
end
P#60896 2019-01-16 19:46

Alright, I figured that the problem is nil values due to skipping tiles with sprite value 0. However, that got me even more lost as I'm now doubting whether this (multi-dimensional table) implementation can ever work.

So let me start over with a more generic question: how to actually achieve this? All pointers are very welcome.

P#60900 2019-01-16 19:59

Got it, I was over-complicating things. This is what worked for me:

            tile={
                x=x,
                y=y,
                sp=sp
            }
            add(world,tile)

So I end up with a simpler table and just iterate over all elements.

P#60901 2019-01-16 20:05 ( Edited 2019-01-16 20:06)

Remember that Lua tables start at 1, not 0. When populating your table in the first post, you started at index 0. However, when you use all() later, it will start at index 1, skipping the first tile. In addition, all() iterates over a table's sequence (the "array" part), which ends when it encounters a nil value. Sequences are always consecutive, with no "nil holes".

The name of the function all() is a bit of a misnomer, as it doesn't iterate over all elements in the table, just in the sequence. To actually iterate over all elements in the table (although not necessarily in order; consider it as a hash table/dictionary), use pairs().

https://pico-8.wikia.com/wiki/All
https://pico-8.wikia.com/wiki/Pairs

P#60908 2019-01-16 21:08 ( Edited 2019-01-16 21:11)

Thanks, I missed that completely (tables starting at 1)!

My code works, but it feels horribly inefficient because every time I want to change a sprite I for-loop over the whole table:

if (item == 32 or item == 48 or item == 49) then
    for tile in all(world) do
        if (tile.x == x and tile.y == y) then
            tile.sp = 64
        end
    end
end

Note that x and y are passed into the function from my collision detection.

Is there any way I could just look these up based on the index? I tried the suggested approach in https://blog.headchant.com/arrays-in-pico-8/ (index using concatenation of x and y), but I couldn't look up elements that way either.

P#60926 2019-01-17 15:13

Instead of actually concatenating the coordinates to a string, you can of course use arithmetic. See these examples for implementation:

That said, how exactly did using the concatenation of the x and y coordinates as the key/index not work? You should be able to look up elements that way, like it says in the blog post. However, as I mentioned before, you will not be able to iterate over a table using strings as keys/indices with all(), since that only iterates over the sequence/array part of the table. But like the blog post says, you can iterate over a table like that using pairs(), although then order is not guaranteed. (If you know Python already, for example, it's like iterating over a list vs. a dict.)

However, you went from having a two-dimensional table earlier, where you could look a tile up with x and y as indices in the respective tables/dimensions. Can't you just go back to doing that now that you know you should start at index 1 instead of 0? Then you can iterate in order, and also look up with world[x][y] (row-major order). That seems the easiest to me. Just remember that they start at 1. So then your original code can be used again (see my comments):

function generate_world()
    world={}

    t_x=0
    t_y=0
    max_x=48
    max_y=16

    print "generating world ..."

    for x=1,max_x do
        world[x]={}
        for y=1,max_y do
            sp=mget(x-1,y-1) -- the map is 0-indexed...
            if sp != 0 then
                print("tile: ".. x-1 ..",".. y-1 ..": "..sp)
                world[x][y] = sp
            end
        end
    end
end

function build_world()
    for x in all(world) do
        for y in all(x) do
            print(y)
            -- this should now be executed
        end
    end
end
P#60937 2019-01-17 20:08 ( Edited 2019-01-17 20:34)

Just noticed I didn't respond here anymore, sorry for that. You're right: the only problem I had was that I missed that Lua tables start at 1 instead of 0. Works like a charm now :)

P#61723 2019-02-10 15:31

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-28 07:54:06 | 0.006s | Q:13