Table.insert more than one thing?

Quick question I’m trying to do this:

if leveltimer ==1 and level==1 then
        wave={AlienA(col1,row3,a,1),AlienA(col1, row3*1.1,a,1), AlienA(col1, row3*1.2,a,1), AlienA(col1,row3*1.3,a,1), AlienA(col1,row3*1.4,a,1), RockA(col4,row3), RockB(col2,row3*1.2)}
    end
    if leveltimer ==400 and level==1 then
        table.insert(wave, AlienA(col1,row3,a,1),AlienA(col1, row3*1.1,a,1), AlienA(col1, row3*1.2,a,1), AlienA(col1,row3*1.3,a,1), AlienA(col1,row3*1.4,a,1), RockA(col2,row3), RockB(col4,row3*1.2) )
    end

Which is filling the table ‘wave’ with the first wave of alIens. Then when timer hits 400 it inserts new aliens into the table. The first part works well but I get errors one the next part.

The reason I doing a timer based insertion is my game involves time travel so you can jump back in time to fix something.

Thanks

Only works for adding at the last position (for speed). You could change it to be able to insert anywhere though.

function table.insertMany(tab, ...)
    local args={...}
    for i,v in ipairs(args) do
        tab[#tab+1]=v
    end
end

Thanks @yojimbo2000 the last position is fine!

So I understand the code, insertMany is pulling each tab which I think is a tab number saved as v for position in the table.

Local args is a local set of variables which the ipairs run through assigning each to a tab+a number.

As my table is called wave, do I change tab to wave?

like this? :

 if leveltimer ==400 and level==1 then
        function table.insertMany(wave, ...)
    local args={AlienA(col1,row3,a,1),AlienA(col1, row3*1.1,a,1), AlienA(col1, row3*1.2,a,1), AlienA(col1,row3*1.3,a,1), AlienA(col1,row3*1.4,a,1), RockA(col2,row3), RockB(col4,row3*1.2)}
            for i,v in ipairs(args) do
                wave[#wave+1]=v
            end
        end

Thanks

No, leave the function as is, and just substitute table.insert for table.insertMany if you have more than one thing to insert.

eg:

if leveltimer ==1 and level==1 then
        wave={AlienA(col1,row3,a,1),AlienA(col1, row3*1.1,a,1), AlienA(col1, row3*1.2,a,1), AlienA(col1,row3*1.3,a,1), AlienA(col1,row3*1.4,a,1), RockA(col4,row3), RockB(col2,row3*1.2)}
    end
    if leveltimer ==400 and level==1 then
        table.insertMany(wave, AlienA(col1,row3,a,1),AlienA(col1, row3*1.1,a,1), AlienA(col1, row3*1.2,a,1), AlienA(col1,row3*1.3,a,1), AlienA(col1,row3*1.4,a,1), RockA(col2,row3), RockB(col4,row3*1.2) )
    end

function table.insertMany(tab, ...)
    local args={...}
    for i,v in ipairs(args) do
        tab[#tab+1]=v
    end
end

so tab is just a local placeholder for whatever table you pass to the function, in this case wave. And ... is a special key that designates a variable number of arguments, which then gets packed into a local table, args.

Ah gotcha, sorry I missed seeing it was a function. That’s awesome.

So now I can create more if statements linked to leveltimer and the function insertMany checks the see if it needs to populate wave again.

Cool! Thank you!

That works brilliantly!

It’s not checking anything, it’s exactly the same as doing lots of table.insert or myTable[#myTable+1] calls in a row, but less typing. In my game jam entry, I use it in my extrude function, because each face of the object has 6 vertices, and needs 6 texCoords, and 6 normals, and I didn’t want to have 18 table.inserts in each cycle of the loop.

It’s a cool, efficient piece of code for sure

That code is still super awesome!

Hi again. This code has been working brilliantly. I have an efficiency question regarding my main file code. It’s getting bigger and bigger especially as I’m plugging in level data as the code above that @yojimbo2000 kindly helped with.

i don’t know if having that amount of if statements will slow the game as I add more data to the statements and so should I add them instead to a class that handles level data ? Or are the amount of text data so low it doesn’t need to worry? Currently main has 877 lines of code that will grow I imagine to at least 1800.

Also how can I get data from a table in another class? Do I need to setup the class in main, draw it onto the stage (call it) and then target the table within?

Thanks and sorry for the question…

I would generally avoid having lots of long branching if statements checking for various states. It probably isn’t that much of a problem performance wise, it just looks really ugly and isn’t readable.

I would think about holding wave data in a table. It could be organised by level, and then wave, have a timer flag indicated the time after which it should trigger.

Maybe something like

levels = {
--level 1
{
  --wave 1
  {timer = 400, type = AlienA, arguments = { {col1,row3,a,1}, {col1, row3*1.1,a,1}, {col1, row3*1.2,a,1}, {col1,row3*1.3,a,1}, {col1,row3*1.4,a,1}}, type = RockA, arguments = {col4,row3}, type = RockB, arguments={col2,row3*1.2}}
  }
  --wave 2
},
--level 2 etc
}

And it might trigger with something like:

if levels[level][wave].timer > levelTimer then etc

Just my idea. Designing “big data” for games (levels etc) is tricky, and usually takes a few iterations

Wrt performance, it’s hard to say without knowing what the code is doing. More if tests probably won’t matter much because Codea is very fast.

If a table is stored in a class with the name self.tbl, and you have an instance of the class named a, then you can simply use a.tbl to get the table data from anywhere in your code.

If the data is shared by all the instances of the class, so that for class A it is named (say) A.tbl, then you can use A.tbl to get the data from anywhere in your code.

Cool. @yojimbo2000 that sounds like a cool plan. And it could work well for my cut scenes too as its chocked full of if statements. I’ll test it for levels first and then i may switch the cut scenes too. Thanks!

@Ignatz that sounds cool too. So if I hear you right, if A is a class, I don’t have to have an instance of it on the stage, I can still grab the data from the table in the Class? That sounds great

Yes, a class is just a table, so you can put stuff in it that applies to all instances, eg

A=class()

A.speedLimit=5 --applies to all instances*

(* not specifically because we have written it as a property of the class, but because the class is a global table, so it can be accessed from anywhere).

Ok I’m all over the place with the code. Mainly because I am a designer by nature.

To complicate matters there are levels that split into decisions like at the end of each level (there are 5) the level names are strings as level “1” is the first level. At the end of that you can choose to go left to “2a” or right to “2b”. So level 3 has a b and c, level 4 is a-d and level 5 is a-e.

I now have the level data table in Levels class.

Levels = class()

function Levels:init(x)
    -- you can accept and set parameters here
    self.x = x
    level = {
--level 1
{
  --wave 1
  {timer = 400, type = AlienA, arguments = { {col1,row3,a,1}, {col1, row3*1.1,a,1}, {col1, row3*1.2,a,1}, {col1,row3*1.3,a,1}, {col1,row3*1.4,a,1}}, type = RockA, arguments = {col4,row3}, type = RockB, arguments={col2,row3*1.2}}
  --wave 2
},
--level 2 etc
}
    
end

function Levels:draw()
    -- Codea does not automatically call this method
end

function Levels:touched(touch)
    -- Codea does not automatically call this method
end

So before in @yojimbo2000 's code the level number comes from it’s position in the table. If it’s a string name then how do I name and check the level name in both the table and the code?

Then in main I have this code?

if Levels["level"].timer == leveltimer then 
        table.insertMany(wave, Levels[level])
    end

wave is the name of the table that holds enemies.

Help?!? Thanks rich

If the level names are valid Lua variable names, then use a key-value dictionary instead of an array. 4a etc is not a valid variable name (because it starts with a number), but you can still use it as a dictionary key, if you wrap it in quotes and square brackets eg

levels = {
levelWithValidVariableName = {
  {...}, --wave 1
  {...}, --wave 2 etc
},
["4d_notAValidName"] = {...},
}

Regardless of whether it’s an array or a dictionary, you can still compute the index eg use a variable to point to the index in the table:

currentLevel = "4d_notAValidName"
currentWave = 5
...
levels[currentLevel][currentWave]

Have you read @Ignatz 's eBook (the Lua one)? It covers tables very clearly AFAIR

I’m not sure why you define a global variable level in the init function of Levels, which means it will be redefined (unnecessarily) every time you create a Level instance. I would put it outside init like this

Levels.level = { your data here…}

Which means it sits tidily inside the Levels class, but is only defined once and can be used from anywhere.

If you have sub levels within levels, it is might be best to create sub tables, so level 2a would be stored in Levels.level[2][a].

Thanks both. Hey @yojimbo, @Ignatz 's book is one of the first I had read when I started out. Tables always scare me so I’m slowly getting used to it all.

I may just change the level names to be numbers 1-15 and at end of level 1 you choose 2 or 3. At 2 you choose 4 or 5 etc… I’ll see if I can grasp what you’re saying about key value dictionary etc… It’s a new language to me. Lol

@Ignatz I see what you mean. I can set up Level = {} in Init and then add to that depending on the level data. Cool. I’m understanding better the more I play with your ideas in code

Yes, tables take some getting used to, but they are incredibly versatile, and with practice, you’ll get more familiar with them