Эффективное удаление объектов из памяти

#lua #coronasdk

#lua #coronasdk

Вопрос:

У меня есть следующий код в main.lua Все, что я пытаюсь сделать, это создать прямоугольники, добавить их в physics, чтобы они могли исчезать с экрана, удалить прямоугольники из памяти, как только их 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 , но я не знаю почему. Кроме того, это правильный способ удаления объектов из памяти?

Комментарии:

1. 5 ~= nil это юридическое заявление. Эта ошибка, вероятно, возникает в результате rects[i].y > display.contentHeight 100 сравнения. Это означает, что ваш rects[i] объект не имеет y значения в этот момент.

2. Да .. Я прокомментировал эту строку, и кажется, что это rects[i].y > display.contentHeight 100 вызывает проблему. Но я не понимаю, почему, поскольку в rectTouch() Я удаляю объект и делаю его нулевым, и условие if rects[i] ~= nil then не должно позволять ему достигать if rects[i].y > display.contentHeight 100 then , если оно равно нулю

Ответ №1:

Проблема в rectTouch функции touch, вам нужно удалить не только прямоугольник, но и ссылку, которая есть в вашей rects[] таблице. Вы можете создавать прямоугольники со значением id, чтобы вы могли идентифицировать их в функции event и удалять их.

 --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 и обнаружить столкновение, чтобы удалить прямоугольник.
Посмотрите на руководство по обнаружению столкновений

Комментарии:

1. В реальном сценарии, с которым я сталкиваюсь, проблема немного отличается, поскольку мне нужно использовать removeInactiveRects() при перемещении прямоугольников с помощью transition.to () и не гравитация. Обнаружение столкновения объектов при переходе с другим объектом (границей) имеет некоторые проблемы.

2. Хорошо, но вам все равно нужно удалить прямоугольники, к которым вы прикасаетесь в своем событии rectTouch(), и использовать событие onComplete из transition.to () функция для удаления остальных.

Ответ №2:

Проблема в том, что инструкция event.target = nil также не устанавливает соответствующее rects[i] значение nil, она только преобразует целевой объект из отображаемого объекта обратно в обычную таблицу. Итак, после этого утверждения, rects[i] для i , который соответствует затронутому целевому объекту, содержит обычный объект table, а не nil, и у этого объекта table нет поля y. Всякий раз, когда вы removeSelf работаете с отображаемым объектом, убедитесь, что вы удаляете ссылки из других объектов, таких как таблицы, подобные rects .

Кроме того, что касается удаления, когда объект опускается ниже определенной высоты, есть несколько способов сделать это:

  1. Один из них заключается в создании прозрачной геометрии (такой как линия), которая является физическим телом с «isSensor» = true. В обработчике столкновений вы должны использовать timer.performWithDelay(функция () 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»)»