Привет ,Habr. Сегодня мы начнём разработку своего карточного рогалика про приготовление... рогаликов! Именно эта тема победила в обсуждении под предыдущим туториалом. Работать будет на свежем Godot 4.1. В этой статье добавим карты, "Руку (Копыто) карт" и реализуем функцию Drag & Drop.
![](https://habrastorage.org/getpro/habr/upload_files/366/44c/674/36644c674769418550419f462bb8357a.jpg)
Знакомство
Для начала давайте познакомимся с Эдгаром, отважным поросёнком, который мечтает стать пекарем и ради своей мечты отправится в подземелье, чтобы накормить тамошних обитателей свежей выпечкой.
![](https://habrastorage.org/getpro/habr/upload_files/206/75c/65e/20675c65ef01ef5ee40ea9a0cfe73683.gif)
В последующих статьях он будет для нас:
Замешивать тесто
![](https://habrastorage.org/getpro/habr/upload_files/acc/bd6/34a/accbd634ae291dfbd4d299315a9479b9.gif)
Формировать рогалики
![](https://habrastorage.org/getpro/habr/upload_files/ebe/3f5/56e/ebe3f556ed1caf7b7e4e4d24ffb0829f.gif)
Печь
![](https://habrastorage.org/getpro/habr/upload_files/41f/b43/fa2/41fb43fa2d7752259245eac18eb6ca97.gif)
Сервировать стол
![](https://habrastorage.org/getpro/habr/upload_files/baa/5a2/6e8/baa5a26e817adfcc03a58a31e641e1da.gif)
С Эдгаром познакомились, вернёмся к нему в следующей части. Пока, Эдгар...
Создание проекта
Создаём проект примерно так:
![](https://habrastorage.org/getpro/habr/upload_files/3a3/f7f/a85/3a3f7fa855f8e34b9060f2ac43df3184.png)
После создание проекта, заходим в настройки проекта -> Список действий и добавляем действие "click", щелчок ЛКМ
Сцена болванка для карт
Начнём как всегда с создания сцены, которую позже будем наследовать для разных карт.
Главным узлом выбираем Node2D(CardDefault), дочерний к нему Sprite2D(CardSprite) - текстурка нашей карты, дочерние к CardSprite:
Sprite2D(CardTitul) - Картинка рисуемая на карте
Label(CardName) - Заголовок карты
Label(CardDescription) - Описание карты
Дерево объектов:
![](https://habrastorage.org/getpro/habr/upload_files/ef5/fc7/e4c/ef5fc7e4cffce81a1c6d564c49a37ead.png)
Выглядеть это должно примерно так:
![](https://habrastorage.org/getpro/habr/upload_files/296/265/a39/296265a39d220356e2fc9b919228854f.png)
Давайте загрузим шрифт в Label, на 4 версии, это делается в пару кликов. Найдите где-то шрифт, файл .ttf. Выберите в дереве объектов Label, В инспекторе на вкладке "Control", последний пункт "Theme Overrides", выбираем Fonts -> загрузить и загружаем свой шрифт, поменяйте ему цвет, размер, сделайте всё под себя. Также в инспекторе, найдите свойство Autowrap Mode и установите его в Word (Smart), для обоих Label. Создайте несколько карт. Изменяя текстуру в CardTitul и напишите для них название в CardName и описание в CardDescription. Должно получится примерно следующее:
![](https://habrastorage.org/getpro/habr/upload_files/d90/b8c/05a/d90b8c05a6292e2a9ca198e08913a29b.png)
Чтобы создать карту:
Создаём новую сцену
Главным узлом сцены выбираем "Инстанцировать дочернею сцену"
(Ctrl+Shift+A) и выбираем нашу сцену, которую только-что создали.
CardTitul, В свойстве Texture, нажимаем на стрелочку "Сделать уникальным" и добавляем свою картинку.
В оба Label пишем текст.
К скрипту вернёмся чуть позже.
Сцена "Руки карт"
Главным узлом сцены выбираем Node2D(CardArm), и дочерние к нему элементы:
Sprite2D
4 Marker2D(Card1...Card4)
Каждая метка будет указывать местоположение и угол поворота для карты. У вас может быть больше 4-х, просто у Эдгара влезает только 4 карты. Заливаем текстуру нашей руки и выставляем местоположение для Marker2D. Не большое отступление, так-же выставляйте угол поворота. Карты обычно держат под углом. Для Sprite2D выставляем Z_index = 2
![](https://habrastorage.org/getpro/habr/upload_files/901/5f0/4bd/9015f04bd1f750d24d70cd7ef0ce0dcc.png)
![](https://habrastorage.org/getpro/habr/upload_files/615/3e0/f5c/6153e0f5cc6b0be49060d892d4618b18.png)
Небольшой лайфхак. Вы можете добавить на сцену, 4 карты, инстанцировав дочернею сцену. Расположить их как вам нравится. Потом записать в Marker2D положения по X и Y и угол поворота
Добавляем скрипт на CardArm и переходим к его редактированию:
extends Node2D
#Объявляем 4 переменных на экспорт, это и будут наши карты
@export var card1:PackedScene
@export var card2:PackedScene
@export var card3:PackedScene
@export var card4:PackedScene
#Записываем наши паркеры и переменные
@onready var _card1_marker = $Card1
@onready var _card2_marker = $Card2
@onready var _card3_marker = $Card3
@onready var _card4_marker = $Card4
#Спрайтик тоже запишем, вдруг пригодится потом
@onready var _sprite = $Sprite2D
#Каждой карте мы будем присваивать ID, просто пропишите эту строчку
var ID = 0
#В функции _ready, создаём наши карты
func _ready():
place_card(card1,_card1_marker)
place_card(card2,_card2_marker)
place_card(card3,_card3_marker)
place_card(card4,_card4_marker)
#Функция создания карты, в качестве аргумента,
#передаём сцену, которую ставим и маркер - куда ставим.
func place_card(scene,marker):
#Установили сцену карты
var s = scene.instantiate()
#Выставили карте поворот
s.rotation_degrees = marker.rotation_degrees
#Выставили карт местоположение
s.position = marker.position
#Увеличили счётчик, перед присваиванием, т.к. ID начинается с 1
ID += 1
#Присвоили ID
s.ID = ID
#Добавили сцену, как потомка
add_child(s)
Переменная ID, потребуется в дальнейшем, чтобы управлять картами.
Синглтон CardMover
Создаём новый скрипт, обязательно проверяем, чтобы он наследовал Node. После создания скрипта, это делается на вкладке "Script" -> Файл -> Новый скрипт. Обязательно назовите его CardMover. Переходим в настройки -> Автозагрузка -> выбираем путь до нашего скрипта и нажимаем добавить. Мы будем использовать Глобальный синглтон, для управления рукой карт. Переходим к редактированию этого скрипта:
extends Node
#Выбранная карта
var selected_card_ID = null
#Установить ID
func set_ID(ID):
selected_card_ID = ID
#Обнулить ID
func unset_ID():
selected_card_ID = null
#Получить ID
func get_ID():
return selected_card_ID
#Проверить ID
#Мы можем взаимодействовать только с выбранной картой
#Или с пустой
func check_ID(ID):
if((selected_card_ID == null) or (selected_card_ID == ID)):
return true
else:
return false
Тут никаких сложных функций нет, только почти обычные гетеры и сетеры.
Скрипт болванки для карт
Навешиваем скрипт на CardDefault и переходим к его редактированию:
extends Node2D
#Объявили переменные дерева
@onready var _card_sprite = $CardSprite
@onready var _card_titul = $CardSprite/CardTitul
@onready var _card_description = $CardSprite/CardDescription
#Объявили переменную ID
@export var ID = "0"
#Объявили локальные переменные
var start_rotation:int#Переменная стартовой позиции
var start_position:Vector2#Переменная стартового поворота
var dragable = false#Выделен-ли объект, для перетаскивания
var start_z_index#Стартовый Z-index
#Объявляем все стартовые переменные
func _ready():
start_z_index = z_index
start_rotation = rotation_degrees
start_position = position
#Функция обработки ввода игроком
func _input(event):
#Если нажата ЛКМ
if event is InputEventMouseButton and event.is_action_pressed("click"):
#Если клик произошёл в области спрайта карты и проверили ID
if (_card_sprite.get_rect().has_point(to_local(event.position)) and CardMover.check_ID(ID)):
#Можно перетаскивать
dragable = true
#Установили ID
CardMover.set_ID(ID)
#Если отпущена ЛКМ
if event is InputEventMouseButton and event.is_action_released("click"):
#Если отпустили ЛКМ в области спрайта карты и проверили ID
if (_card_sprite.get_rect().has_point(to_local(event.position)) and CardMover.check_ID(ID)):
#Отменили перетаскивание
dragable = false
#Обнулили ID
CardMover.unset_ID()
#Если переместили карту, то
if(position != start_position):
#Убирам стартовый поворот
start_rotation = 0
#Меняем стартовое положение
start_position = position
#Поменяли угол
rotation_degrees = start_rotation
#Если курсор мыши двигается
if event is InputEventMouseMotion:
#Если при движении курсор мыши задел спрайт нашей карты и проверили ID
if (_card_sprite.get_rect().has_point(to_local(event.position)) and CardMover.check_ID(ID)):
#Убрали поворот
rotation_degrees = 0
#Установили поверх других карт
z_index = 2
#Задали ID
CardMover.set_ID(ID)
else:
#Проверили ID
if (CardMover.check_ID(ID)):
#Вернули z_index
z_index = start_z_index
#Вернули угол поворота
rotation_degrees = start_rotation
#Обнулили ID
CardMover.unset_ID()
func _process(delta):
#Если состояние карты перетягивание, то следуем за курсором
if dragable:
set_global_position(get_global_mouse_position())
При создании карт в "Руке карт" мы добавляли каждой карте ID, чтобы была возможность отслеживать каждую карту в руке и взаимодействовать только с ней, если такого не было-бы, то в местах наслаивания карт друг на друга, мы бы брали две карты сразу или поворачивали две карты сразу при наведении.
Код в целом прокомментирован очень подробно, думаю вопросов не должно возникнуть.
Заключение
![](https://habrastorage.org/getpro/habr/upload_files/b2b/7b4/e66/b2b7b4e6624aea44a10bb34d0cbaa099.gif)
Вот мы и создали наши карты и базовое взаимодействие с ними. В следующей части мы научим каждую карту уникальному эффекту и будем взаимодействовать с игрой, с помощью карт.