Как я могу динамически получить переменную, используемую для инициализации экземпляра?

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

function Mob:spawn(x,y,m)
    local mob = {}
    setmetatable(mob, Mob)
    mob.x = x
    mob.y = y
    mob.is_monster = m
    return mob
end

Как только это будет сделано, я вызываю следующее:

function Mob:roll_call()
    who_is_here[self.y][self.x] = self.is_monster
    self.turn_counter = self.turn_counter * math.random(0.9, 1.1)
    table.insert(allTurnCounters, self.turn_counter)
end

Это помещает self.turn_counter моба в таблицу. Между тем, в другом модуле я определил эти две функции, составляющие суть проблемы:

function turn.decrement_counters(dt) -- runs in Dungeon.update(dt) and subtracts from allTurnCounters
    for i = 1,#allMobsSpawned do
            if allTurnCounters[i] <= 0 then
                    allTurnCounters[i] = 0
                    turn_active = true
                    whose_turn = i
                    return
            elseif allTurnCounters[i] > 0 then
                    allTurnCounters[i] = allTurnCounters[i] - (10 * dt)
            end
    end
end

function turn.whose_is_it() -- called when an entry in allTurnCounters goes zero
    if whose_turn == 1 then -- spots 1 and 2 in the spawn list are only ever for players
            player1.my_turn = true -- turns on player 1's keys
    elseif whose_turn == 2 then
            player2.my_turn = true -- turns on player 2's keys
    elseif whose_turn >= 3 then -- above 3 we're in monster territory

    end
end

Я решил, что первыми двумя экземплярами Mob, которые будут инициализированы, всегда будут игроки 1 и 2, присвоенные переменным player1 и player2 соответственно. И как бы то ни было, он отлично работает для передачи управления между игроками! Но для полноценной игры этого явно недостаточно. Мне тоже нужны монстры.

Таблица allTurnCounters получает новые записи по порядку от каждого появляющегося моба (класс, который включает как игроков, так и монстров, поэтому они могут делиться статистикой). Вот мой вопрос: Как я могу заставить Lua динамически извлекать имя таблицы, связанной с данным Turn_counter / value в этой таблице, и использовать его для получения приоритета очереди, даже если я не знаю, что был заранее создан процедурно или какое место он займет в порядке появления?

У меня есть 3 идеи, ни одну из которых я твердо не знаю, как реализовать. Один из методов - это что-то вроде отправки всей таблицы экземпляров в другую таблицу, а не только их turn_counters, а затем каким-то образом захватить пару значений (сама таблица и my_turn в таблице), напрямую обновляя значение my_turn.

Другой способ - каким-то образом использовать среду _G ... Я все еще изучаю главу 14 PiL, пытаясь адаптировать ее к своим целям, но value = _G [varname] кажется мощным фрагментом кода, который я мог бы использовать для этого. Не знаю как, но пока.

Моя последняя идея заключалась в том, чтобы, возможно, написать какой-то вид поиска-замены с распознаванием строк, который мог бы захватывать какое-то другое значение в таблице каждого моба, а затем помещать его в начало my_turn. Например, присвоение некоторого значения с известным шаблоном для каждого типа моба, которое я могу использовать в string.find, а затем в string.gsub, чтобы понравиться ... вручную, чтобы строка кода читалась так, как задумано. Хотя кажется неэлегантным.

Мне повезло, что я задал здесь свой предыдущий вопрос о Lua / Love2D, поэтому я решил, что давайте выбросим его, пока я думаю!


person Apple Baps    schedule 07.09.2016    source источник
comment
Как я могу заставить Lua динамически извлекать имя таблицы, связанной с заданным Turn_counter / значением в этой таблице [...]? - 1) у таблиц нет имен, 2) в вашем коде нет связи между записями в allTurnCounters и другими таблицами / именами / чем-либо.   -  person user253751    schedule 08.09.2016
comment
Под именем я подразумеваю переменную, связанную с таблицей, используемую для инициализации этого экземпляра класса Mob. Так, например, player1, small_ant1 или что-то еще. Я знаю, что их можно переопределить и что ссылка не зафиксирована. Но я не уверен, как конструктивно использовать эти знания для этого приложения, поэтому и спрашиваю. И правильно, нет никакой связи между allTurnCounters и чем-либо еще. Вы можете предложить хороший способ исправить это?   -  person Apple Baps    schedule 08.09.2016


Ответы (2)


Вот мое предложение, как это реализовать:

  1. Вместо allTurnCounters[i] дайте мобам свойство turn_counter и используйте allMobsSpawned[i].turn_counter. Затем удалите allTurnCounters.

  2. Вместо того, чтобы хранить номер моба в whose_turn, сохраните самого моба. (Примечание: когда я говорю «сам моб», это сокращение от «отсылка к самому мобу»)

    Так что вместо

    whose_turn = i
    

    вам придется:

    whose_turn = allMobsSpawned[i]
    
  3. Теперь whose_turn держит толпу, чья очередь. Вы можете легко проверить whose_turn == player1, whose_turn == player2 и т. Д. В качестве бонуса он больше не полагается на то, что игроки являются первыми мобами.

Вы можете получить доступ к свойствам моба через whose_turn - например, если whose_turn == player1 истинно, тогда whose_turn.x обращается к тому же полю, что и player1.x

person user253751    schedule 08.09.2016
comment
За прошедшее время я самостоятельно придумал несколько иное решение. Но в вашем ответе есть отличное предложение, которое я воспользуюсь, чтобы сделать свой ответ менее резким. - person Apple Baps; 08.09.2016

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

-- in "Mob.lua" module
function Mob:roll_call()
    who_is_here[self.y][self.x] = self.is_monster
    self.turn_counter = self.turn_counter * math.random(0.9, 1.1)
    table.insert(allMobs, {self.name, self.turn_counter})
    if self.is_monster == true then
        table.insert(allMonsters, {self.name, self.turn_counter})
    end
end

    function Mob:move(dx, dy)
     who_is_here[self.y][self.x] = nil
       self.x, self.y = self.x + dx, self.y + dy
       who_is_here[self.y][self.x] = self.is_monster
       self.turn_counter = 1 * self.speed
       for k,v in ipairs(allMobs) do
         if v[1] == self.name then
            v[2] = self.turn_counter
         end
     end
     self.my_turn = false -- flags turn is over
     turn_active = false -- flags no active turn
    end

-- in "turn.lua" module 
function turn.decrement_counters(dt)
    if turn_active == false then
        for k,v in ipairs(allMobs) do
            v[2] = v[2] - (10 * dt)
            if v[2] < 0 then
                v[2] = 0
                turn_active = true
                whose_turn = v[1]
                return
            end
        end
    else turn.whose_is_it()
    end
end

function turn.whose_is_it()
    if whose_turn == player1.name then
        player1.my_turn = true
    elseif whose_turn == player2.name then
        player2.my_turn = true
    elseif whose_turn == ant1.name then
        ant1.my_turn = true
    end
end

Turn.whose_is_it () - это та часть, которая нуждается в доработке. Если я использую метод immibis для присвоения allMobs [i] .turn_counter, это значительно упростит ситуацию и обеспечит возможность расширения в будущем. Этот ответ работает только для player1, player2 и, в частности, для муравья ant1.

person Apple Baps    schedule 08.09.2016
comment
А что вы будете делать, когда у вас будет неограниченное количество муравьев? (Скажем, королева муравьев, которая бросает яйца каждые 100 ходов, которые вылупляются после 50 ходов?) - person user253751; 08.09.2016
comment
Я не понимаю, почему нельзя просто поместить самих мобов в allMonsters и allMobs. - person user253751; 08.09.2016
comment
Вот что я в итоге сделал. - person Apple Baps; 15.09.2016