Should it be
if wave01[a].x etc...
Should it be
if wave01[a].x etc...
I suggest what you do is write a function in the alien class like this
function Alien:hit(bulletPos)
--check if bulletPos is within the alien, return true if it is
--ideally a simple test like this
return bulletPos:dist(self.pos) < hitDistance
end
then for each bullet, you can check if it hits each alien
This is what I’m using but it returns a nil value which is wrong:
for a,b in ipairs(bullets) do
if b.y < 0 or b.y > HEIGHT then
table.remove(bullets,a)
elseif b.y >= wave[b].y and b.y <= wave[b].y+scalerY*15 and b.x >= g-scalerX*7 and b.x <= g+scalerX*7 then
table.remove(bullets,a)
--wave01[a].shot=true
end
Which is in the draw part of main.
Here’s the table wave in the set up part of main:
wave={AlienA(scalerX*-30,scalerY*100), AlienA(scalerX*-15,scalerY*100),AlienA(scalerX*0,scalerY*100),AlienA(scalerX*15,scalerY*100),AlienA(scalerX*30,scalerY*100)}
Although it must be pointed out the first value in the wave table is wrong because this is an assigning Init value to the alien instance. When I pass that data I add the first column to a value g which is
g=g+gravity.x*-50
G is my way of workng out where the postion of the alien should be based on tilting left and right
It is dangerous to remove items from a table in the middle of a loop, especially using the index number (a in your case), because it changes the numbering.
Better may be to write “b=nil” to delete bullets, or else change the loop command to loop backwards through the list, with “for i=#bullets,1,-1 do”
Or, as I believe @HyroVitalyProtago showed me, you could always insert the index number into a table called toRemove, like so:
for i,v in pairs(gameObject) do
if something then
table.insert(toRemove, i)
end
end
for a,b in pairs(toRemove) do
gameObject[b]=nil
toRemove[a]=nil
end
Thanks @Ignatz I’ve used the nill code now. I’ll use that from now on. Just so I know does that mean the item stays in the table but with data that is nullified (not used) or does it mean it is removed?
It comes down in part to whether you’re trying to maintain a sequential array (ie if the order of draw operations is important, in which case you need to use table.remove, and should probably loop backwards), or you’re happy with a key-value hash table (where you can kill items by setting them to nil and not worry about the sequence breaking, but you can’t control the order in which you move through the array).
Hey @TheSoldierKing thanks. the double table thing confuses me. But there might be a way. I successfully had hit detection code in the alien object before that cycled round the bullet code removing hits. Just couldn’t get the alien to kill itself. But could I target the table it’s in and self.b=nil? And that would be removed from the table?
Hey @yojimbo2000 thanks. The aliens are waves and when they pass the screen I want to nil them all anyway even if they aren’t killed. When you say you can’t control the order in which we move through the array (table) will that affect me? The tables are generated by hand to create waves and not proceeds rally using a random code.
I’ve got the aliens being shot individually now, but not removing themselves from the wave table.
In alien class I’m using
self.b=nil
But the aliens that are shot don’t disappear
In the snippets of code you were posting above, you were using a sequential array, ie a table indexed in order from 1 to #mytable. This is the sort that can predict the order that you move through it in. ie you can go forwards or backwards, for i=#myTable,1,-1
etc, and you can also use iPairs. BUT, you have to take a bit of care to maintain this sequence. If you set an element in the middle of the array to nil
, you will break the sequence; ipairs will stop at the element preceding the one you nilled etc, #myTable will still give the old count value.
eg:
myTab={}
for a=1,5 do
myTab[a]=math.random(70)
end
print(#myTab.." items in myTab") --prints "5 items in myTab"
myTab[3]=nil --nil the middle item
for i,v in ipairs(myTab) do
print ("element "..i.." is "..v) --ipairs only gets up to number 2
end
print(#myTab.." items in myTab") --still thinks there are 5 items
for i,v in pairs(myTab) do --pairs still sees the 4 remaining items
print ("element "..i.." is "..v) --and seems to present them in order
end
pairs
will still return the elements of a sequenced array in order it seems, even though the sequence is broken.
AFAICR I thought I saw a benchmark test somewhere that showed that for i=#myTable,1,-1
is faster than pairs
or ipairs
, but it takes a bit of extra work to maintain the sequence
Ok I think I understand. Bullets are added to the table on each screen touch. When I nill them, say the first one goes off screen because that first bullet is nil ipairs stops cycling through the table at 1 and all the other bullets just keep getting added and nothing gets removed anymore, is that understanding right @yojimbo2000 ? And thanks all. Tables is really where I struggle
It’s hard to say without seeing more of your code. Think of ipairs and pairs as functions that try to manage your table a little for you. ie it’s perfectly OK to do a table.remove
in the middle of an ipairs loop, but not in the middle of a forwards for i=1,#myTable
loop, because the latter will a) skip an item, and b) run out of items and crash at the end. iPairs “magically” avoids this, because each run through the loop it asks for whatever the next item is eg:
myTab={}
for a=1,5 do
myTab[a]=math.random(70)
end
--loop with table.remove:
for i,v in ipairs(myTab) do
print ("element "..i.." is "..v)
if i==2 then table.remove(myTab, 2) end --table.remove in the middle of an ipairs loop is absolutely fine. No elements are skipped, and there is no crash at the end of the loop
end
change it to a forwards loop, no good:
--loop with table.remove:
for i=1,#myTab do
print ("element "..i.." is "..v)
if i==2 then table.remove(myTab, 2) end --table.remove in the middle of a forward loop: one item skipped, crash at end
end
backwards is OK again:
--loop with table.remove:
for i=#myTab,1,-1 do
print ("element "..i.." is "..v)
if i==2 then table.remove(myTab, 2) end --table.remove in the middle of a backwards loop is ok
end
Cool thanks. I’m using the ipairs code anyway so I should be fine removing the item like bullets. That works cool.
Just now the way of getting code within a class to remove the instance of itself from a table called wave on the main file
I found a way. Lol. Just had to place some code in a for loop that assessed the aliens for a certain value and if so it nils them lol
a class instance can’t remove itself
best may be to have an items_for_deletion table. Inside the class instance, add self
to this table when deleting.
Then at the top of draw, go through this table and set all items in it to nil.
@Ignatz I need to test this a bit more, but I think a class instance can destroy itself, as long as the table that the instances are held in is indexed by some element of that instance (eg its physics body, like in your 2D platform game). In one of my projects, this seems to work (tho I should probably check that instance aren’t just piling up… hard to tell with a hash table)
function Body:destroy()
scene:unsubscribe("draw3D", self) --event manager handles draw
self.body:destroy()
game.bodies[self.body]=nil --table is indexed by body
end
If this is what you mean, it doesn’t work
function setup()
t={a(),a()} --create two instances
print(t[1].status,t[2].status) --prints alive, alive
t[2]:kill() --kill the second instance
print(t[1].status,t[2].status) --prints alive,alive
end
a=class()
function a:init()
self.status="alive"
end
function a:kill()
t[self]=nil
end
All I needed to do was reuse @Crumble s code he wrote for bullets and repurpose it to ‘listen’ to y values that were off screen. So when an alien is killed it’s y is placed below the bottom of screen and the for loop checks against these positions and removes them