General discussion about LÖVE, Lua, game development, puns, and unicorns.
narffx
Prole
Posts: 5
Joined: Mon Jul 16, 2018 11:20 pm

Hi!, i've been struggling with the differences or not between this two ways of doing this.
From my beginner point of view, it's the same but maybe there are potencial bugs coming once the proyect moves forward so that's why i'm asking:

Code: Select all

for i, m in ipairs(monsters) do
for j, b in ipairs(bullets) do
if check_collision(b.x, b.y, b.width, b.height, m.x, m.y, m.width, m.height) then
table.remove(bullets, j)
m.hp = m.hp - b.damage
if m.hp == 0 then
table.remove(monsters, i)
end
end
end
end

and the other way i was doing it was:

Code: Select all

for i, m in ipairs(monsters) do
for j, b in ipairs(bullets) do
if check_collision(b.x, b.y, b.width, b.height, m.x, m.y, m.width, m.height) then
m.hp = m.hp - b.damage
if m.hp == 0 then
end
end
end
end

for i=#monsters,1,-1 do
local m = monsters[i]
table.remove(monsters, i)
end
end

for i=#bullets, 1, -1 do
local b = bullets[i]
table.remove(bullets, i)
end
end


is it really the same? is one way better than the other? both are wrong? any suggestions?

pgimeno
Party member
Posts: 1785
Joined: Sun Oct 18, 2015 2:58 pm

The second one is more reliable.

The first, single loop has two problems. One is that it can skip elements; the other one is that simultaneous collisions might not be detected. The problem of skipping elements can be solved by iterating backwards; the problem of simultaneous collisions can only be solved by marking the elements and removing them afterwards like the last method does.

How does the first version skip elements? Well, let's say you have three monsters, A, B and C, in positions 1, 2 and 3, and a bullet hits monster A. Your loop sets i to values from 1 to 3. When i is 1, the collision is detected, and A is removed. The problem is that when an element is removed, the elements are shifted! After that happens, the table has B in position 1 and C in position 2. In the next loop iteration, i is set to 2, and B, which is now in position 1, is never checked. The same happens to bullets.

The problem of skipping simultaneous collisions is as follows. If the same bullet hits two monsters at the same time (which can be more or less likely depending on how big your bullets are), first it checks collisions between the bullet and one of the monsters. If a collision is detected, then both the bullet and the monster are removed. That means that the collision between the bullet and the other monster is never checked.

Both problems are solved by deferring deletion until all checks are finished, and making the deletion loop iterate backwards, like in the second version.

narffx
Prole
Posts: 5
Joined: Mon Jul 16, 2018 11:20 pm

pgimeno wrote:
Tue Aug 20, 2019 10:36 am
The second one is more reliable.

The first, single loop has two problems. One is that it can skip elements; the other one is that simultaneous collisions might not be detected. The problem of skipping elements can be solved by iterating backwards; the problem of simultaneous collisions can only be solved by marking the elements and removing them afterwards like the last method does.

How does the first version skip elements? Well, let's say you have three monsters, A, B and C, in positions 1, 2 and 3, and a bullet hits monster A. Your loop sets i to values from 1 to 3. When i is 1, the collision is detected, and A is removed. The problem is that when an element is removed, the elements are shifted! After that happens, the table has B in position 1 and C in position 2. In the next loop iteration, i is set to 2, and B, which is now in position 1, is never checked. The same happens to bullets.

The problem of skipping simultaneous collisions is as follows. If the same bullet hits two monsters at the same time (which can be more or less likely depending on how big your bullets are), first it checks collisions between the bullet and one of the monsters. If a collision is detected, then both the bullet and the monster are removed. That means that the collision between the bullet and the other monster is never checked.

Both problems are solved by deferring deletion until all checks are finished, and making the deletion loop iterate backwards, like in the second version.
Thanks for taking the time to reply! really good answer, you clarified everything!! Now, time to make some modifications, and again, thanks!!!

### Who is online

Users browsing this forum: No registered users and 2 guests