루아에서 테이블은 마치 배열처럼 사용할 수 있는데 인덱스가 1로 부터 시작한다는 것이 특이하다.


          tA = {10,11, 20, 30, 40}

          print(tA[1]) -- 10 이 찍힌다

          print(tA[3]) -- 20 이 찍힌다


하지만 인덱스를 0으로부터 시작시킬 수도 있다.


          tB = {[0]=10,11, 20, 30, 40}

          print(tB[1]) -- 11 이 찍힌다

          print(tB[3]) -- 30 이 찍힌다


테이블이름 앞에 #을 붙이면 배열의 크기를 구할 수 있는데, 엄밀히 얘기하면 맨 마지막 자연수키를 반환하는 것 같다.


          print(#tA) -- 5가 찍힌다

          print(#tB) -- 4가 찍힌다


만약 tA의 한 요소를 삭제하기 위해서 nil로 지정하면, 예를 들어서


          tA[4]=nil

          print(tA[4]) -- nil 이 찍힌다

          print(#tA) -- 여전히 5가 찍힌다.


이때 오해하기 쉬운게 4번째 요소가 nil로 사라졌으니 tA의 크기는 4로 줄어야 되는 것 아니냐 하는 것인데 여전히 5이다. 4번째 요소는 nil로 바뀌었을뿐 여전히 자리를 차지하고 있다.

  완전히 삭제하려면 table.remove()를 써야한다.


          table.remove(tA, 4)

          print(tA[4]) -- 40이 찍힌다.

          print(#tA) -- 이제 4가 찍힌다.


즉, table.remove()함수를 사용하면 그 즉시로 배열의 인덱스값이 달라진다. 원래 인덱스가 5였던 것이 4로 바뀌는 것이다. 이 사실은 반복문 안에서 table.remove()함수를 사용할 때 반드시 고려해야 한다.


  프로그램을 작성하다보면 필요에 의해서 객체를 동적으로 생성한 후 (몬스터, 총알 등등) 배열에 집어넣게 된다. 그리고 어떤 조건에 맞으면 (화면에서 벗어났다던가) 그것을 삭제해야 되는데 그 조건 검사를 보통 for문으로 다음과 같이 하게 된다.


          for id=1, #tA do

                    ...

                    if condition1 == true then

                              ...

                              tA[id]:revmoveSelf()

                              tA[id] = nil

                    end

                    ...

          end


그냥 이렇게 하는 걸로는 충분하지 않은 이유는 배열의 크기는 그대로이기 때문에 새로운 객체가 생성될 때마다 배열이 계속 커지게 된다. 시간이 지날수록 조건 검사의 부담이 늘어날 것이다. 그래서 table.remove()를 다음과 같이 써야 한다.


          for id=1, #tA do

                    ...

                    if condition1 == true then

                              ...

                              tA[id]:removeSelf()

                              table.remove(tA, id)

                    end

                    ...

          end


그런데 이렇게 하면 모든 요소에 대해서 제대로 검사가 수행이 되지 않는데 그 이유는 table.remove()함수가 실행되면 그 즉시로 인덱스가 변하기 때문에 하나를 건너뛰게 되기 때문이다. 예를 들어 4번 요소가 조건이 맞아서 삭제되면 원래 5번이었던 것이 4번이 되고 그 다음 반복에서는 5번이(원래는 6번 이었던 것) 검사가 되기 때문이다.


  간단한 해법은 역순으로 검사를 하는 것이다.


          for id=#tA, 1, -1 do

                    ...

                    if condition1 == true then

                              ...

                              tA[id]:removeSelf() 

                              table.remove(tA, id)

                    end

                    ...

          end


이렇게 하면 table.remove()가 실행되어도 이후에 검색할 요소의 인덱스는 변하지 않으므로 모든 배열 요소에 대해서 조건검사가 수행이 되게 된다.


Posted by 살레시오

댓글을 달아 주세요