Всем привет
Продолжаем серию разборов чужого кода с этой страницы: Публичный пример Defold .
Сегодня разбираем пример от britzl — Воспроизведение анимации .
Попробуйте этот проект в действии: запустите пример .
Исходная папка с проектом: ссылка на github .
Обращение к новичкам:
Я предполагаю, что у вас уже установлен Defold, если нет, перейдите по этой ссылке: Добро пожаловать в Defold.
Также, будет плюсом, если вы хотя бы поверхностно знакомы со строительными блоками Defold. Если нет, ознакомиться с основными концепциями Defold можно на официальном сайте — перейдите по этой ссылке.
Пример того, как скачать и открыть готовый проект:
Скачиваем архив с примерами проектов из github
Распаковываем скачанный ZIP архив примеров в любую папку во вашему усмотрению.
Переходим в папку examples
.
Ищем проект play_animation
.
Открываем game.project
.
Внимание: скриншоты представлены ниже, это пример скачивания и открытия проекта, в этом примере мы рассматриваем проект с названием play_animation, потому название папок проекта будет отличаться.


Конфликт версий
Нажмите (ctrl + B)
или f5
.
Если у вас фоновое изображение черное:
Зайдите в
play_animation.collection
и поменяйте значение Z Position с -1.0
до -0.5
.Теперь фоновое изображение отображается:
Скорее всего, это связано с тем, что граница отрисовки компонентов в какой-то версии движка поменялась с -1 включительно на -1 не включительно.
Рассмотрим play_animation.atlas:
В этом атласе содержится несколько изображений. Одно будет отвечать за фоновое изображение. Другие изображения добавлены в анимации. Анимация
player_walk
предназначена для перемещение игрового объекта. Анимация player_idle
будет проигрываться при неподвижном состоянии игрового объекта.
Нажмите на любую анимацию в панели outline
и нажмите клавишу SPACE(пробел)
. Анимация проигрывается в левом нижнем углу рабочей панели редактора. Ctrl + T
скрывает это проигрывание.
Рассмотрим play_animation.collection:
Мы видим два игровых объекта:
bg
и player
. Каждый имеет по одному компоненту sprite
, который отвечает за визуальное представление игрового объекта, изображение этот компонент берёт из play_animation.atlas
:Там же мы можем выбирать анимацию по умолчанию для компонента:
Игровой объект player
содержит в себе скрипт — play_animation.script
. В этом файле содержится код, по которому будет “действовать” игровой объект.
Рассмотрим game.input_binding:
Action
up, down, left, right
будут служить hash-строкой, с помощью которой мы будет обрабатывать ввод с клавиатуры.В Defold,
hash
в input — это способ представления строки как уникального числового идентификатора (хэш-функция), который используется для оптимизации производительности и памяти.Когда ты работаешь с вводом, например, нажатием клавиш, Defold не передаёт строку
"left"
напрямую. Вместо этого он использует:
hash("left")
Это значит:
"left"
превращается в уникальный числовой ключ (например,0x9d3fc1c3
).- Сравнение хэшей намного быстрее, чем сравнение строк.
Defold использует hash(...)
:
- для всех имён сообщений, анимаций, ввода, групп объектов, имён скриптовых свойств и т.д.
- потому что хранить и сравнивать строки неэффективно (особенно на мобильных устройствах).
Например:
action_id
— это уже хэшированное значение, переданное движком при нажатии клавиши.- В on_input() мы будем сравнивать его с
hash("left")
, чтобы понять, что нажата именно клавиша “влево”.
Рассмотрим файл play_animation.script:
go.property("speed", 200) -- the speed of movement
Добавляем пользовательское свойство игровому объекту, которое будет отвечать за скорость перемещения персонажа в пикселях в секунду.
msg.post(".", "acquire_input_focus")
Захватывает ввод с клавиатуры, позволит нам управлять персонажем.
self.direction = vmath.vector3(0, 0, 0) -- the current direction of movement
Вектор направления движения. Куда повернуто изображение персонажа, в ту сторону и перемещается игровой объект.
self.actions = {} -- mapping of input states (action_id mapped to pressed state)
Таблица, где будут храниться состояния клавиш (нажата/отпущена): true/false.
self.current_animation = nil -- the current animation
Текущая анимация (для проверки повторов, чтобы не начинать все заново проигрывать анимацию, когда клавиша зажата).
function on_input(self, action_id, action)
if action_id then
if action.pressed then
self.actions[action_id] = true
elseif action.released then
self.actions[action_id] = false
end
end
end
Если игрок вводит соответствующую клавишу из action указанных в game.input_binding
, то начинается обработка событий ввода.
При нажатии/отпускании клавиш обновляет self.actions
. Если была клавиша нажата — true
, отпущена — false
. Напомню ещё раз, в этом коде обрабатываются только клавиши привязанные в game.input_binding
.
В функции update
обрабатывается движение и анимация каждый кадр:
...
if self.actions[hash("left")] then
play_animation(self, hash("player_walk"))
sprite.set_hflip("#sprite", true)
self.direction.x = -self.speed
elseif self.actions[hash("right")] then
play_animation(self, hash("player_walk"))
sprite.set_hflip("#sprite", false)
self.direction.x = self.speed
else
self.direction.x = 0
end
...
if self.actions[hash("left")] then -- или (self.actions[hash("left") ] == true)
Проверяет, нажата ли клавиша “влево”. self.actions
— это таблица, в которую при нажатии клавиши заносится true
.
play_animation(self, hash("player_walk"))
Если “влево” нажата — запускается анимация ходьбы "player_walk"
(если ещё не проигрывается).
sprite.set_hflip("#sprite", true)
Отражает спрайт по горизонтали, чтобы он “смотрел” влево (по умолчанию в атласе изображения в анимации “смотрят” вправо).
self.direction.x = -self.speed
Устанавливает направление по оси X влево (отрицательное значение скорости).
...
else
self.direction.x = 0
...
Игрок не нажал ни “вправо”, ни “влево”, т.е горизонтального движения нет, а значит нет и направления.
Если нажата клавиша “вправо”, то всё также, за исключением того, что скорость ставим в положительное значение.
Логика с движением “вверх”, “вниз” аналогична, только мы изменяем координаты направления по оси Y.
if self.direction.x == 0 and self.direction.y == 0 then
play_animation(self, hash("player_idle"))
end
Если ни по X, ни по Y не движемся, то запускаем анимацию “player_idle
” — стоячее положение.
go.set_position(go.get_position() + self.direction * dt)
Эта строка обновляет позицию игрового объекта.
go.get_position()
– получает текущую позицию объекта.self.direction
– вектор направления, куда должен двигаться объект (например,vmath.vector3(200, 0, 0)
).dt
– это дельта времени между кадрами (в секундах), используется для того, чтобы движение было одинаково плавным при любом FPS.self.direction * dt
– это расстояние, на которое нужно сдвинуть объект за текущий кадр.go.set_position(...)
– устанавливает новую позицию, сдвигая объект.
msg.post("@render:", "draw_text", { text = "Move using arrow keys", position = vmath.vector3(10, 100, 0) } )
Эта строка отправляет сообщение рендеру, чтобы отрисовать текст на экране.
msg.post(...)
– отправка сообщения."@render:"
– адрес получателя — встроенная система рендеринга Defold."draw_text"
– тип сообщения: команда нарисовать текст.{ text = "...", position = vmath.vector3(...) }
– таблица с параметрами:text
– строка, которую нужно отрисовать.position
– координаты на экране, где рисовать (в пикселях от нижнего левого угла экрана).
-- play animation unless the same animation is already playing
local function play_animation(self, animation)
if self.current_animation ~= animation then
self.current_animation = animation
sprite.play_flipbook("#sprite", animation)
end
end
Этот блок кода отвечает за проигрывание анимации персонажа, если она отличается от текущей анимации персонажа.
sprite.play_flipbook("#sprite", animation)
sprite.play_flipbook(url, animation_id):
url
: ссылка на спрайтовый компонент, например:"#sprite"
— означает “спрайт-компонент текущего объекта”.- Можно указать и путь к другому объекту, например:
"enemy#sprite"
. animation_id
: имя анимации, которую нужно проиграть:- Должно быть передано как
hash("имя_анимации")
. - Например:
hash("run")
,hash("idle")
,hash("jump")
.
Надеюсь, кому-нибудь этот материал будет полезен.
Также я буду рад получить обратную связь, чтобы в дальних постах я смог улучшить качество изложений/объяснений.
Всем спасибо за внимание
Другие разборы:
- Разбор проектов на Defold 1.Tilemap Collisions [tilemap]
- Разбор проектов на Defold 2. Parallax [parallax]
- Разбор проектов на Defold 3. Game object movement [animation, movement, input]
- Разбор проектов на Defold 4. Воспроизвести анимацию [animation movement input]