我是Lua的新手。我正在尝试使用Cocos2d-x v3.1rc0创建游戏。
我遇到的问题似乎是Cocos2d-x lib创建的其中一个对象在它应该被收集之前被垃圾收集。
这是一个在屏幕上跟踪“猎物”的课程。每个猎物都会引用将根据猎物的状态显示的帧/动画。
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.
}
这是构造函数:
function Prey:new()
local o = {}
setmetatable(o, self)
self.__index = self
return o
end
这是帧与猎物相关联的地方:
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
以上将打印以下内容:
cocos2d: [LUA-print] move frames: 3
cocos2d: [LUA-print] rest frames: 2
但是,当我尝试调用以下方法时,frame.move和frame.rest变量似乎是垃圾收集的,因为当我尝试访问它们时会引发错误。请注意,每个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
当针对这两个条件中的任何一个进行cclog调用时,将显示以下错误。请注意,我知道这个特定的Prey实例没有被垃圾收集,因为在我调用tick方法之前self.state被设置为空闲。它还会在后续调用此方法时保留self.state。
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'
在查看了许多描述如何保留对象的文章之后,似乎我的Animation对象可能被垃圾收集了。但我不明白为什么!对Cocos2d-x对象的引用应该很强,对吗?
以下是我读过的关于这个主题的一些文章:
更新1
以下代码导致问题:
-- 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)
但是,当我尝试在调度程序之外简单地调用prey:tick()
时,我得到NO错误。我需要这个代码才能运行每一个滴答...我错过了什么?在这个特定的场景中,我将prey
作为一个全局变量,以便tick方法可以访问唯一的Prey实例。我这样做是为了简化这个特定的测试。但是,我想让猎物本地化并使调度程序为每个Prey实例运行tick函数。
答案 0 :(得分:0)
对象正在被垃圾收集。我已经运行了几个测试并得出结论,你不能将任何 Cocos2d对象与一个变量关联,以后它们不会在下一个循环中被垃圾收集。相反,您必须使用Cocos2d-x的lib来缓存纹理,然后在需要时查询这些纹理。
很难说明,但最终结果是在我需要纹理时调用cc.Director:getInstance():getTextureCache():getTextureForKey("texture.png")
,并在状态为对象更改时重新创建每个动画所需的帧。我将寻找一种缓存精灵的方法,所以我不必重新创建它们。但是,这解决了我的问题。所以经验教训是Cococ2d对象在下一个周期收集垃圾。保留的唯一对象是Cocos2d在内部缓存的对象。我可能错了,但这就是我所观察到的。
所以我的过程是首先在加载时将图像添加到纹理缓存中:
local texture = cc.Director:getInstance():getTextureCache():addImage("texture.png")
然后在稍后调用以下内容:
local texture = cc.Director:getInstance():getTextureCache():getTextureForKey("texture.png")
我真的很感激任何洞察力。你们是怎么处理这个的?这是正确的过程吗?是否有任何与缓存精灵,纹理等有关的文章供以后使用?谢谢!
更新1
是。这些对象正在Cocos2d-x库中释放。你可以通过缓存精灵帧来解决这个问题。这是我在Lua中用来缓存精灵帧的代码。缓存后,您在Lua代码中对SpriteFrame的任何引用都将继续指向该帧的活动实例。
cc.SpriteFrameCache:getInstance():addSpriteFrame(frame, name)
让SpriteFrame从缓存中退出:
local frame = cc.SpriteFrameCache:getInstance():getSpriteFrame(name)