Tables always get me...

So tables are the bit I really need to conquer. In my new game I have a class called Bullet.

I have a table set up in main setup

bullets={}

On each screen tap i want to attach a bullet to the stage or rather a copy of the bullet class as the class has all its own collision detection and movement in it.

I can write the touch code fine, but it’s using the touch code to place an instance name into the table and then the code within draw function to draw each of the bullets from the table.

The other hurdle is then the removal of bullet from the table when it goes off screen. I always stumble with tables. I’ve tried for over a year I understand them…

Any help to understand it all is greatly appreciated.

Thanks, The Major

@Majormorgan let’s represent your bulletclass by Bullet(‘your args would go here’)

to add a bullet to your table, you’d have to do

-- this adds a Bullet() in the bullets table
table.insert(bullets, Bullet() )

to draw this, you’d use iPairs or pairs (I never know which one it is), these loop over a table for you, but since you want to understand it all, here’s the manual looping

-- table index starts at 1
-- table index stops at the number of elements inside the table
for i = 1, #bullets do
    bullets[i]:draw()
end
-- since every element inside the table, is actually an instance of a class, you can draw the instance like this

for the removal of an instance, let’s say there’s a var inside of your Bullet() class that’s a boolean and contains weather or not the bullet is on screen

the checking of this could be done inside of the drawing loop

-- we'll create a temp table to store the indices of all bullets that aren't on screen
local tempTable = {}

for i = 1, #bullets do
    bullets[i]:draw()

    if bullets[i].onScreen == false then
        table.insert(tempTable, i)
    end
end

-- when the loop is done, we now have all the indices of the bullets 
-- which may be removed, to remove them, we'll go through a backwards
-- loop, because if we'd do a normal loop, we'd for example delete index
-- 1, but then everything else gets shoved up 1 place and you'll remove
-- wrong indices

-- starting at the last index of the table, to index 1, reducing the value with -1 every loop
for i = #tempTable, 1, -1 do
    -- we now remove a bullet in the bullets table
    -- the index of the bullet we remove, is stored inside of the tempTable
    table.remove(bullets, tempTable[i])
end

I hope this helped you a bit, but I’m sure others will explain it way better :stuck_out_tongue:

edited because of the corrections @yojimbo2000 made (thanks for that)

@stevon8ter Tables in Lua are always indexed from 1, never 0. For sequential arrays, use ipairs. For hash tables of key, value pairs, use pairs. To loop backwards you need to have end, start, step all separated by commas, eg for i=#bullets,1,-1 do

@yoji’bo2000 thanks for correcting me, I’ll edit this in my post, I was on the computer while I wrote this and actually forgot about adding the ‘step’, about the starting index, I just confused it with java (since that’s what I get at school)

hey @stevon8ter that is an awesome break down. It really helped me understand how the table is added to. I was trying to adjust a piece of code someone had written for putting sprites on and couldn’t get a handle between swapping the code to handle the class.

I’ve not got the touch part working yet, but I’d like to crack that myself so I’m all over that. Thank you, I might finally be able to conquer tables and use them to create my levels like I want to.

thanks for helping out too @yojimbo2000 !

The way I understand tables when you use them for storing multiple copies of something like a bullet is in all layman’s terms… but essentially when you create multiple copies of something, like bullets, without a table there is nowhere to keep track of the location of each copy.

So you add them to a table, and the table essentially just keeps track of each copy “a”, and the position of each copy “b”. This lets you use table wide tests for things like collision or going off screen, and various other things.

Then you can use:

for a,b in ipairs/pairs (table) do
     -- code that will affect all objects in the table
end

Thanks @Crumble its the layman’s understanding I’m always after. And you both explained it pretty darn well!

so in your example @Crumble a is the name of the copy and b is the position…?

@stevon8ter I don’t think that code is removing the bullets as the game slows right down over time. I’m just checking the code to see what I’ve missed. I’m sure its just something I’ve not done.

@Majormorgan Yeah, you can’t select any specific copy of the bullet, it just runs through the table and “a” is whatever copy it is looking at, and b.x and b.y is the location of that copy.

So for example (this code won’t actually work because it’s missing other key parts, I just pulled the code that uses tables out of one of my games):


function setup()
-- table for asteroids
    tab={}
-- timer for launching asteroids
    timer=0
-- frequency of asteroid spawn
    asteroidFrequency = 1
end

-- function for adding asteroids to the table when the timer calls this function
function LaunchEllipse()
    -- inserting asteroid into table at random x location and set y location
    table.insert(tab,vec2(math.random(64,WIDTH-64),1024))
end

function draw()
    -- draw asteroids that are in table
    -- make asteroids fall
for a,b in pairs(tab) do
    -- b.x and b.y locations are set in LaunchEllipse function
        sprite(asteroid,b.x,b.y,AsteroidWidth,AsteroidHeight) 
        b.y=b.y-15
    end
    -- remove asteroids that go off bottom of screen
    for a,b in pairs(tab) do
        if b.y<HEIGHT/10.24 then
            table.remove(tab,a)
        end
    end
    -- timer to launch asteroids
timer=timer+DeltaTime
    if timer>asteroidFrequency then
        LaunchEllipse()
        timer=0 
        end
end

So you can see that the “for a,b” just runs through the table and does what you want to each copy in the table. It could be “if tests” or you could change the location of each object making them fall or whatever.

You can tweak the above code to do most of the stuff that you were wanting to do with the bullets.

For removing bullets that go off screen just do:


for a,b in ipairs(bullets) do
    if b.x < 0 or b.x > WIDTH or b.y < 0 or b.y > HEIGHT then
       table.remove(bullets,a)
    end
end

That code works well to remove the bullets. Thanks team!

So bullets are working well.

I’m looking to build waves of aliens. I tried building a new table called

Wave01={}

Now when I put this code in to it, it throws up variable errors

AlienA(g,scalerY*150,scalerX*15,scalerY*15,"Project:AlienA")

I then want repeat the line of code within the table and change subsequent aliens.

@Majormorgan, I can’t see anything wrong with those snippets, my guess is one of those variables is nil at the time, or something wrong in the Alien class

post the error (copy it by touching the error text in the output panel)

Hi, here’s what I was doing in set up:

wave01={AlienA(g,scalerY*150,scalerX*15,scalerY*15,"Project:AlienA"),
    AlienA(g+scalerX*15,scalerY*150,scalerX*15,scalerY*15,"Project:AlienA")}

The error won’t copy I’m afraid but it is nil value on line 9 for scalerY. The code above is line nine. I think it’s because I’m trying prepopulate the table and probably the wrong way. The code works if I do a standard class call of

A1=AlienA(g+scalerX*15,scalerY*150,scalerX*15,scalerY*15,"Project:AlienA")

Thanks

I’m guessing scaler is a variable that you use to make the app universal? What does your X and Y scaling variable look like? I tried using a universal scaling variable and it didn’t work out and got rejected because it was buggy.

Sounds like the problem is in your scaler variables.

Thanks @JakAttak and @Jmv38.

I worked it ou - a silly mistake really - I had the table before the other variables set up in the order of things. du-oh!

Inside the alien class is a hit detect that works well against my table of screen tap generated bullets.

I then use this code in the ‘dead’ state of the alien so you see it blow up and then trigger this code:

 table.remove(wave01,a)

What I finding is two things. With my earlier table it’s only creating one alien, not two I specify. Secondly when the dead state plays it blows up, but then the code I have in the draw of main returns a nil value for the draw:

    for i = 1, #wave01 do
        wave01[i]:draw()
    end

Hi @Crumble, I know the issue you’re talking about but the scalerX and scalerY variables are working well. It was just the order I had wrong in the set up meant because it was running my table before the variables it needed it was producing nil values.

I know now the issue in having with hit detection, I was originally running detection within the alien object but it’s better to run it in one ipairs code on the main hit detecting two different tables.

So I’m currently running a for a,b ipairs code to see if the bullets in table bullets{} are off screen and removing them if so. Check.

But within that script it’s about getting the bullets to check if they are hitting an alien. I have the variables that give me the position of both a bullet and alien, but I was originally doing the variable for alien in the alien class hence a self.x etc…

Now it’s on the main stage as part of the for code, I’m trying to say assess it as [wave01,a.x] wave being the table, a being the identifier for this alien in particular and x being its x position.

But in an if statement it doesn’t like what I’m doing