attempt to call method 'applyForce' (a nil value)

ok so I’ve made some adjustments to my code and I’ve gotten a little further as I am able to restart at least once but I still get the attempt to call method ‘applyForce’ (a nil value) error

local peng = {} local function activatePengs(peng,event) peng:applyForce(0, -45, peng.x, peng.y) end local function touchScreen(event) -- print("touch") if event.phase == "began" then peng.enterFrame = activatePengs Runtime:addEventListener("enterFrame", peng) end if event.phase == "ended" then Runtime:removeEventListener("enterFrame", peng) end end local function onCollision(event) if event.phase == "began" then print "collide" composer.gotoScene( "restart",{ time=800, effect="crossFade" } ) end end function scene:create( event ) local sceneGroup = self.view ... peng = display.newImage(sceneGroup, "peng.png", 80, 201) physics.addBody(peng, "dynamic", {density=.18, bounce=0.1, friction=.5, radius=55}) ... end

EnterFrame listeners do not receive any parameters. Check the documentation for the event your are listening for.

You need to make sure you are calling applyForce() (or any function) on an object which has that function. If you want to dump out the properties of an object (table) you can use this:

local function dump( tbl ) for k,v in pairs(tbl) do print(k,v) end end

If I were you I would start by calling that and passing peng to it inside the enterFrame function.

And PLEASE PLEASE PLEASE use the ‘<>’ button when posting code!!!

Could you explain? 

EnterFrame listener functions only have one item passed to them and that’s an “event” table that has information like the time when the function was called. It has ZERO information about any object. That’s because enterFrame listeners are part of the Corona global Runtime object. There are no per-object enterFrame listeners. This means when define the Runtime enterFrame function like this:

local function activatePengs(peng,event)

peng will have the contents of the “event” table that gets passed and in this case the event entry will be nil.

You have to define it such as:

local function activatePengs(event)

In this case, event will have the event table and there is no per-object reference available.

Rob

I did that but I still got the error

Can you share your modified code?

local peng = {} local function activatePengs(event) peng:applyForce(0, -45, peng.x, peng.y) end local function touchScreen(event) -- print("touch") if event.phase == "began" then peng.enterFrame = activatePengs Runtime:addEventListener("enterFrame", peng) end if event.phase == "ended" then Runtime:removeEventListener("enterFrame", peng) end end -- local function endGame() -- composer.gotoScene( "restart", { time=800, effect="crossFade" } ) -- end local function onCollision(event) if event.phase == "began" then print "collide" -- applyForceToPenguin = false composer.gotoScene( "restart",{ time=800, effect="crossFade" } ) end end function scene:create( event ) local sceneGroup = self.view ... peng = display.newImage(sceneGroup, "peng.png", 80, 201) physics.addBody(peng, "dynamic", {density=.18, bounce=0.1, friction=.5, radius=55}) ... end

It is weird to initialize peng as a table and then later assign a display object to it.

Do this for me and see what you get:

-- At top of file: local function isValidPhysics( obj ) return( obj and type(obj.applyForce) == "function" ) end local peng -- Leave it nil local function activatePengs(event) if( isValidPhysics( peng ) then peng:applyForce(0, -45, peng.x, peng.y) end end

 That worked thank you so much :slight_smile:

You mind explaining why that worked instead of the code I have, I really would like to work with this program more

Actually, the code I gave you is bad in some ways.  It simply avoids the problem by detecting if the reference you are trying to operate on is valid.

It doesn’t solve the problem that you have a reference you thought should be valid when it isn’t.  i.e. You either have a bug in your code or an error in your assumptions.

Still, it is an OK band-aid that does no harm.

I don’t see any particular reason why your code isn’t working, but looking at it sliced up here isn’t quite the same as seeing it in situ, so I may simply not be seeing the issue.

EnterFrame listeners do not receive any parameters. Check the documentation for the event your are listening for.

You need to make sure you are calling applyForce() (or any function) on an object which has that function. If you want to dump out the properties of an object (table) you can use this:

local function dump( tbl ) for k,v in pairs(tbl) do print(k,v) end end

If I were you I would start by calling that and passing peng to it inside the enterFrame function.

And PLEASE PLEASE PLEASE use the ‘<>’ button when posting code!!!

Could you explain? 

EnterFrame listener functions only have one item passed to them and that’s an “event” table that has information like the time when the function was called. It has ZERO information about any object. That’s because enterFrame listeners are part of the Corona global Runtime object. There are no per-object enterFrame listeners. This means when define the Runtime enterFrame function like this:

local function activatePengs(peng,event)

peng will have the contents of the “event” table that gets passed and in this case the event entry will be nil.

You have to define it such as:

local function activatePengs(event)

In this case, event will have the event table and there is no per-object reference available.

Rob

I did that but I still got the error

Can you share your modified code?

local peng = {} local function activatePengs(event) peng:applyForce(0, -45, peng.x, peng.y) end local function touchScreen(event) -- print("touch") if event.phase == "began" then peng.enterFrame = activatePengs Runtime:addEventListener("enterFrame", peng) end if event.phase == "ended" then Runtime:removeEventListener("enterFrame", peng) end end -- local function endGame() -- composer.gotoScene( "restart", { time=800, effect="crossFade" } ) -- end local function onCollision(event) if event.phase == "began" then print "collide" -- applyForceToPenguin = false composer.gotoScene( "restart",{ time=800, effect="crossFade" } ) end end function scene:create( event ) local sceneGroup = self.view ... peng = display.newImage(sceneGroup, "peng.png", 80, 201) physics.addBody(peng, "dynamic", {density=.18, bounce=0.1, friction=.5, radius=55}) ... end

It is weird to initialize peng as a table and then later assign a display object to it.

Do this for me and see what you get:

-- At top of file: local function isValidPhysics( obj ) return( obj and type(obj.applyForce) == "function" ) end local peng -- Leave it nil local function activatePengs(event) if( isValidPhysics( peng ) then peng:applyForce(0, -45, peng.x, peng.y) end end

 That worked thank you so much :slight_smile:

You mind explaining why that worked instead of the code I have, I really would like to work with this program more

Actually, the code I gave you is bad in some ways.  It simply avoids the problem by detecting if the reference you are trying to operate on is valid.

It doesn’t solve the problem that you have a reference you thought should be valid when it isn’t.  i.e. You either have a bug in your code or an error in your assumptions.

Still, it is an OK band-aid that does no harm.

I don’t see any particular reason why your code isn’t working, but looking at it sliced up here isn’t quite the same as seeing it in situ, so I may simply not be seeing the issue.