This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
Компонент Script позволяет создавать игровую логику, используя язык программирования Lua. Скрипты добавляются к игровым объектам точно так же, как и любой другой компонент, при этом Defold будет выполнять код Lua как часть функций жизненного цикла движка.
В Defold существует три типа Lua-скриптов, для каждого из которых доступны различные библиотеки.
Defold выполняет Lua-скрипты как часть жизненного цикла движка и раскрывает этот жизненный цикл через набор предопределенных функций обратного вызова. При добавлении компонента скрипта к игровому объекту скрипт становится частью жизненного цикла игрового объекта и его компонента(ов). Скрипт оценивается в Lua-контексте при его загрузке, затем движок выполняет следующие функции и передает ссылку на текущий экземпляр компонента скрипта в качестве параметра. Эту ссылку self
можно использовать для хранения состояния в экземпляре компонента.
self
— это объект типа userdata, который действует как Lua-таблица, однако его нельзя итерировать с помощью pairs()
или ipairs()
и нельзя распечатать с помощью pprint()
.
init(self)
function init(self)
-- Эти переменные доступны в течение всего времени существования экземпляра компонента
self.my_var = "something"
self.age = 0
end
final(self)
function final(self)
if self.my_var == "something" then
-- провести чистку
end
end
update(self, dt)
dt
содержит дельту времени с момента последнего кадра.
function update(self, dt)
self.age = self.age + dt -- increase age with the timestep
end
on_message(self, message_id, message, sender)
msg.post()
движок вызывает эту функцию компонента-приемника. За подробностями обращайтесь к руководству по передаче сообщений.
function on_message(self, message_id, message, sender)
if message_id == hash("increase_score") then
self.total_score = self.total_score + message.score
end
end
on_input(self, action_id, action)
acquire_input_focus
), движок вызывает эту функцию когда ввод зарегистрирован. За подробностями обращайтесь к руководству по вводу.
function on_input(self, action_id, action)
if action_id == hash("touch") and action.pressed then
print("Touch", action.x, action.y)
end
end
on_reload(self)
function on_reload(self)
print(self.age) -- вывести возраст данного игрового объекта
end
Игровой объект с компонентом Script реализует некоторую логику. Часто эта логика зависит от какого-либо внешнего фактора. Вражеский AI может реагировать на то, что игрок находится в определенном радиусе от него; дверь может отомкнуться и открыться в результате взаимодействия с игроком и т.д. и т.п.
Функция update()
позволяет реализовать комплексное поведение, определяемое как механизм состояний, запускаемый каждый кадр — иногда это вполне адекватный подход. Однако каждый вызов update()
сопряжен с определенными затратами. Если функция в действительности не нужна, ее следует удалить и вместо этого попытаться построить логику реактивно. Выгоднее пассивно ждать какого-либо сообщения с последующей реакцией, чем активно исследовать игровой мир в поисках данных для ответа. Более того, проектирование реактивным способом также часто приводит к более чистому и надежному дизайну и реализации.
Давайте рассмотрим конкретный пример. Предположим, вы хотите, чтобы скрипт отправил сообщение через 2 секунды после того, как он был инициирован. Затем он должен дождаться определенного ответного сообщения и после получения ответа отправить еще одно сообщение через 5 секунд. Нереактивный код для этого будет выглядеть примерно так:
function init(self)
-- Счетчик для учета времени.
self.counter = 0
-- Это необходимо, чтобы следить за состоянием.
self.state = "first"
end
function update(self, dt)
self.counter = self.counter + dt
if self.counter >= 2.0 and self.state == "first" then
-- отправить сообщение через 2 секунды
msg.post("some_object", "some_message")
self.state = "waiting"
end
if self.counter >= 5.0 and self.state == "second" then
-- отправить сообщение через 5 секунд после получения "ответа"
msg.post("another_object", "another_message")
-- Nil the state so we don’t reach this state block again.
self.state = nil
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("response") then
-- “first” state done. enter next
self.state = "second"
-- zero the counter
self.counter = 0
end
end
Даже в этом довольно простом случае мы получаем довольно запутанную логику. Это можно улучшить с помощью горутин в модуле (см. ниже), но давайте вместо этого попробуем сделать это реактивным и использовать встроенный механизм синхронизации.
local function send_first()
msg.post("some_object", "some_message")
end
function init(self)
-- Подождать 2 секунды, затем вызвать send_first()
timer.delay(2, false, send_first)
end
local function send_second()
msg.post("another_object", "another_message")
end
function on_message(self, message_id, message, sender)
if message_id == hash("response") then
-- Подождать 5 секунды, затем вызвать send_second()
timer.delay(5, false, send_second)
end
end
Так чище и проще для понимания. Мы избавляемся от внутренних переменных состояния, которые часто трудно проследить через логику, и которые могут привести к трудноуловимым ошибкам. Мы также полностью избавляемся от функции update()
. Это освобождает движок от необходимости вызывать скрипт 60 раз в секунду, даже если он простаивает.
Редактор Defold поддерживает редактирование Lua-скриптов с подсветкой синтаксиса и автозаполнением. Чтобы заполнить имена функций Defold, нажмите Ctrl+Space, чтобы вызвать список функций, соответствующих тому, что вы вводите.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB