I'm new to Lua. I'm trying to create a game using Cocos2d-x v3.1rc0.
I'm running into an issue where it appears that one of the objects, created by the Cocos2d-x lib, is being garbage collected before it should be.
Here is a class to keep track of "prey" on the screen. Each prey references frames/animations that will be displayed depending on the state of the prey.
Prey = {
sprite = false -- Main prey sprite.
-- Frames used for movement, getting hit, knocked out, etc.
, frame = {
idle = false -- idle frames
, move = false -- move frames
, rest = false -- resting frames
}
, state = false -- The current state of the Prey.
}
Here is the constructor:
function Prey:new()
local o = {}
setmetatable(o, self)
self.__index = self
return o
end
Here is where the frames are associated to the prey:
function Prey:setFrames(frames)
--[[ Moving ]]--
self.frame.move = cc.Animation:createWithSpriteFrames({frames[1], frames[2], frames[3]}, 1.0)
cclog("move frames: " .. #self.frame.move:getFrames())
--[[ Resting ]]--
self.frame.rest = cc.Animation:createWithSpriteFrames({frames[4], frames[5]}, 2.0)
cclog("rest frames: " .. #self.frame.rest:getFrames())
end
The above will print the following:
cocos2d: [LUA-print] move frames: 3
cocos2d: [LUA-print] rest frames: 2
However, when I attempt to call the following method, the frame.move and frame.rest variables appear to be garbage collected because an error is raised when I attempt to access them. Please note that this method is called every tick:
function Prey:tick()
cclog("state: " .. self.state)
local animation = false
-- Moving
if (self.state == PreyState.MOVING)
then
cclog("moving: " .. #self.frame.move:getFrames())
animation = self.frame.move
elseif (self.state == PreyState.RESTING)
then
cclog("resting: " .. #self.frame.rest:getFrames())
-- Resting
animation = self.frame.rest
end
end
When the cclog calls are being made for either of the two conditions the following error is displayed. Please note that I know that this specific instance of Prey has not been garbage collected because self.state was set to idle before I made the call to the tick method. It also retains self.state on subsequent calls to this method.
cocos2d: [LUA-print] state: 2
cocos2d: [LUA-print] ----------------------------------------
cocos2d: [LUA-print] LUA ERROR: [string "Prey.lua"]:189: invalid 'cobj' in function 'lua_cocos2dx_Animation_getFrames'
After looking at many articles describing how objects are retained, it appears that it's possible that my Animation object is being garbage collected. But I have no idea why! The reference to the Cocos2d-x object should be strong, right?
Here are some articles I've read regarding the subject:
- http://www.tutorialspoint.com/lua/lua_object_oriented.htm
- http://lua-users.org/wiki/WeakTablesTutorial
- http://www.lua.org/pil/17.html
- http://phrogz.net/lua/LearningLua_ValuesAndMetatables.html
- http://lua-users.org/wiki/GarbageCollectionTutorial
UPDATE 1
The following code is what causes the issue:
-- Create the instance of our prey object here...
prey = new Prey:new()
local function tick()
prey:tick()
end
scheduleID = cc.Director:getInstance():getScheduler():scheduleScriptFunc(tick, 0, false)
However, when I attempt to simply call prey:tick()
outside of the scheduler I get NO errors. I need this code to be ran every tick... what am I missing? In this particular scenario I have made the prey
a global variable so that the tick method could access the only instance of Prey. I did this to simplify this particular test. However, I'd like to make prey local and make the scheduler run the tick function for every instance of Prey.