Page 1 of 1

(Solved) Enemy removal code is not working as intended

Posted: Wed Jan 09, 2013 1:48 am
by pikuchan
For anyone else that might have problems, I simply added a new value to my table named removeEnemy and set it to false.
If a collision is detected, I think set this value to true.
Then in my enemy update loop I check this variable. If it is true, I remove it from the table. If it is false, I run the missile update.


Any help would be appreciated. My problem is that my enemies are not moving as intended. Basically, this is a missile command type of game. You fire a missile, it explodes and takes any incoming missiles with it. In my case, the collision detection is working, but not all of the incoming missiles get removed. If only one missile is hit, it works. If multiple collisions occur, it remove n-1 incoming missiles. So, if I collide with 4 incoming missiles, 3 will be removed. I know the collision detection is working because it will score for 4. Relevant code is below, I am attaching the .love file.

Code: Select all

--update our bullets
	for i,v in ipairs(player.bullets) do
		bulletUpdate(dt, v)
		
		local okToRemove = bulletUpdate(dt, v)
		
		if okToRemove == true then
			table.insert(bulletsToRemove, i)
			
			bulletExplosionX = v.x - halfFrameSize
			bulletExplosionY = v.y - halfFrameSize
			bulletShowExplosion = true
			
			for ii, vv in ipairs(missileAttacks) do
				if CheckCollision(bulletExplosionX, bulletExplosionY, explosionFrameSize, explosionFrameSize, vv.x, vv.y, vv.image:getWidth(), vv.image:getHeight()) then
					--okToRemove = true
					table.insert(attacksToRemove, ii)
					
					--Score!
					player.score = player.score + 100
					
					--explosionX = vv.x - vv.image:getWidth()
					--explosionY = vv.y - vv.image:getHeight()
					--showExplosion = true
				end	
			end
			
			--remove our missiles that collided with bullets
			for i,v in ipairs(attacksToRemove) do
				table.remove(missileAttacks, v)
			end
		end
	end

Re: Enemy removal code is not working as intended

Posted: Wed Jan 09, 2013 3:01 am
by verilog
Sounds like you're removing an element from a table using a “normal” loop instead of a “reverse loop”. If you remove an element while looping from the first to the last element, the table reshaping could be skipping an element, take a look at this example:

Code: Select all

local someTable = { "apple", "oranges", "cherries", "bananas", "tomato", "strawberries", "blueberries", "pears", "blackberries" }
local someTable2 = { "apple", "oranges", "cherries", "bananas", "tomato", "strawberries", "blueberries", "pears", "blackberries" }
We would like to remove either the "tomato" or "strawberries" elements, we're looping from the first element to the last one. "tomato" is the first to go, but during the table reordering, "strawberries" will take "tomato’s" place inside the table, causing the element not to be removed in the following loop iteration:

Code: Select all

	for i, item in ipairs(someTable) do
		if(item == "tomato" or item == "strawberries" ) then
			table.remove(someTable, i);
		end
	end
The solution is pretty straightforward:

Code: Select all

--use a "reverse" loop to avoid any entry being skipped due to the table's reordering:
	
	for i = #someTable2, 1, -1 do
		local item = someTable2[i]
		if(item == "tomato" or item == "strawberries" ) then
			table.remove(someTable2, i);
		end
	end

Re: Enemy removal code is not working as intended

Posted: Wed Jan 09, 2013 3:59 am
by pikuchan
Thanks a bunch. These types of things are easy to overlook when you have been writing OOP code for years. I'll get this put in first thing tomorrow!

Re: Enemy removal code is not working as intended

Posted: Wed Jan 09, 2013 3:05 pm
by pikuchan
I think I must be doing something silly now. I have put in the below code, but now it is not removing any enemies. Any ideas?

Code: Select all

--loop through all our our attacks to remove
	for i, v in ipairs(attacksToRemove) do
		--then loop through all of the missile attacks
		for ii = #missileAttacks, 1, -1 do
			local item = missileAttacks[ii]
			--remove any matches
			if item == attacksToRemove[i] then
				table.remove(missileAttacks, i)
			end
		end
	end