2013-12-02 4 views
1
balls = {} 
createBall() 

function checkLocation() 
    for i,v in pairs(balls) do --loops through all the balls 
     if v.x>320 or v.x<-50 or v.y<-30 then --Removes balls outside of the screen 
      v:removeSelf() 
      balls[i]=nil 
      print "gone" 
     end 
    end 
end 

function shoot(x, y) 
    if balls[#balls].inAir==false then --Checks if the last made ball is already shot 
     balls[#balls]:setLinearVelocity(-x,-y) --sets the velocity for the last made ball 
     balls[#balls].inAir=true; -- is shot 
    end 
    timer.performWithDelay(1000, createBall) -- Creates a new ball after 1 second 
end 

function createBall() 
    boll = {}; 
    boll = display.newCircle(160, 400, 20) 
    boll.x, boll.y = 160, 400 
    boll:setFillColor(255,0,0) 
    physics.addBody(boll, { density=1.0, friction=0.3, bounce=0.3, radius=25}) 
    boll:setLinearVelocity(0,0) 
    boll.inAir=false 
    balls[#balls+1] = boll; -- adds the new ball to the balls table 
    timer.performWithDelay(1000, shoot) -- shoots the ball after 1 second 
end 

Моя программа работает на 3 шара. Они создаются, снимаются и удаляются, но он не может стрелять в 4-й шар. Программа работает, если я удаляю всю функцию checkLocation, но хочу удалить шары. Что я делаю не так? Возможно, что-то с balls[#balls] ошибочно, но для меня это должно означать, что он выбирает последний сделанный шар.Corona SDK tables

ответ

1

Прежде всего, если balls таблица представляет собой массив типа таблицы, или вы хотите, чтобы перебрать часть массива только, вы лучше использовать или стандартную for i петлю вместо этого. pairs выполняет итерацию по всем индексам таблицы, включая нечисловые, такие как строковые ключи.

Не говоря уже о том, что pairs (next с помощью) также итерация в неопределенном порядке, в то время как ipairs всегда будет итерацией предсказуемым образом от 1 до первого целого ключа отсутствует в таблице. Обратите внимание: если вы используете стандартный цикл for i с оператором длины #t, это может быть немного иным, если ваша таблица не является последовательной.

За исключением случаев, __len метаметод не задан, длина таблицы т определяется только если таблица представляет собой последовательность, то есть множество его положительных цифровых клавиш равно {1..N} для некоторых целое число n. В этом случае n - его длина.


Во-вторых, устанавливая числовые индексы массива типа таблицы будет оставить таблицу с отверстиями.

local t = {1, 2, 3} 
t[2] = nil 
-- t is {1, nil, 3}, not {1, 3} as one might expect. 

Вам нужно будет использовать table.remove если вы хотите сохранить последовательную согласованность вашей таблицы.

local t = {1, 2, 3} 
table.remove(t, 2) 
-- t is {1, 3} 

Последнее, но не менее является менее очевидным и менее интуитивное изъян в своем подходе к удалению элементов.

local t = {2, 3, 5, 2, 1} 
for i=1, #t do 
    if t[i] % 2 == 1 then -- If value is odd, 
     table.remove(t, i) -- remove it. 
    end 
end 
-- t is {2, 3, 2}, but that can't be right. 

Вы удаляете элементы из массива, когда вы перебираете их вперед. Это неизбежно приведет к тому, что вы пропустите каждый элемент после удаленной, возможно, до точки, где вы перебираете внешний массив.

Если вы хотите удалить элементы из массива при его переходе по нему, вы должны сделать это назад. Если по какой-то причине вы не можете перебирать назад по массиву, вам нужно будет сохранить список индексов для последующего удаления и повторить их позади.

На этом этапе вы можете спросить: «Почему назад? «Проще говоря, это потому, что цикл не обновляет длину или не сохраняет итератор так же, как размер таблицы уменьшается, что приводит к пропуску. Если вы переходите назад, вы сохраняете структуру, в которой обрабатывается итерация. Длина не нуждается в обновлении, так как теперь она является стартовым значением, а не конечным. Итератору не нужно «удерживать» или удерживать от шага, так как перед ним всегда будет больше элементов, из-за этого идет в обратном направлении

local t = {2, 3, 5, 2, 1} 
for i=#t, 1, -1 do -- Start at the end and go backwards. 
    if t[i] % 2 == 1 then 
     table.remove(t, i) 
    end 
end 
-- t is {2, 2}, as expected. 

в заключение (ТЛ;. др версия)

  • Использование ipairs вместо pairs для массивов, если вы предпочитаете использовать итераторы vs. с for i цикла.
  • Используйте table.remove для сохранения последовательности массива.
  • Используйте обратные for i петли при удалении элементов из массивов.
+1

Лучший ответ, касающийся таблиц lua. Поздравления. Это очень помогает мне. – MarcVit

0

У вас есть массив шаров, вы не можете сделать balls[i]=nil, вы должны сделать table.remove(balls, i), или ваш массив будет иметь значение nil в середине его и перестанет работать правильно, используя table.remove удаляет элемент и сдвигает остальные предметы.

+0

Этот ответ является лишь частично правильным. Вы не упомянули, как удаление элементов из таблицы при перемещении с помощью «пар» приведет к пропуску. –

+0

@ RyanStein Конечно, то, что вы пишете, просто неправильно, см. Справочное руководство по Lua (http://www.lua.org/manual/5.2/manual.html#pdf-next): * Поведение следующего undefined, если во время обхода вы присваиваете любое значение несуществующему полю в таблице. Однако вы можете изменить существующие поля. В частности, вы можете очистить существующие поля. * – dualed

+0

Вы можете очистить существующие поля. Очистить не то же самое, что удалить в контексте последовательности/массива. Попробуйте эту небольшую демонстрационную версию, и вы увидите, что один из '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' 't = {2, 3, 5, 5, 2, 1}, для k, v в парах (t), если v% 2 == 1, тогда table.remove (t, k) end end; print (table. concat (t, ',')) ' –