Как напрямую сопоставить переменную Lua с переменной C ++? - PullRequest
6 голосов
/ 09 июня 2011

Я работаю над игровым движком на C ++, используя Lua для определения NPC.

Я могу определить опытный NPC следующим образом:

orc =
{
    name = "Generic Orc",
    health = 100
}

function orc:onIdle()
    print("Orc idles...")
end

, а затем порождает экземпляр "Орка" с entitySpawn(orc). Это функция C ++, которая считывает значения, такие как здоровье и имя, из заданной таблицы, создает объект Entity в C ++ с заданными значениями и, кроме того, создает таблицу Lua для конкретного NPC.

Теперь я хотел бы иметь прямую связь между переменной orc.health в Lua и переменной mHealth члена соответствующего объекта Entity в C ++, чтобы я мог присваивать значение в Lua и мгновенно использовать его в C ++. и наоборот.

Это вообще возможно? Или я должен использовать функции установки / получения? Я взглянул на легкие пользовательские данные и дошел до точки хранения указателя на переменную C ++ в Lua, но не смог присвоить значение.

Ответы [ 2 ]

6 голосов
/ 09 июня 2011

Это возможно. Я предполагаю, что entitySpawn возвращает таблицу, созданную C ++ для сущности. Я также предполагаю, что вы можете предоставить функцию из C ++, которая берет таблицу сущности и возвращает текущее состояние, а также аналогично для установки. (Вы можете использовать легкий указатель пользовательских данных на объект C ++ в качестве члена этой таблицы для реализации этого.)

Итак, уродливый путь будет выглядеть так:

local myOrc = entitySpawn(orc)
local curHealth = getEntityHealth(myOrc)
setEntityHealth(myOrc, curHealth + 10)

Чтобы сделать это красивее, мы можем повеселиться с метатаблицами. Сначала мы добавим методы доступа для всех свойств, которые нас интересуют.

entityGetters = {
    health = getEntityHealth,
    -- ...
}
entitySetters = {
    health = setEntityHealth,
    -- ...
}

Затем мы создадим метатабельный , который использует эти функции для обработки присваивания свойств.

entityMetatable = {}

function entityMetatable:__index(key)
    local getter = entityGetters[key]
    if getter then
        return getter(self)
    else
        return nil
    end
end

function entityMetable:__newindex(key, value)
    local setter = entitySetters[key]
    if setter then
        return setter(self, value)
    end
end

Теперь вам нужно сделать entitySpawn назначить метатабельный. Это можно сделать с помощью функции lua_setmetatable.

int entitySpawn(lua_State* L)
{
    // ...
    // assuming that the returned table is on top of the stack
    lua_getglobal(L, "entityMetatable");
    lua_setmetatable(L, -2);
    return 1;
}

Теперь вы можете написать это следующим образом:

local myOrc = entitySpawn(orc)
myOrc.health = myOrc.health + 10

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

Вы можете создавать таблицы entityGetters, entitySetters и entityMetatable, а также метаметоды __index и __newindex в C ++ вместо Lua, если вам это кажется чище, но общая идея такова: то же самое.

2 голосов
/ 09 июня 2011

У меня нет времени, чтобы дать вам какой-либо код, но имейте в виду, orc.health - это то же самое, что и orc["health"];то есть orc - это таблица, а "health" - это элемент.

Имея это в виду, вы можете изменить index и newindex метаметоды вашей таблицы наиметь свое собственное специфическое поведение.Сохраните ваш "настоящий" экземпляр orc как некоторые личные метаданные, а затем используйте его для обновления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...