Всем привет!
В этом руководстве мы создадим прототип для игры, основанной на механике свайпов:

Ссылка на git-репозиторий готового проекта:
План работ:
1. Создаём проект и добавляем необходимы ресурсы(ассеты) в проект:
Создаём проект и открываем его:
Создаём папку
assets и создаём здесь два каталога json и png:В папке
json создаём card_data.json файл:Добавим туда
json код:
[
{
"id": 1,
"title": "Name Card 1",
"description": "Description for 1 card",
"image": "card_1.png"
},
{
"id": 2,
"title": "Name Card 2",
"description": "Description for 2 card",
"image": "card_2.png"
},
{
"id": 3,
"title": "Name Card 3",
"description": "Description for 3 card",
"image": "card_3.png"
},
{
"id": 4,
"title": "Name Card 4",
"description": "Description for 4 card",
"image": "card_4.png"
},
{
"id": 5,
"title": "Name Card 5",
"description": "Description for 5 card",
"image": "card_5.png"
},
{
"id": 6,
"title": "Name Card 6",
"description": "Description for 6 card",
"image": "card_6.png"
},
{
"id": 7,
"title": "Name Card 7",
"description": "Description for 7 card",
"image": "card_7.png"
},
{
"id": 8,
"title": "Name Card 8",
"description": "Description for 8 card",
"image": "card_8.png"
}
]
Если вы не знакомы с JSON: Знакомство с JSON в Defold
Из этого файлы мы будем брать данные для карточек и передавать их в Lua таблицу, а затем использовать эти данные из Lua таблицы в нашей игре.
Теперь в каталог png добавим ассеты для спрайтов, которые будут использоваться в игровом объекте карточки:
Я использую все те же простые кубики, когда-то нарисованные Честером.
Создадим атлас и добавим туда добавленные изображения для карточек:
2. Пишем логику для свайпа:
Сначала создадим каталог core. В этой папке будем хранить основную логику игры.
Создадим скрипт
game:В этом скрипте, в функции обработки ввода напишем такой код:
function on_input(self, action_id, action)
-- Проверяем, что событие ввода связано с касанием экрана (touch)
if action_id == hash("touch") then
-- Если палец только что коснулся экрана (нажали)
if action.pressed then
-- Запоминаем координату X начального касания
self.start_x = action.x
-- Если палец отпущен и есть сохранённая начальная координата
elseif action.released and self.start_x then
-- Вычисляем разницу по X между текущей точкой и началом касания
local dx = action.x - self.start_x
-- Порог, который определяет минимальное смещение для распознавания свайпа
local threshold = 30
-- Проверяем, что смещение по горизонтали больше порога
if math.abs(dx) > threshold then
-- Если смещение вправо (положительное)
if dx > 0 then
print("Swipe right")
else
-- Если смещение влево (отрицательное)
print("Swipe left")
end
end
-- Сбрасываем сохранённое значение начала касания, чтобы обработать новые свайпы
self.start_x = nil
end
end
end
В файле game.input_binding по умолчанию на левую кнопку мыши стоит привязка ввода “touch”. По крайней мере, на момент написания этого поста(версия Defold 1.11.0):
В
main.collection создадим игровой объект game и добавим в качестве компонента скрипт game.script:У вас должно получиться что-то подобное:
Сохраним проект(
ctrl + S), соберём его(ctrl + B):Теперь сделайте свайп курсором. Ничего не происходит.
Это потому что в начале инициализации скрипта мы не отправили запрос на получение ввода данных из скрипта. Исправим это в функции
init():
function init(self)
msg.post(".", "acquire_input_focus")
end
Прежде чем собрать проект заново, давайте изменим разрешение дисплея игры. Для этого перейдём в game.project. Найдём вкладку Display:
Установим такие значения для ширины и высоты дисплея:
Сохраним проект(ctrl + S), а затем запустим проект(ctrl + B) снова.
Во время свайпов вы должны увидеть сообщение в консоле:
3. Загрузим данные из JSON в Lua Module:
В папке core создадим подкаталог card. В нем создадим луа-модуль card.lua:
Если вы не знаете что такое модуль: Что такое модуль, что такое require в Defold
Вставим такой блок кода:
local M = {}
-- Загрузка и парсинг JSON файла из ресурсов по пути "/assets/json/card_data.json"
local json_text = sys.load_resource("/assets/json/card_data.json")
if json_text then
-- Парсим JSON текст в Lua таблицу и сохраняем в M.cards
M.cards = json.decode(json_text)
else
-- Если файл не загружен, выводим сообщение об ошибке и инициализируем пустую таблицу
print("Ошибка загрузки JSON файла")
M.cards = {}
end
-- Инициализация текущего индекса карты (по умолчанию 5)
M.current_index = 5
-- Функция возвращает текущую карту из списка по индексу
function M.get_current_card()
return M.cards[M.current_index]
end
-- Функция меняет текущую карту при свайпе влево или вправо
-- direction: "left" или "right" - направление свайпа
function M.swipe_change(direction)
if direction == "right" then
M.current_index = M.current_index + 1 -- сдвигаем индекс карты вправо
if M.current_index > #M.cards then
-- Если индекс превысил количество карт, ограничиваем последний элемент
-- Чтобы зациклить, можно раскомментировать строку ниже
-- M.current_index = 1 -- переход к первой карте
M.current_index = #M.cards -- оставляем последний индекс
end
elseif direction == "left" then
M.current_index = M.current_index - 1 -- сдвигаем индекс карты влево
if M.current_index < 1 then
-- Если индекс стал меньше 1, ограничиваем первый элемент
-- Для зацикливания можно раскомментировать строку ниже
-- M.current_index = #M.cards -- переход к последней карте
M.current_index = 1 -- остаемся на первой карте
end
end
-- Выводим в консоль текущую карту для отладки
pprint(M.cards[M.current_index])
end
return M
Теперь в game.script самой первой строкой кода оставим такую записть:
local CARD = require("core.card.card")
Затем обновим обработчик ввода on_input(...), добавив несколько вызовов функций из нашей таблицы card.lua:
function on_input(self, action_id, action)
-- Проверяем, что событие ввода связано с касанием экрана (touch)
if action_id == hash("touch") then
-- Если палец только что коснулся экрана (нажали)
if action.pressed then
-- Запоминаем координату X начального касания для определения свайпа
self.start_x = action.x
-- Если палец отпущен и уже была сохранена стартовая координата
elseif action.released and self.start_x then
-- Вычисляем смещение по оси X от точки начала касания до текущей точки
local dx = action.x - self.start_x
-- Задаём порог смещения, который считается свайпом
local threshold = 30
-- Проверяем, превысило ли абсолютное смещение порог
if math.abs(dx) > threshold then
-- Если смещение положительное — свайп вправо
if dx > 0 then
print("Swipe right")
-- Вызываем функцию переключения карты вправо
CARD.swipe_change("right")
else
-- Если смещение отрицательное — свайп влево
print("Swipe left")
-- Вызываем функцию переключения карты влево
CARD.swipe_change("left")
end
end
-- Сбрасываем сохранённое начальное положение для обработки следующих свайпов
self.start_x = nil
-- Выводим в консоль текущую карту для отладки
print(CARD.get_current_card())
end
end
end
Сохраним и соберём проект. Теперь после свайпа влево или вправо выводится информация о карточке. Та самая информация, которая лежит в card_data.json.
4. Создадим игровой объект card и добавим ему визуальное представление:
В папке card создадим игровой объект card.go:
Создадим компонент
sprite:Выберем в качестве источника изображений для спрайта
main.atlas.Выберем какое-нибудь изображение в качестве анимации:
Теперь добавим 2 компонента
label, как добавляли компонент sprite:Перейдём в main.collection и добавим игровой объект в игровой объект game:
Сохраним и соберём проект:
Установим позиции для игрового объекта такими, чтобы он был расположен по центру(я просто поделил ширину и высоту дисплея на 2):
Сохраним и соберём проект:
Теперь нам необходимо изменять визуальное представление карточки во время свайпов по экрану. Для этого создадим в модуле card(card.lua) несколько функций, которые будут отправлять сообщения нашему игровому объекту card.go, а именно, его скрипту(который мы создадим). И уже через компонент скрипт будет изменять визуальное представление других компонентов в игровом объекте card.go.
-- изменяем изображение спрайта для текущей карты
function M.update_sprite(go_url)
local card = M.get_current_card()
if card and card.image then
-- Убираем расширение .png из имени файла для flipbook
local anim_id = hash(card.image:gsub("%.png$", ""))
-- Отправляем сообщение игровому объекту-спрайту сменить анимацию
msg.post(go_url, "play_animation", { id = anim_id })
end
end
-- Функция изменения description для текущей карты
function M.update_description(go_url)
local card = M.cards[M.current_index]
msg.post(go_url, "update_description", {description = card.description})
end
-- Функция изменения title для текущей карты
function M.update_title(go_url)
local card = M.cards[M.current_index]
msg.post(go_url, "update_title", {title = card.title})
end
В папке card создаём скриптовый файл card.script:
В функции обработки сообщений запишем такой код:
function on_message(self, message_id, message, sender)
if message_id == hash("play_animation") then
sprite.play_flipbook("#sprite", message.id)
elseif message_id == hash("update_description") then
label.set_text("#card_description", message.description)
elseif message_id == hash("update_title") then
label.set_text("#card_title", message.title)
end
end
Добавим скрипт в качестве компонента игрового объекта card.go:
Теперь перейдём в game.script и изменим условия в обработчике ввода on_input(...):
-- Функция обработки ввода пользователя
function on_input(self, action_id, action)
-- Проверяем, что событие ввода связано с касанием экрана
if action_id == hash("touch") then
-- Если палец только что коснулся экрана (начало касания)
if action.pressed then
-- Запоминаем координату X начального касания для определения свайпа
self.start_x = action.x
-- Если палец отпущен и есть сохранённая начальная точка касания
elseif action.released and self.start_x then
-- Вычисляем смещение по оси X от начала касания до текущей позиции отпуска
local dx = action.x - self.start_x
-- Порог смещения для распознавания действия свайпа
local threshold = 30
-- Проверяем, превышает ли абсолютное смещение порог
if math.abs(dx) > threshold then
-- Если смещение вправо (положительное значение)
if dx > 0 then
print("Swipe right")
-- Вызываем функцию смены карты вправо
CARD.swipe_change("right")
else
print("Swipe left")
-- Если смещение влево (отрицательное значение)
-- Вызываем функцию смены карты влево
CARD.swipe_change("left")
end
-- Сбрасываем начальную точку касания для следующего события
self.start_x = nil
-- Обновляем внешнее состояние карточки: спрайт, описание, заголовок
CARD.update_sprite(self.go_url)
CARD.update_description(self.go_url)
CARD.update_title(self.go_url)
end
end
end
Обновим функцию инициализации:
function init(self)
-- Запрашиваем захват фокуса ввода для текущего game object, чтобы получать события ввода
msg.post("", "acquire_input_focus")
-- Инициализируем начальное значение для координаты X начала свайпа (nil — свайп не начался)
self.start_x = nil
-- Сохраняем URL объекта карточки для удобства обращения к нему позже
self.go_url = msg.url("/card")
-- Обновляем визуальные элементы карточки: спрайт, описание и заголовок с использованием модуля CARD
CARD.update_sprite(self.go_url)
CARD.update_description(self.go_url)
CARD.update_title(self.go_url)
end
Сохраним и запустим проект:

Всем спасибо за внимание!
Если есть какие-то вопросы, пишите!

































