Сегодня на Godot 4.1 создадим простой редактор персонажа, как в старых рпг, когда ты выбираешь внешний вид персонажа из уже нарисованных ассетов.
Вступление
Для начала давайте немного обсудим, как это будет работать. У нас есть игровой персонаж, внешний вид которого будет устанавливаться игроком, на данном примере рассмотрим, что будет устанавливаться: цвет кожи, глаза, улыбка. Выбранные игроком спрайты должны куда-то сохраниться и мы в последующем будем загружать их на персонажа. По хорошему нужно хранить это в файле сохранения игрока и при запуске этого сейва заливать в синглтон, который объявлен, как глобальная переменная. Мы же в данном туториале будем хранить только в синглтоне и никуда сохранять не будет.
Графика
Что из себя должна представлять графика.
Для начала нужно создать что-то вроде манекена, на котором мы будем рисовать. То есть это будет наш персонаж, у которого есть отметены под глаза и рот(в нашем случае).
Дальше на нём всё рисуем и сохраняем, как отдельный спрайт.
Размеры изображений у вас должны быть одинаковые в каждой группе элементов. Например для всех пар глаз, размер — 100X30, для всех улыбок — 100X40 и т.д.
Персонаж
С графикой закончили, теперь перейдём к сцене персонажа в Godot.У меня она выглядит следующим образом:

Да, конечно следует ещё добавить узел коллизии, возможно ещё некоторые узлы, но в данном туториале мы просто сделаем персонажа, которого создаёт игрок.
Как правильно расставить местоположение Sprite2D(у вас может быть AnimatedSprite2D, тогда этот способ не подойдёт, если захотите, то рассмотрим это в отдельной статье). Для этого мы опять используем нашего маникена и примеряем всё на нём. То есть выбираем, как текстуру для Body, маникена и выставляем глаза и улыбку.

Сцена редактора
У меня сцена имеет примерно следующий вид

Думаю за что отвечает каждый узел, объяснять смысла нет. Это просто надписи, кнопки и элементы декора. У ColorRect(Preview), как дочерние элементы используются просто 3 спрайта, а не сцена персонажа.
Давайте перейдём к коду:
extends Node2D #константы с путями к ассетами const EYE_ROOT = "res://Assets/Eye/eye" const SKIN_ROOT = "res://Assets/Skin/Skin" const SMILE_ROOT = "res://Assets/Smile/Smile" #Массивы которые будут хранить наши ассеты var eye_array = [] var skin_array = [] var smile_array = [] #номер эллемента в массиве var eye_number = 0 var skin_number = 0 var smile_number = 0 #элементы дерева @onready var _eye = $CustomMenu/Preview/Body/Eye @onready var _body = $CustomMenu/Preview/Body @onready var _smile = $CustomMenu/Preview/Body/Smile #Вспомогательные функции для получения полных путей ассетов func get_eye_path(index): return EYE_ROOT + str(index) + ".png" func get_skin_path(index): return SKIN_ROOT + str(index) + ".png" func get_smile_path(index): return SMILE_ROOT + str(index) + ".png" #Заполним массив ассетами глаз func get_eye_array(): #Счётчик var i = 1 while true: #Если такая картинка есть, то добавляем в массив if load(get_eye_path(i)) != null: eye_array.append(load(get_eye_path(i))) #Иначе заканчиваем while #У меня все картинки идут по порядку(Eye1,Eye2...) #Можно сделать чуть иначе, но так проще... else: break i+=1 #тоже самое, но для улыбок func get_smile_array(): var i = 1 while true: if load(get_smile_path(i)) != null: smile_array.append(load(get_smile_path(i))) else: break i+=1 #тоже самое, но для кожи func get_skin_array(): var i = 1 while true: if load(get_skin_path(i)) != null: skin_array.append(load(get_skin_path(i))) else: break i+=1 #наполнили все массивы func _ready(): get_eye_array() get_smile_array() get_skin_array() #функция получения новых глаз на превью func get_new_eye(): #Сделали вращалки цикличными if eye_number == eye_array.size(): eye_number = 0 if eye_number == -1: eye_number = eye_array.size() - 1 #Залили новую текстурку _eye.texture = eye_array[eye_number] #тоже самое для кожи func get_new_skin(): if skin_number == skin_array.size(): skin_number = 0 if skin_number == -1: skin_number = skin_array.size() - 1 _body.texture = skin_array[skin_number] #тоже самое для улыбок func get_new_smile(): if smile_number == smile_array.size(): smile_number = 0 if smile_number == -1: smile_number = smile_array.size() - 1 _smile.texture = smile_array[smile_number] #Обработка сигналов для кнопок Skin func _on_skin_next_pressed(): skin_number+=1 get_new_skin() func _on_skin_prew_pressed(): skin_number-=1 get_new_skin() #Обработка сигналов для кнопок Eye func _on_eye_next_pressed(): eye_number+=1 get_new_eye() func _on_eye_prew_pressed(): eye_number-=1 get_new_eye() #Обработка сигналов для кнопок Smile func _on_smile_next_pressed(): smile_number+=1 get_new_smile() func _on_smile_prew_pressed(): smile_number-=1 get_new_smile()
В функции _ready, мы заполняем массивы картинками, и дальше просто заливаем в соответствующий Sprite2D, соответствующую текстурку.
Теперь нам потребуется написать синглтон HeroView и поставить его на автозагрузку и сделать глобальной переменной.
Синглтон HeroView:
extends Node #Объявляем переменные хранящие картинки(не должны быть пустыми, чтобы не было ошибок) var skin = load("res://Assets/Skin/Skin1.png") var eye = load("res://Assets/Eye/eye1.png") var smile = load("res://Assets/Smile/Smile1.png") #Обычные сеттеры и геттеры func set_skin(new_skin): skin = new_skin func set_eye(new_eye): eye = new_eye func set_smile(new_smile): smile = new_smile func get_skin(): return skin func get_eye(): return eye func get_smile(): return smile
Он просто хранить картинки и содержит сеттеры и геттеры для картинок.
Как вы могли в скрипте для сцены редактора нет обработки нажатия на кнопку accept, а вот и она:
#Обработка сигнала для кнопки принять func _on_accept_pressed(): HeroView.set_skin(_body.texture) HeroView.set_eye(_eye.texture) HeroView.set_smile(_smile.texture)
Мы просто обновляем переменные в синглтоне HeroView.
Завершающий штрих
Теперь у нас есть где хранятся картинки, но что с ними делать дальше? Дальше мы просто добавляем нашему персонажу следующую функцию:
func get_new_look(): _body.texture = HeroView.get_skin() _eye.texture = HeroView.get_eye() _smile.texture = HeroView.get_smile()
И вызываем срабатывание этой функции когда потребуется обновить его внешний вид.
Результат
Я ещё добавил, что герой появляется на сцене, при нажатии кнопки Accept, и теперь мы имеет следующее:
Ну вот мы и создали простенький редактор персонажа.
Не большое обращение
Статей давно не было, потому-что я просто не знаю о чём вам было-бы интересно почитать. Поэтому если хотите чтобы статьи выходили чаще, пишите в комментариях о чём написать статью.
ссылка на оригинал статьи https://habr.com/ru/articles/749532/
Добавить комментарий