Lua userdata应该是垃圾收集之前

时间:2014-06-04 04:43:12

标签: lua garbage-collection cocos2d-x cocos2d-x-3.0

我是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函数。

1 个答案:

答案 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)