Remove value in table when a body gets destroyed?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
louie999
Prole
Posts: 46
Joined: Fri Mar 06, 2015 9:01 am

Remove value in table when a body gets destroyed?

Post by louie999 »

So in this code:

Code: Select all

function love.mousepressed(x, y, button)
if player.getState(1) == "is-playing" then 
		if button == "l" then
         unit_value = unit_value + 1
			table.insert(units,{unit_id = lp.newBody(map, x, y, "kinematic"), img = lg.newImage("gfx/turret3.png"), x = tonumber(x), y = tonumber(y), id = unit_value})
		elseif button == "r" then
			for _, d in pairs(units) do
			        local unitX = d.unit_id:getX() - 10
				local unitY = d.unit_id:getY() - 10
				local unitX_max = d.unit_id:getX() + 10
				local unitY_max = d.unit_id:getY() + 10
				if x >= unitX and x <= unitX_max and y >= unitY and y <= unitY_max then
					d.unit_id:destroy()
					table.remove(units,???)
				end
			end
		end
	end		
end
When I press the left mouse button then the unit/body is created and a value is inserted in the table. But when I press the right mouse button the unit/body is removed BUT the value in the table remains, so how can I remove the value of the body in the table?

Code: Select all

fun = true
school = true

function isItFun()
    if school then
       fun = false
    end
    if not fun then 
       me:explode()
    end
end
User avatar
ejmr
Party member
Posts: 302
Joined: Fri Jun 01, 2012 7:45 am
Location: South Carolina, U.S.A.
Contact:

Re: Remove value in table when a body gets destroyed?

Post by ejmr »

You need to give table.remove() the numeric index for the sub-table you want to remove. You could do this by looping through using ipairs() instead of pairs(), and when you find the unit you want to remove then you'll have the index to give to table.remove(). At which point you should break out of the loop since table.remove() will shift all the elements "down" to fill in that hole. For example:

Code: Select all

for index, d in ipairs(units) do
    local unitX = d.unit_id:getX() - 10
    local unitY = d.unit_id:getY() - 10
    local unitX_max = d.unit_id:getX() + 10
    local unitY_max = d.unit_id:getY() + 10
    if x >= unitX and x <= unitX_max and y >= unitY and y <= unitY_max then
        d.unit_id:destroy()
        table.remove(units, index)
        break
    end
end
ejmr :: Programming and Game-Dev Blog, GitHub
南無妙法蓮華經
louie999
Prole
Posts: 46
Joined: Fri Mar 06, 2015 9:01 am

Re: Remove value in table when a body gets destroyed?

Post by louie999 »

ejmr wrote:You need to give table.remove() the numeric index for the sub-table you want to remove. You could do this by looping through using ipairs() instead of pairs(), and when you find the unit you want to remove then you'll have the index to give to table.remove(). At which point you should break out of the loop since table.remove() will shift all the elements "down" to fill in that hole. For example:

Code: Select all

for index, d in ipairs(units) do
    local unitX = d.unit_id:getX() - 10
    local unitY = d.unit_id:getY() - 10
    local unitX_max = d.unit_id:getX() + 10
    local unitY_max = d.unit_id:getY() + 10
    if x >= unitX and x <= unitX_max and y >= unitY and y <= unitY_max then
        d.unit_id:destroy()
        table.remove(units, index)
        break
    end
end
Hmm will this work?

Code: Select all

for name, d in pairs(units) do
	local unitX = d.unit_id:getX() - 10
	local unitY = d.unit_id:getY() - 10
	local unitX_max = d.unit_id:getX() + 10
	local unitY_max = d.unit_id:getY() + 10
	if x >= unitX and x <= unitX_max and y >= unitY and y <= unitY_max then
		d.unit_id:destroy()
		if d.id == d.id then
			table.remove(units,name)
		end
	end
end
:death:

Code: Select all

fun = true
school = true

function isItFun()
    if school then
       fun = false
    end
    if not fun then 
       me:explode()
    end
end
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Remove value in table when a body gets destroyed?

Post by Positive07 »

louie999 wrote: Hmm will this work?
Try it! but yeah, it should
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
louie999
Prole
Posts: 46
Joined: Fri Mar 06, 2015 9:01 am

Re: Remove value in table when a body gets destroyed?

Post by louie999 »

Positive07 wrote:
louie999 wrote: Hmm will this work?
Try it! but yeah, it should
Well it kinda works :)

Code: Select all

fun = true
school = true

function isItFun()
    if school then
       fun = false
    end
    if not fun then 
       me:explode()
    end
end
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Remove value in table when a body gets destroyed?

Post by s-ol »

A more efficient approach would be to mark every object that should get destroyed with an attribute, like ".destroy = True".

Then at the end of every game loop you can do this:

Code: Select all

for i=#i,1,-1 do
  if units[i].destroy then
    table.remove(units, i)
  end
end
This works much better because you don't end up looping over the table twice for every deletion (and it's even more efficient in case you have to remove multiple units at once). Also because we iterate backwards there is no issue with table.remove shifting the elements around.

You need to take care when interacting with your elements though, you should consider units that have .destroy set as nonexistant. (if you don't care about a one-frame delay there you can of course dont mind, but watch out that you don't kill thing twice etc.)

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Remove value in table when a body gets destroyed?

Post by Nixola »

S0lll0s wrote:You need to take care when interacting with your elements though, you should consider units that have .destroy set as nonexistant. (if you don't care about a one-frame delay there you can of course dont mind, but watch out that you don't kill thing twice etc.)
This. It took me a few minutes to understand why, in a game I was making (I'm out of ideas for now), killing an enemy with a gun, uzi or rifle yelded the correct amount of XP but killing it with a shotgun gave me a fuckload more. (I was killing it once for every bullet that hit it.)
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
BlueWolf
Prole
Posts: 12
Joined: Fri May 29, 2015 7:55 pm

Re: Remove value in table when a body gets destroyed?

Post by BlueWolf »

How about storing units as keys in table (instead of values) and doing something like:

Code: Select all

for unit, _ in pairs(units) do
   ...
   if ... then
      units[unit] = nil
   end
end
You insert unit as a key like this:

Code: Select all

units[unit] = true -- or whatever value, it doesn't really matter
Although polling destroyed units like S0lll0s suggested might be useful in some specific circumstances as well. For instance if you want to know precisely how much "overkill damage" you have done or if you want to know when two players hit something in exact same time. Although I wonder how many "one frame ties" like this would you encounter...
Post Reply

Who is online

Users browsing this forum: Yolwoocle and 219 guests