【问题标题】:Efficiently Remove Objects from Memory有效地从内存中删除对象
【发布时间】:2014-07-04 10:45:52
【问题描述】:

我在 main.lua 中有以下代码 我要做的就是生成矩形,将它们添加到物理中,这样它们就可以从屏幕上掉下来,一旦它们的 y 大于屏幕高度(意味着它们不再可见),就从内存中删除矩形,并删除那些矩形被用户触摸。

这是我的代码

local physics = require( "physics")
physics.start( )

--table to hold dynamically created rectangles
local rects={}
--used as index for table
local numRect=0

--event handler for rectangle touch
local function rectTouch(event)
    event.target:removeSelf( )
    event.target = nil
end

--function for spawning rectangles
local function spawnRect()
    numRect = numRect + 1
    rects[numRect] = display.newRect( display.contentWidth/2, 200, 200, 200)
    rects[numRect]:setFillColor( 1,1,1 )
    physics.addBody( rects[numRect], "dynamic",{density=1, friction=0,2, bounce=0  })
    rects[numRect]:addEventListener( "touch", rectTouch )
end

--function for removing rectangles which are no more visible
local function removeInactiveRects()
    for i = 1, #rects do
        if rects[i] ~= nil  then
            if rects[i].y > display.contentHeight + 100 then
                rects[i]:removeSelf( )
                rects[i] = nil
            end
        end

    end
end



timer.performWithDelay( 1000, spawnRect, -1 )
timer.performWithDelay( 2000, removeInactiveRects,-1 )

我收到一个错误 removeInactiveRects 函数,指出尝试将数字与 nil 进行比较,我猜负责此的语句是 rects[i] ~= nil 但我不知道为什么。此外,它是从内存中删除对象的正确方法吗?

【问题讨论】:

  • 5 ~= nil 是法律声明。该错误可能来自rects[i].y > display.contentHeight + 100 比较。这意味着您的 rects[i] 对象此时没有 y 值。
  • 是的.. 我评论了那行,似乎是rects[i].y > display.contentHeight + 100 导致了问题。但我不明白为什么在 rectTouch() 中我要删除对象并将其设为 nil,并且条件 if rects[i] ~= nil then 不应该允许它达到 if rects[i].y > display.contentHeight + 100 then 如果它是 nil

标签: lua coronasdk


【解决方案1】:

问题出在触摸rectTouch 函数中,您不仅需要删除矩形,还需要删除rects[] 表中的引用。您可以使用 id 值创建矩形,这样您就可以在事件函数中识别它们并删除它们。

--event handler for rectangle touch
local function rectTouch(event)
    local i = event.target.id
    event.target:removeSelf( )
    event.target = nil
    rects[i] = nil
end

--function for spawning rectangles
local function spawnRect()
    numRect = numRect + 1
    rects[numRect] = display.newRect( display.contentWidth/2, 200, 200, 200)
    rects[numRect]:setFillColor( 1,1,1 )
    rects[numRect].id = numRect
    physics.addBody( rects[numRect], "dynamic",{density=1, friction=0,2, bounce=0  })
    rects[numRect]:addEventListener( "touch", rectTouch )
end

我也是 Corona 的新手,所以我不确定,但也许你可以在底部 +500 创建一些“地面对象”并检测碰撞以移除矩形。 看collision detection guide

【讨论】:

  • 在我面临的实际情况中,问题略有不同,因为我需要使用 removeInactiveRects(),因为矩形是使用 transition.to() 而不是重力移动的。检测过渡中的对象与其他对象(边界)的碰撞有一些问题。
  • 好的,但是您仍然需要在 rectTouch() 事件中移除您触摸的矩形,并使用 transition.to() 函数中的 onComplete 事件移除其他矩形。
【解决方案2】:

问题在于语句event.target = nil 也没有将相应的rects[i] 设置为nil,它只是将目标从显示对象转换回常规表格。所以在这个语句之后,rects[i] 对应于被触摸的目标的i 包含一个常规的表格对象,而不是 nil,并且这个表格对象没有 y 字段。每当您在显示对象上removeSelf 时,请确保从其他对象(例如rects 等表)中删除引用。

此外,关于一旦物体低于某个高度时的移除,有几种方法可以做到这一点:

  1. 一种是制作透明几何体(例如一条线),它是一个“isSensor”=true 的物理体。在碰撞处理程序中,您必须使用 timer.performWithDelay(function () event.target:removeSelf() end) 因为您不能立即删除属于碰撞事件一部分的对象。
  2. 另一种方法是使用PhysicsContact:isEnabled() 并在碰撞处理程序中禁用碰撞并安排对象移除。
  3. 另一种方法是在运行时对象上使用enterFrame,并在其处理程序中检查y > yMax 的任何对象。这些对象可以立即删除。
  4. 最后,您使用的每 2 秒检查一次的技术也有效。

但是#4 技术每 2 秒循环一次所有“活动”盒子,而基于物理的技术(#1 和 #2)只对那些应该删除的盒子使用计算周期。 OTOH,碰撞检测本身有点要求,但在 2D 中可能没有那么多。 enterFrame 方法(#3)可能有点矫枉过正,因为它在每一帧(30 次/秒)都被调用,而您只想删除对象以将物理从永远不会再可见的进化对象中释放出来,但是当对象通过阈值时或一秒钟后发生此清理并不重要。

这在 Corona 的碰撞文档中都有解释。

【讨论】:

    【解决方案3】:

    简单使用:

    if rects[i] and rects[i].y > display.contentHeight + 100 then
    

    这是因为一些矩形被删除了,所以它们在表中的索引是空的。如果它是空的,那么很明显它不能有.y参数。

    你也可以通过像这样插入对象来避免它:

    local localRect = display.newRect( display.contentWidth/2, 200, 200, 200)
    rects:insert(localRect)
    

    而不是使用

    if rects[i] ~= nil then
    

    使用

    if rects[i] then
    

    表示“如果rects[i]中有任何对象(不是“nil”而不是“false”值)”

    【讨论】:

      猜你喜欢
      • 2015-07-01
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多