Редактор персонажа

от автора

Сегодня на 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *