Сценарии для игрового актера

Я хотел бы добавить несколько сценариев к своим моделям/актерам. Когда загружается новая модель или изменяется сценарий, актер реагирует.

На данный момент у меня есть базовый класс Lua, в котором есть, например, функция Update(), и каждая модель/актер должна перегружать эту функцию. Но как это реализовать? Основная проблема в том, что каждой модели нужно уникальное имя для класса,...

  1. Я думал о таблице, ключевыми значениями которой являются идентификатор актора (уникальный), а значением будет класс, унаследованный от базового класса, но это немного сложно, когда скрипт перезагружается.

    Objects[ActorID] = Model(paramater)

    Objects[ActorID].Update = function() print("Update: actor 1") end

  2. Возможно, также возможно создать новое состояние lua для каждого актера.

На это меня вдохновил движок Leadwerks: http://www.youtube.com/watch?v=z-EuS1EYk8o

Если кто знает хорошую книгу по написанию скриптов в игровых движках, подскажите пожалуйста

Я думаю, что понял:

Вот некоторый псевдокод:

Онньюактер создал:

//Add actor
Objects[param.ID] = createClass(baseclass)

//Check if this actor has a script to run.
if param.hasScript then

   //Add the new ID to the script
   Scripts[param.filename][param.ID]

   Entity = Objects[param.ID]

   doFile(param.filename)

   Entity = nil

end

OnFileChanged:

foreach id in Scripts[changedfile] do

    Entity = Objects[id]

    dofile(changedfile)

    Entity = nil

end

Пример сценария:

//check if Entity is valid
if not Entity then
   print("[Error] Entity is invalid")
else   
    function Entity:Update() 
        print(self.name)
     end
end

Может работать ;)


person Mathias Hölzl    schedule 03.09.2012    source источник


Ответы (1)


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

Они используют функциональные возможности ОС для прослушивания обновлений файлов (см. эту SO вопрос для получения дополнительной информации об этом), а затем просто выполните скрипт в lua_State игры. Поскольку скрипты изменяют только определения типов (таблицы и метатаблицы), когда вы перезагружаете скрипт (я полагаю, через простой luaL_dofile или его эквивалент), новые определения перезаписывают старые, и lua радостно пыхтит, используя обновленное поведение. Если вы действительно прищуритесь и посмотрите на код, показанный в видео в редакторе, вы заметите, что они просто определяют функции, а не запускают методы Update.

И последнее замечание: если вы создадите новые lua_States для каждого актора, вы потеряете возможность свободно передавать данные между ними в Lua, и вам придется писать код C++ для ручной передачи данных между двумя (или более) lua_States.

Изменить: что касается наследования от общего базового объекта: изменение его метатаблицы изменит поведение всех объектов, поэтому нам нужно защититься от этого. Одним из способов было бы окружить сценарий объекта защитой от изменения фактической общей метатаблицы. Перед загрузкой скрипта мы сохраняем ссылку на базовую метатаблицу и заменяем ее копией, которую может использовать скрипт.

Таким образом, сценарию не нужно создавать собственную метатаблицу и не нужно знать, как остальная часть движка будет ссылаться на него. Вместо этого он просто использует Entity one. После того, как скрипт определил свое производное поведение, мы можем дать его копии Entity новое имя (основанное на имени файла скрипта, имени объекта мира и т. д.) и восстановить Entity до исходной ссылки.

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

person mtsvetkov    schedule 04.09.2012
comment
Спасибо, это действительно интересно, и теперь некоторые моменты ясны, но я до сих пор не знаю, почему они могут использовать var Entity для всех моделей. Это не локально, и когда они изменяют функцию обновления для одной модели, все функции обновления также изменяются, поскольку они имеют одно и то же имя. И именно это происходит, когда я пробую это. (Я говорю, что не уверен, что Entity используется для всех моделей) - person Mathias Hölzl; 04.09.2012
comment
Я немного изучил сам движок, и кажется, что они проводят различие между обычными сценариями и сценариями сущностей, что наводит меня на мысль, что они также обрабатываются по-разному. Я бы предположил, что за кулисами происходит какая-то метатабличная магия. Например, непосредственно перед загрузкой сценария сущности вы можете сохранить ссылку на исходную сущность (или, по крайней мере, ее метатаблицу) и заменить ее копией, загрузить сценарий, а затем восстановить исходную сущность. Имеет смысл, если вы хотите, чтобы обновления скриптов не содержали изменений, внесенных в предыдущие, которые не были перезаписаны. - person mtsvetkov; 04.09.2012
comment
Таким образом, исходная метатаблица Entity не загрязняется, вы можете ссылаться на Entity (в отличие от создания собственных метатаблиц, которые оставили бы возможность для пользователя облажаться и создать объект, несовместимый с остальной частью движка), и когда происходит обновление, вы начинаете со свежей копии Entity. В противном случае, если вы определите Entity:foo, а затем передумаете и удалите его, он останется в lua_State, так как ничто не перезаписало его. (недостаточно места для комментариев, поэтому я, вероятно, обновлю ответ, если вы удовлетворены объяснением) - person mtsvetkov; 04.09.2012
comment
Большое спасибо за все усилия, вы указали мне правильное направление - person Mathias Hölzl; 04.09.2012