Pull to refresh

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

Level of difficultyMedium
Reading time4 min
Views4.4K

Сегодня на 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, и теперь мы имеет следующее:

Демонстрация результат
Демонстрация результат

Ну вот мы и создали простенький редактор персонажа.

Не большое обращение

Статей давно не было, потому-что я просто не знаю о чём вам было-бы интересно почитать. Поэтому если хотите чтобы статьи выходили чаще, пишите в комментариях о чём написать статью.

Tags:
Hubs:
Total votes 4: ↑4 and ↓0+4
Comments5

Articles