Lua и C++: разделение обязанностей
Пожалуйста, помогите классифицировать способы организации игрового кода C++/Lua и разделить их обязанности. Каковы наиболее удобные способы, которые вы используете?
Например, Lua можно использовать только для инициализации объектов C++ или на каждой итерации игрового цикла. Его можно использовать только для игровой логики или для графики. Некоторые игровые движки предоставляют полный контроль над всеми подсистемами из скриптов! Мне действительно не нравится этот подход (никакого разделения вообще).
Является ли хорошей идеей реализовать все игровые объекты (npc, локации) в виде таблиц Lua без объектов C++? Или лучше их отразить (таблицы Lua для управления объектами C++)? Или что-то другое?
Спасибо.
Редактировать. Моя классификация: Lua и C++: разделение обязанностей.
Продолжение темы: Lua, состояние игры и игровой цикл
3 ответа
Мой подход состоял в том, чтобы максимально ограничить то, что подвергается воздействию Lua. Я никогда не обнаруживал необходимости в "главной" или другой подобной функции, которая вызывается каждый раз, когда воспроизводится сцена (или больше). Однако некоторые двигатели Lua (например, LOVE) делают это. Я предпочитаю определять объекты с дополнительными функциями обратного вызова для общих событий, на которые вы, возможно, захотите, чтобы объект реагировал, таких как столкновение, щелчок мыши, вход в игровой мир или выход из него и т. Д.
Конечный результат очень декларативный, почти конфигурационный файл для объектов. У меня есть функция для создания классов или типов объектов и другая для создания объектов на основе этих типов. Затем объекты имеют коллекцию методов, которые можно вызывать при ответе на различные события. Все эти методы Lua отображаются на методы C/C++, которые, в свою очередь, изменяют частные свойства объекта. Вот пример объекта-ведра, который может захватывать объекты-шарики:
define {
name='ball';
texture=png('images/orb.png');
model='active';
shape='circle';
radius=16;
mass=1.0;
elastic=.7;
friction=.4;
}
define {
name='bucket';
model='active';
mass=1;
shape='rect';
width=60;
height=52;
texture=png('images/bucket.png');
elastic=.5;
friction=.4;
oncontact = function(self, data)
if data.subject:type() == 'ball' then
local a = data.subject:angleTo(self:getxy())
if a < 130 and a > 50 then
--update score etc..
end
end
end;
}
Я бы не стал воспринимать это как "единственно верный способ" реализации вашего скриптового API. Одна из прелестей Lua в том, что он поддерживает множество различных стилей API. Это то, что я нашел, хорошо работает для игр, которые я делаю - игры на основе физики 2D.
Я предлагаю эту классификацию:
Экстремальный вариант: Lua-скрипты управляют всем (игровая логика, графика, AI и т. Д.). Более того: скрипт работает как хост-программа, владеет игровым циклом. Некоторые двигатели делают такую вещь. Ба-ад вещь: нет разделения обязанностей вообще и нет сценария безопасности.
Скрипты Lua поддерживают состояние игры и обрабатывают игровую логику. Вероятно, скрипты вызываются на каждой итерации игрового цикла.
Скрипты Lua редко используются для инициализации, конфигурации, обратных вызовов. Хост-программа предоставляет (связывает) очень минималистичный интерфейс для сценариев. Таким образом, сценарии построены из таких хорошо спроектированных и предоставленных блоков.
Начните с малого. Разрешите доступ к игровым объектам, чтобы вы могли выполнять сценарии для карт / уровней. Поведение, которое одинаково для разных карт / уровней, вероятно, не требует сценариев.
Кроме того, только предоставьте доступ к общедоступному интерфейсу ваших объектов.