[Godot, Разработка игр] Механики для реализации платформера на Godot engine. 3 часть
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Здравствуйте, это уже 3-я часть сборника механик для реализации платформера. На этот раз мы поговорим о жизни, смерти и сохранении с последующей загрузкой. Это будет не совсем урок по реализации платформера, но без данной части программы мы особо и не сможем нормально играть. Только бесконечные уровни а-ля игровые автоматы начала девяностых.
Предыдущие статьи:
Пожалуй начнём в обратном порядке: сначала система сохранения и загрузки, потом о смерти и жизни.
Система сохранения и загрузки
Вообще по умолчанию Godot Engine создаёт папку для данных пользователя где-то в AppData/godot/app_userdata/[название проекта], если не включить галочку в use custom user dir.
Вот как это выглядит в проекте.
После этих действий, проект будет создавать папку в appdata/[название проекта]. Также user:// будет указывать туда. Теперь мы точно знаем куда будут отправляться любые файлы проекта. Теперь стоит создать в проекте папку scripts куда мы будем ложить все скрипты для синглтонов. О создании синглтонов рассказано в документации, так что рассказывать ещё и это будет лишним.
Ладно. Приступим к коду.
# Код снова будет настроен на python, так как он больше всего похож на gdscript, а последний пока не ввели.
# scripts/lvl_mgr.gd допустим в этом файле будет храниться информация для переходов между уровнями
extends Node;
var current_level: int = 0 # Для выбора уровня если у вас полностью линейный платформер с нумерацией уровней.
var current_scene: Node = null # Фактически - указатель на текущую сцену. Для редактора - переменная равная какому-то узлу
func load_level(lvl_id: int = 0) -> void:
var lvl_name = "res://levels/level%s/level%s.tscn" % [lvl_id, lvl_id]
# Создаём переменную чтобы хранить путь к уровню
self.current_level = lvl_id # запоминаем текущий уровень для того, чтобы перезагружаться отсюда
goto_scene(lvl_name) # Вызываем метод перехода к сцене
func goto_scene(path: String) -> void:
call_deferred("_deferred_goto_scene", path)
func _deferred_goto_scene(path: String) -> void:
# Здесь всё и будет происходить.
current_scene.free() # Очищаем переменную
var scene = ResourceLoader.load(path) # Загружаем нужную сцену
current_scene = scene.instance() # Создаём из упакованной сцены узел
get_tree().get_root().add_child(current_scene) # Добавляем к корню дерева сцен наше дерево из сцены
get_tree().set_current_scene(current_scene) # Опционально. Делает совместимым с SceneTree.change_scene() API. Бла-бла-бла. Если коротко, то если это добавить мы сможем держать N деревьев из сцен и переключаться между ними.
Это позволит нам переключать уровни. Далее в коде данный файл будет упоминаться как синглтон LevelManager. На кой нам это нужно? Это позволяет запомнить игре, какой уровень перезапускать после смерти игрока и с чего продолжить, если игрок загружает игру.
Итак, приготовления более-менее закончены, а теперь приступим к самой системе сохранений-загрузок.
# scripts/save_mgr.gd Подключить как синглтон SaveManager
extends Node
var file: File = File.new() # Создаём обработчик файлов
var dir: Directory = Directory.new()
var save_data = { # Данные для сохранения. Чтобы не формировать их каждый раз
"current_level": LevelManager.current_level
}
func _ready():
if !dir.dir_exists("user://saves"):
dir.make_dir("user://saves")
func update_save_data() -> void: # Для обновления данных
self.save_data["current_level"] = LevelManager.current_level
func upload_save_data() -> void: # Для загрузки данных во все фрагменты программы.
LevelManager.current_level = self.save_data["current_level"]
func save_progess(file_name: String) -> void:
file.open("user://" + file_name, File.WRITE)
# Теперь мы как-то должны упаковать данные что сохраняем.
# Пусть это будет словарь.
self.update_save_data() # Собирает по игре данные в save_data.
file.store_string(str(self.save_data)) # Сохраняет данные из save_data в форме строки
file.close()
return
func load_progress(file_name: String) -> void: # Нужно тоже получить имя файла сохранения, если их в игре > 1
file.open("user://" + file_name, File.READ)
# Также открыли файл.
self.save_data = JSON.parse(file.get_as_text()).result # Вытаскивает в self.save_data результат парсинга содержимого файла.
self.upload_save_data() # Вызов этого метода вытаскивает из save_data все данные по правильным местам
file.close()
return
На этом с сохранениями и загрузками покончено. На самом деле это можно улучшать и улучшать, но пока хватает этого.
Смерть
На самом деле это будет переход на экран смерти, где будет кнопка возрождения с текущего уровня, которая реализуется до безобразия просто. Но сначала я должен рассказать о том, что где должно лежать, чтобы мои скрипты сработали.
res://
+-----+- scenes
| +-----+ dead_screen
| | +---- dead_screen.tscn
| | +---- dead_screen.gd
| + ...
+ ...
Теперь откройте нашего персонажа и создайте новый метод dead().
# . . .
func dead() -> void:
LevelManager.goto_scene("res://scenes/dead_screen/dead_screen.tscn")
return
# . . .
В сцене dead_screen.tscn примерно следующее создайте:
И вот скрипт:
extends Control
func _on_exit_pressed(): # Выход в главное меню
LevelManager.goto_scene("res://scenes/main_menu/main_menu.tscn") # Такая сцена должна существовать
func _on_restart_pressed():
LevelManager.load_level(LevelManager.current_level) # Если нажать restart_level - загрузится текущий уровень
Ну а живем мы пока не мертвы…
Заключение
Теперь вы поняли как я насылаю смерть на игрока, если она не должна быть по сюжету. Ну и ещё как работает в моём понимании переключение сцен и система сохранений. На данный момент мне пока нечего рассказать, поэтому я иду думать как создать нейронную сеть, что будет двигаться к точке N. Об этом проекте расскажу больше когда завершу его. Но это совсем другая история.
P. s. И да, отпишитесь в комментариях о том, о чём мне стоит рассказать в следующий раз. Постараюсь подготовить материал достаточно качественно.
===========
Источник:
habr.com
===========
Похожие новости:
- [C++, CGI (графика), Программирование, Работа с 3D-графикой, Разработка игр] Vulkan-tutorial. Урок 1.1 — Вступление (перевод)
- [Unity, Разработка игр] Database using ScriptableObjects with save/load system (перевод)
- [Игры и игровые приставки, Разработка игр] Бесплатная онлайн-конференция «Хочу в геймдев»
- [Разработка игр, Управление персоналом, Карьера в IT-индустрии, Удалённая работа] Один день в офисе будущего
- [Игры и игровые приставки, Разработка игр] Выход ремастера Need for Speed: Hot Pursuit анонсировали 6 ноября
- [Godot, Разработка игр] Механики для реализации платформера на Godot engine. 2 часть
- [Разработка игр, Godot] Механики для реализации платформера на игровом движке GodotEngine
- [C++, Разработка мобильных приложений, Разработка игр] Qt? ImGUI? wxWidgets? Пишем свое
- [Дизайн игр, Игры и игровые приставки, Монетизация игр, Развитие стартапа, Разработка игр] Разбор игры RAID: Shadow Legends (монетизация через поведенческую психологию)
- [Работа с 3D-графикой, Разработка игр, WebGL] Рендеринг каустики воды в реальном времени (перевод)
Теги для поиска: #_godot, #_razrabotka_igr (Разработка игр), #_chisto_programmirovanie (Чисто программирование), #_gdscript, #_godot, #_razrabotka_igr (
Разработка игр
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:18
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Здравствуйте, это уже 3-я часть сборника механик для реализации платформера. На этот раз мы поговорим о жизни, смерти и сохранении с последующей загрузкой. Это будет не совсем урок по реализации платформера, но без данной части программы мы особо и не сможем нормально играть. Только бесконечные уровни а-ля игровые автоматы начала девяностых. Предыдущие статьи: Пожалуй начнём в обратном порядке: сначала система сохранения и загрузки, потом о смерти и жизни. Система сохранения и загрузки Вообще по умолчанию Godot Engine создаёт папку для данных пользователя где-то в AppData/godot/app_userdata/[название проекта], если не включить галочку в use custom user dir. Вот как это выглядит в проекте. После этих действий, проект будет создавать папку в appdata/[название проекта]. Также user:// будет указывать туда. Теперь мы точно знаем куда будут отправляться любые файлы проекта. Теперь стоит создать в проекте папку scripts куда мы будем ложить все скрипты для синглтонов. О создании синглтонов рассказано в документации, так что рассказывать ещё и это будет лишним. Ладно. Приступим к коду. # Код снова будет настроен на python, так как он больше всего похож на gdscript, а последний пока не ввели.
# scripts/lvl_mgr.gd допустим в этом файле будет храниться информация для переходов между уровнями extends Node; var current_level: int = 0 # Для выбора уровня если у вас полностью линейный платформер с нумерацией уровней. var current_scene: Node = null # Фактически - указатель на текущую сцену. Для редактора - переменная равная какому-то узлу func load_level(lvl_id: int = 0) -> void: var lvl_name = "res://levels/level%s/level%s.tscn" % [lvl_id, lvl_id] # Создаём переменную чтобы хранить путь к уровню self.current_level = lvl_id # запоминаем текущий уровень для того, чтобы перезагружаться отсюда goto_scene(lvl_name) # Вызываем метод перехода к сцене func goto_scene(path: String) -> void: call_deferred("_deferred_goto_scene", path) func _deferred_goto_scene(path: String) -> void: # Здесь всё и будет происходить. current_scene.free() # Очищаем переменную var scene = ResourceLoader.load(path) # Загружаем нужную сцену current_scene = scene.instance() # Создаём из упакованной сцены узел get_tree().get_root().add_child(current_scene) # Добавляем к корню дерева сцен наше дерево из сцены get_tree().set_current_scene(current_scene) # Опционально. Делает совместимым с SceneTree.change_scene() API. Бла-бла-бла. Если коротко, то если это добавить мы сможем держать N деревьев из сцен и переключаться между ними. Это позволит нам переключать уровни. Далее в коде данный файл будет упоминаться как синглтон LevelManager. На кой нам это нужно? Это позволяет запомнить игре, какой уровень перезапускать после смерти игрока и с чего продолжить, если игрок загружает игру. Итак, приготовления более-менее закончены, а теперь приступим к самой системе сохранений-загрузок. # scripts/save_mgr.gd Подключить как синглтон SaveManager
extends Node var file: File = File.new() # Создаём обработчик файлов var dir: Directory = Directory.new() var save_data = { # Данные для сохранения. Чтобы не формировать их каждый раз "current_level": LevelManager.current_level } func _ready(): if !dir.dir_exists("user://saves"): dir.make_dir("user://saves") func update_save_data() -> void: # Для обновления данных self.save_data["current_level"] = LevelManager.current_level func upload_save_data() -> void: # Для загрузки данных во все фрагменты программы. LevelManager.current_level = self.save_data["current_level"] func save_progess(file_name: String) -> void: file.open("user://" + file_name, File.WRITE) # Теперь мы как-то должны упаковать данные что сохраняем. # Пусть это будет словарь. self.update_save_data() # Собирает по игре данные в save_data. file.store_string(str(self.save_data)) # Сохраняет данные из save_data в форме строки file.close() return func load_progress(file_name: String) -> void: # Нужно тоже получить имя файла сохранения, если их в игре > 1 file.open("user://" + file_name, File.READ) # Также открыли файл. self.save_data = JSON.parse(file.get_as_text()).result # Вытаскивает в self.save_data результат парсинга содержимого файла. self.upload_save_data() # Вызов этого метода вытаскивает из save_data все данные по правильным местам file.close() return На этом с сохранениями и загрузками покончено. На самом деле это можно улучшать и улучшать, но пока хватает этого. Смерть На самом деле это будет переход на экран смерти, где будет кнопка возрождения с текущего уровня, которая реализуется до безобразия просто. Но сначала я должен рассказать о том, что где должно лежать, чтобы мои скрипты сработали. res://
+-----+- scenes | +-----+ dead_screen | | +---- dead_screen.tscn | | +---- dead_screen.gd | + ... + ... Теперь откройте нашего персонажа и создайте новый метод dead(). # . . .
func dead() -> void: LevelManager.goto_scene("res://scenes/dead_screen/dead_screen.tscn") return # . . . В сцене dead_screen.tscn примерно следующее создайте: И вот скрипт: extends Control
func _on_exit_pressed(): # Выход в главное меню LevelManager.goto_scene("res://scenes/main_menu/main_menu.tscn") # Такая сцена должна существовать func _on_restart_pressed(): LevelManager.load_level(LevelManager.current_level) # Если нажать restart_level - загрузится текущий уровень Ну а живем мы пока не мертвы… Заключение Теперь вы поняли как я насылаю смерть на игрока, если она не должна быть по сюжету. Ну и ещё как работает в моём понимании переключение сцен и система сохранений. На данный момент мне пока нечего рассказать, поэтому я иду думать как создать нейронную сеть, что будет двигаться к точке N. Об этом проекте расскажу больше когда завершу его. Но это совсем другая история. P. s. И да, отпишитесь в комментариях о том, о чём мне стоит рассказать в следующий раз. Постараюсь подготовить материал достаточно качественно. =========== Источник: habr.com =========== Похожие новости:
Разработка игр ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:18
Часовой пояс: UTC + 5