Всем привет ![]()
Продолжаем серию разборов чужого кода с этой страницы: Публичный пример Defold .
Сегодня разбираем пример от britzl — Воспроизведение анимации .
Попробуйте этот проект в действии: запустите пример .
Исходная папка с проектом: ссылка на github .
Обращение к новичкам:
Я предполагаю, что у вас уже установлен Defold, если нет, перейдите по этой ссылке: Добро пожаловать в Defold.
Также, будет плюсом, если вы хотя бы поверхностно знакомы со строительными блоками Defold. Если нет, ознакомиться с основными концепциями Defold можно на официальном сайте — перейдите по этой ссылке.5.
Пример того, как скачать и открыть готовый проект:
Скачиваем архив с примерами проектов из 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]
- Разбор проектов на Defold 3. Движение игровых объектов [animation, movement, input]
- Разбор проектов на Defold 4. Воспроизвести анимацию [animation, movement, input]
- Разбор проектов на Defold 5. Меню и игра. Прокси-коллекции [proxy-collection, gameloop, collection, gui]











