Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
destroyBody — Gideros Forum

destroyBody

peach303peach303 Member
edited January 2013 in General questions
Hi,

i want to delete an Object completely after some time. When the object collides it changes its image. After 2 secounds it should be deleted. My first attempt is this:
function Trigger:init(xp, yp, world)
 
	-- self:addChild(sprite) ...
 
	local body = world:createBody{type = b2.DYNAMIC_BODY}
 
	self.body.type = "Trigger"
	self.parent = self
	-- .....
	self.body.aktiviert = false
	self.body.killed = false
 
	self.body:setLinearDamping(damping)
 
	self:addEventListener(Event.ENTER_FRAME, function() 
		triggerAktiviert(self,world)
		end)
end
 
 
function triggerAktiviert(self, world)
	if self.body.aktiviert and self.body.killed == false then
		if self.triggerSpr1 then self:removeChild(self.triggerSpr1) end
		self:addChild(self.triggerSpr2)
		self.triggerSpr2:setPosition(-50,-50)
		self.body.killed = true
		Timer.delayedCall(2000, function()
			finishHim(self,world)
			end)
	end
end
 
function finishHim(self,world)
	print("killing")
	if self.body then world:destroyBody(self.body) end
	if self.triggerSpr2 then self:removeChild(self.triggerSpr2) end
end
This gives an error message: body allready destroyed in this function:
function Scene3:onEnterFrame()
    self.world:step(1/60, 8, 3)
    for i = 1, self:getNumChildren() do
        local sprite = self:getChildAt(i)
        if sprite.body then                                         -- <<<<<--------
            local body = sprite.body
            local bodyX, bodyY = body:getPosition()
            sprite:setPosition(bodyX, bodyY)
            sprite:setRotation(body:getAngle() * 180 / math.pi)
        end
    end
end

Am I right, that this error appears, because finishHim and Scene3:onEnterFrame are running parallel? And immidiately after if sprite.body (true) is checked the body gets destroyed in finishHim?

So the only way to do it is to delete the body in Scene3:onEnterFrame. if self.killed destroyBody and so on?

I just want to understand

Comments



  • Am I right, that this error appears, because finishHim and Scene3:onEnterFrame are running parallel? And immidiately after if sprite.body (true) is checked the body gets destroyed in finishHim?
    Yes basically you are right. First thing to do inside finishHim function is to
    self.body = nil
    self:removeFromParent()
    That way this sprite won't be looped in Scene3:onEnterFrame() and it will not try to move the body

  • hm this does not work:

    trigger.lua:39: attempt to index field 'body' (a nil value)

    It occures in function triggerAktiviert


    But let me ask again: Do these functions really run parallel? Because if so, then body could get deleted after the other function checked if sprite.body then...
  • ar2rsawseenar2rsawseen Maintainer
    edited January 2013
    no not really in paralel, but mixed. One complete function, then other complete function

    And what is on trigger.lua:39?
  • if self.body.aktiviert and self.body.killed == false then

    i tried to remove the EventListener that calls the function but still the same error?!
  • So, sounds like you have code firing after the body has been set to nil. You can either check for self.body or check your code execution and maybe that code shouldn't be firing on it in the first place once destroyed.
  • @peach303,
    one small thing
            self:addEventListener(Event.ENTER_FRAME, function() 
    		triggerAktiviert(self,world)
    	end)
    this shows a bit of the beer sdk hangover, i.e. concept from the beer sdk being used in Gideros.

    With Gideros you can use some cool things and also pass data if you so wish.

    so you could have the same as
    function Trigger:triggerAktiviert()
      ...
    end
    and set it in the addEventHandler as
    self:addEventListener(Event.ENTER_FRAME, 
    	Trigger.triggerAktiviert
    	self)
    end
    which would pass the object self to the function

    you can also pass the world, and other data if you pass the same as a table like
     self.addEventListener(Event.ENTER_FRAME, Trigger.triggerAktiviert, {self, world} )
    just thought you could benefit from that in case you were unaware of the same.
    twitter: @ozapps | http://www.oz-apps.com | http://howto.oz-apps.com | http://reviewme.oz-apps.com
    Author of Learn Lua for iOS Game Development from Apress ( http://www.apress.com/9781430246626 )
    Cool Vizify Profile at https://www.vizify.com/oz-apps
  • peach303peach303 Member
    edited January 2013
    I just can't get this run :( I tried around a lot but nothing works. I attached my complete trigger.lua. When i run this an error occures immidiately after simulator start:


    trigger.lua:38: attempt to index field 'body' (a nil value)
    stack traceback:
    trigger.lua:38: in function
    Trigger = Core.class(Sprite)
     
     
    local triggerTex = Texture.new("trigger.png")
    local triggerReg1 = TextureRegion.new(triggerTex,0,0,100,100)
    local triggerReg2 = TextureRegion.new(triggerTex,100,0,100,100)
     
     
    function Trigger:init(xp, yp, world)
    	self.triggerSpr1 = Bitmap.new(triggerReg1)
    	self.triggerSpr2 = Bitmap.new(triggerReg2)
     
    	self:addChild(self.triggerSpr1)
    	self.triggerSpr1:setPosition(-50,-50)
     
    	self:setPosition(xp,yp)
     
    	local body = world:createBody{type = b2.DYNAMIC_BODY}
    	body:setPosition(xp, yp)
    	body:setAngle(self:getRotation() * math.pi/180)
    	local circle = b2.CircleShape.new(0, 0, 50)
    	local fixture = body:createFixture{shape = circle, density = 20.0, friction = 0, 	restitution = 0.2}
    	self.body = body
    	self.body.type = "Trigger"
    	self.parent = self
     
    	self.body.aktiviert = false
    	self.body.killed = false
     
    	self.body:setLinearDamping(damping)
     
    	self:addEventListener(Event.ENTER_FRAME, Trigger.triggerAktiviert, {self,world} )
     
    end
     
     
    function Trigger:triggerAktiviert(self, world)
    	if self.body.aktiviert and self.body.killed == false then  --< ERROR (line 38...)
    		if self.triggerSpr1 then self:removeChild(self.triggerSpr1) end
    		self:addChild(self.triggerSpr2)
    		self.triggerSpr2:setPosition(-50,-50)
    		self.body.killed = true
    		self.Timer.delayedCall(2000, Trigger.finishHim, {self,world})
    	end
    end
     
    function Trigger:finishHim(self,world)
    	print("killing")
    	--self.body = nil
    	--self:removeFromParent()
    	if self.body then world:destroyBody(self.body) end
    	if self.triggerSpr2 then self:removeChild(self.triggerSpr2) end
    end
  • At the top of your triggerAktiviert function add this :

    If not self.body then return end

    That should prevent errors but tjere are probably cleaner ways to handle elsewhere in your code (like whatever calls that function most likely)
  • OZAppsOZApps Guru
    edited January 2013
    @peach303, when working with functions and passing tables, you need to take care of that.
     object.function1({self, world, "test"})
     
     function object:function1(param)
     end
    The param is the variable that receives the table with the data and they can be accessed as param[1], param[2], etc or have named parameters like so,
     object:function({obj=self, box2dObj=world, text="test"})
    and these can then be accessed as param.obj, param.box2dObj and param.text

    Likes: zvardin

    twitter: @ozapps | http://www.oz-apps.com | http://howto.oz-apps.com | http://reviewme.oz-apps.com
    Author of Learn Lua for iOS Game Development from Apress ( http://www.apress.com/9781430246626 )
    Cool Vizify Profile at https://www.vizify.com/oz-apps
    +1 -1 (+1 / -0 )Share on Facebook
  • WHat are you trying to check on that line 38 with :
    if self.body.aktiviert and self.body.killed == false then
    I am just guessing but if you are trying to use the and like & I think they do not work the same way like some other languages.
  • zvardinzvardin Member
    edited January 2013
    When you have functions with a colon, self is automatically handled by Lua also. In this case you need to pass more than just self, so I would take note of what @OZApps just mentioned for parameters as well.
  • Hi,

    thx for the help. It is still not running. This prints out a "nil". I dont get it...
     
    function Trigger:init(xp, yp, world)
     
    	--blah blah
     
    	self:addEventListener(Event.ENTER_FRAME, Trigger.triggerAktiviert, {self, world} )
     
    	return Trigger
    end
     
     
    function Trigger:triggerAktiviert(param)
    	print(param[1])
    end
  • ar2rsawseenar2rsawseen Maintainer
    edited January 2013
    I don't know about parameters, but what I would do, as I mentioned before somewhere on the other thread:
    function Trigger:init(xp, yp, world)
    	self.world = world 
    	--blah blah
     
    	self:addEventListener(Event.ENTER_FRAME, Trigger.triggerAktiviert, self)
     
    	return Trigger
    end
     
     
    function Trigger:triggerAktiviert()
    	print(self.world)
    end
    this way you can use class properties self.property etc in any class method

    Likes: zvardin

    +1 -1 (+1 / -0 )Share on Facebook
  • You need to change your function definition to:
    function Trigger.triggerAktiviert(param)
       print(param[1])
    end
    By having the colon, you are having lua automatically assume you are getting self. I suspect what's happening is, if you checked self inside that function you would have the data you passed (self and world inside).
  • @ar2sawseen's suggestion might make things a lot simpler for you also. That distinction for function definitions is important to keep in mind though.
  • Ok. I will change the code like ar2sawseen suggested.

    But your hint workes too zvardin.
  • Object = Core.class()
     
    function Object:init()
     
    end
     
    function Object:test1(param)
       print("self is: ", self, ", param is: ", param)
    end
     
    function Object.test2(self, param)
        print("self is: ", self, ", param is: ", param)
    end
    The 2 functions 'test1' and 'test2' in the code above function the same. It's a handy feature in Lua, but can trip you up when learning. The colon is just short hand for not having to add self as the first parameter. The same can be said when calling a function, like so:
    local x = Object.new()
    local p = 1
    x:test1(p)
    x.test1(x,p)
    x:test2(p)
    x.test2(x,p)
    Hope this helps!
  • Yes it does! It works now. Thx a lot.
Sign In or Register to comment.