Reputation: 59
balls = {}
createBall()
function checkLocation()
for i,v in pairs(balls) do --loops through all the balls
if v.x>320 or v.x<-50 or v.y<-30 then --Removes balls outside of the screen
v:removeSelf()
balls[i]=nil
print "gone"
end
end
end
function shoot(x, y)
if balls[#balls].inAir==false then --Checks if the last made ball is already shot
balls[#balls]:setLinearVelocity(-x,-y) --sets the velocity for the last made ball
balls[#balls].inAir=true; -- is shot
end
timer.performWithDelay( 1000, createBall ) -- Creates a new ball after 1 second
end
function createBall()
boll = {};
boll = display.newCircle( 160, 400, 20 )
boll.x, boll.y = 160, 400
boll:setFillColor(255,0,0)
physics.addBody( boll, { density=1.0, friction=0.3, bounce=0.3, radius=25} )
boll:setLinearVelocity(0,0)
boll.inAir=false
balls[#balls+1] = boll; -- adds the new ball to the balls table
timer.performWithDelay( 1000, shoot ) -- shoots the ball after 1 second
end
My program is working for 3 balls. They are created, shot, and deleted, but it cannot shoot the 4th ball. The program works if I delete the whole checkLocation
function, but I want to delete the balls. What am I doing wrong? Maybe something with the balls[#balls]
is wrong, but for me it should mean that it selects the last made ball.
Upvotes: 1
Views: 1321
Reputation: 8000
First of all, if your balls
table is an array-like table, or you want to iterate over the array part only, you're better off using ipairs
or a standard for i
loop instead. pairs
iterates over all indices of a table, including non-numeric ones such as string keys.
Not to mention that pairs
(via next
) also iterates in an undefined order, whereas ipairs
will always iterate in a predictable fashion from 1
to the first integer key absent from the table. Note that if you're using a standard for i
loop with the length operator #t
, it can be a little different if your table is not sequential.
Unless a __len metamethod is given, the length of a table t is only defined if the table is a sequence, that is, the set of its positive numeric keys is equal to {1..n} for some integer n. In that case, n is its length.
Secondly, setting numeric indices of an array-like table will leave your table with holes.
local t = {1, 2, 3}
t[2] = nil
-- t is {1, nil, 3}, not {1, 3} as one might expect.
You will need to use table.remove
if you want to preserve the sequential consistency of your table.
local t = {1, 2, 3}
table.remove(t, 2)
-- t is {1, 3}
Last but not least is the less obvious and less intuitive flaw in your approach to removing elements.
local t = {2, 3, 5, 2, 1}
for i=1, #t do
if t[i] % 2 == 1 then -- If value is odd,
table.remove(t, i) -- remove it.
end
end
-- t is {2, 3, 2}, but that can't be right.
You're removing elements from an array as you iterate over them in a forward fashion. This will inevitably lead to you skipping every element after the one removed, possibly to the point where you iterate over the outside of the array.
If you want to remove elements from an array as you iterate over it, then you must do it backwards. If for some reason you cannot iterate backwards over the array, then you will have to save a list of indices to remove later and iterate over those backwards.
At this point, you might be asking, "Why backwards?" Simply put, it is because the loop does not update the length or keep the iterator the same as the table's size decreases which causes the skipping. If you go backwards, then you're preserving the structure in which the iteration is processed. The length does not need to be updated since it is now the starting value instead of the end condition. The iterator does not need to be "held back" or kept from stepping either, since there will always be more elements in front of it, due to it going backwards.
local t = {2, 3, 5, 2, 1}
for i=#t, 1, -1 do -- Start at the end and go backwards.
if t[i] % 2 == 1 then
table.remove(t, i)
end
end
-- t is {2, 2}, as expected.
In conclusion, (the tl;dr version)
ipairs
instead of pairs
for arrays, if you prefer using iterators vs. a for i
loop.table.remove
to preserve sequentiality of an array.for i
loops when removing elements from arrays.Upvotes: 1
Reputation: 1015
You have an array of balls, you can't do balls[i]=nil
you have to do table.remove(balls, i)
or your array will have a nil value in the middle of it and will stop working properly, using table.remove removes an item and shifts the remaining items.
Upvotes: 0