skype: megainformatic, телеграм: megainformatic, онлайн-чат (megainformatic live chat), форма обратной связи
Онлайн Школа Компьютерных Наук Андрея Синицина
Добро пожаловать в нашу школу ! Давайте вместе откроем путь к новым перспективам !!!
Глава 4 - Визуальная новелла на godot 3.4 часть 2 - поддержка нескольких языков, signals
В данной серии статей мы знакомимся с созданием игр на godot версии 3.4 Если вы совсем не знаете godot, советую начать изучение с этих уроков - Осваиваем движок godot 3.4 Глава 1 - Первые шаги Глава 2 - Основы анимации и создание дистрибутива игры на godot Глава 3 - Визуальная новелла на godot 3.4 В предыдущей главе Глава 3 - Визуальная новелла на godot 3.4 часть 1 - основа будущей игры мы рассмотрели как исправить в игре отображение русскоязычных символов. Но наверняка, Вы захотите, чтобы ваша игра поддерживала несколько языков. В описанном далее примере рассмотрен вопрос использования двух языков в игре: EN - английского и RU - русского. Выбор языка происходит через начальный экран игры при её старте.если кликать картинку она будет последовательно меняться в размерах от 640 до 1002 пиксель.Реализовано это в виде 2-х кнопок Button: ru_lang_button en_lang_button с использованием изображений флагов в качестве параметра Icon у кнопокесли кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.Для каждой кнопки создан обработчик клика по ней.если кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.Обработчик клика button_up() создается аналогично тому, как это было показано в 3 главе - Глава 3 - Визуальная новелла на godot 3.4 часть 1 - основа будущей игры когда мы делали обработчики для клика по кнопкам листания фраз текста вперед и назад. В самом обработчике клика кнопки выбора языка записан такой код -если кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.func _on_ru_lang_button_button_up(): selected_lang = 1;#"ru"; start_main_scene(); #pass # Replace with function body. все что происходит здесь - задание для переменной selected_lang значения равного 1, а также вызов метода start_main_scene для кнопки выбора EN - английского языка - все реализовано аналогично. А обработчик клика имеет такой код - func _on_en_lang_button_button_up(): selected_lang = 2;#"en"; print("lang = en"); start_main_scene(); #pass # Replace with function body. здесь все, как видите, аналогично предыдущему обработчику - для кнопки RU, с той лишь разницей, что selected_lang = 2 что определит для игры - заданный по-умолчанию язык EN. ну и еще я для проверки сделал вызов print("lang = en"); то есть при клике на кнопку EN (с изображением флага великобритании), в консоль редактора godot будет выведено сообжение lang = enесли кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.в консоль выведено: lang = enесли кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.При отладке игры на godot следует иметь в виду, что запуск в режиме debug не дает возможность ставить breakpoint - точки останова в коде, такой возможности нет. Поэтому единственный способ отследить значения переменных во время выполнения - выводить куда-то на экран (как fps) или при помощи команды print - тогда значение выводится в консоль отладки. Что собственно я и сделал - это позволяет точно установить значение любой переменной в текущий момент времени или узнать, что произошло какое-то событие. В godot такие события называются signals подробнее почитать о них можно здесь - Using Signals Для того, чтобы игра могла выводить текстовые фразы диалогов в визуальной новелле я создал 2 файла с таким содержимым: \my_godot_visual_novel\dialogs\dialogs_data\phrases_en.json { "dialog_1" : {"name": "Player", "text": "Summer was in full swing. I was walking alone, and the sun was already sinking."}, "dialog_2" : {"name": "Lorry", "text": "Hey ! Walking into the sunset ?"}, "dialog_3" : {"name": "Player", "text": "Hey ! Didn't expect to meet you here !"}, "dialog_4" : {"name": "Lorry", "text": "Well, sometimes I like to admire the setting sun after a hard day."}, "dialog_5" : {"name": "Player", "text": "Have you had a tough day today ?"}, } \my_godot_visual_novel\dialogs\dialogs_data\phrases_ru.json { "dialog_1" : {"name": "Player", "text": "Лето было в самом разгаре. Я прогуливался в одиночестве, а солнце уже клонилось к закату."}, "dialog_2" : {"name": "Lorry", "text": "Привет ! Гуляешь под закат ?"}, "dialog_3" : {"name": "Player", "text": "Привет ! Не ожидал тебя здесь встретить !"}, "dialog_4" : {"name": "Lorry", "text": "Ну я иногда люблю полюбоваться на заходящее солнце после тяжелого дня."}, "dialog_5" : {"name": "Player", "text": "У тебя был сегодня тяжелый день ?"}, } Чтобы эти файлы могли быть загружены в игру я добавил в скрипт \my_godot_visual_novel_3\my_godot_visual_novel\main_scene.gd такой код: export(String, FILE, "*.json") var dialogue_file_ru export(String, FILE, "*.json") var dialogue_file_en Этот вопрос уже рассматривался в предыдущей главе, Глава 3 - Визуальная новелла на godot 3.4 часть 1 - основа будущей игры когда речь шла о файле \my_godot_visual_novel\dialogs\dialogs_data\phrases.json см. видео #302 визуальная новелла на godot 3.4 часть 1.4 из 3 главы начиная с момента времени: 11:15 Там использовался только 1 файл, только для фраз на 1 языке - RU - русском. Теперь же мы используем 2 файла - и каждый будет отвечать за вывод фраз на выбранном языке. Код, который отвечает за загрузку фраз и их отображение в игре через скрипт \my_godot_visual_novel_3\my_godot_visual_novel\main_scene.gd Примет следующий вид (я привожу только код, отвечающий за загрузку и вывод фраз диалогов в визуальной новелле). export(String, FILE, "*.json") var dialogue_file_ru export(String, FILE, "*.json") var dialogue_file_en var dialogue_file var dialogue_keys = [] var dialogue_name = "" var current = 0 var dialogue_text = "" var dialogue_keys_ru = [] var dialogue_keys_en = [] signal dialogue_started #signal dialogue_finished signal selected_lang_changed; func start_dialogue(): #emit_signal("dialogue_started") current = 0 index_dialogue() #dialogue_text = dialogue_keys[current].text #dialogue_name = dialogue_keys[current].name set_dialogue_text(); #emit_signal("dialogue_started"); func next_dialogue(): var dialogue_keys = dialogue_keys_ru; match $select_lang_scene.selected_lang: 1: dialogue_keys = dialogue_keys_ru; 2: dialogue_keys = dialogue_keys_en; #if current == dialogue_keys.size(): if current > (dialogue_keys.size() - 2): #emit_signal("dialogue_finished") return; current += 1; #dialogue_text = dialogue_keys[current].text; #dialogue_name = dialogue_keys[current].name; set_dialogue_text(); #$scene_1/text_panel/MarginContainer2/MarginContainer/HBoxContainer/VBoxContainer/text_panel_text.text = dialogue_text; $scene_1/text_panel_container/text.text = dialogue_text; func index_dialogue(): dialogue_file = dialogue_file_ru; #match $select_lang_scene.selected_lang: #"ru": #1: # print("ru selected"); # dialogue_file = dialogue_file_ru; #"en": #2: # print("en selected"); # dialogue_file = dialogue_file_en; var dialogue = load_dialogue(dialogue_file) dialogue_keys_ru.clear() for key in dialogue: dialogue_keys_ru.append(dialogue[key]) dialogue_file = dialogue_file_en; dialogue = load_dialogue(dialogue_file) dialogue_keys_en.clear() for key in dialogue: dialogue_keys_en.append(dialogue[key]) func load_dialogue(file_path): var file = File.new() if file.file_exists(file_path): file.open(file_path, file.READ) var dialogue = parse_json(file.get_as_text()) return dialogue func prev_dialogue(): if current < 1: return; current -= 1; set_dialogue_text(); #dialogue_text = dialogue_keys[current].text; #dialogue_name = dialogue_keys[current].name; #$scene_1/text_panel/MarginContainer2/MarginContainer/HBoxContainer/VBoxContainer/text_panel_text.text = dialogue_text; $scene_1/text_panel_container/text.text = dialogue_text; func _ready(): $select_lang_scene.visible = true; $main_scene.visible = false; $scene_1.visible = false; start_dialogue(); $scene_1/text_panel_container/text.text = dialogue_text; func _on_start_button_button_up(): $main_scene.visible = false; $scene_1.visible = true; emit_signal("dialogue_started"); #pass # Replace with function body. func _on_next_button_up(): print("next"); next_dialogue(); #pass # Replace with function body. func _on_prev_button_up(): print("prev"); prev_dialogue(); #pass # Replace with function body. func set_dialogue_text(): #print("sel ", $select_lang_scene.selected_lang, " ", current); #test #print(current); match $select_lang_scene.selected_lang: #"ru": 1: # print("ru selected"); dialogue_text = dialogue_keys_ru[current].text dialogue_name = dialogue_keys_ru[current].name #"en": 2: dialogue_text = dialogue_keys_en[current].text dialogue_name = dialogue_keys_en[current].name #print(dialogue_text); #test #pass #$scene_1/text_panel_container/text.text = dialogue_text; func _on_main_game_node_selected_lang_changed(): #set_dialogue_text(); #$scene_1/text_panel_container/text.text = dialogue_text; prev_dialogue(); #pass # Replace with function body. func _on_main_game_node_dialogue_started(): set_dialogue_text(); $scene_1/text_panel_container/text.text = dialogue_text; Кода много (для вас) и он, возможно пока кажется непонятным. Но по ходу дела мы постепенно разберемся что к чему. строки export(String, FILE, "*.json") var dialogue_file_ru export(String, FILE, "*.json") var dialogue_file_en как уже говорилось выше, позволяют через редактор godot задать файлы, которые будут загружаться игрой для отображения из них текстовых фраз. переменная var dialogue_file требуется для определения текущего загружаемого файла фраз диалогов и используется в методе - func index_dialogue(): dialogue_file = dialogue_file_ru; #задаем файл для загрузки (имя файла) и выполняем его загрузку - var dialogue = load_dialogue(dialogue_file) #в переменную dialogue попадут все данные загруженного файла, то есть весь имеющийся там json код dialogue_keys_ru.clear() #выполняем очистку массива dialogue_keys_ru for key in dialogue: #добавляем значения в массив dialogue_keys_ru.append(dialogue[key]) #по ключу key то есть "dialog_1" : {"name": "Player", "text": "Лето было в самом разгаре. Я прогуливался в одиночестве, а солнце уже клонилось к закату."} массив примет вид dialogue[0]['name'] = "Player" dialogue[0]['text'] = "Лето было в самом разгаре. Я прогуливался в одиночестве, а солнце уже клонилось к закату." и для остальных фраз аналогично убедиться в этом легко - попробуйте после строки dialogue_keys_ru.append(dialogue[key]) добавить строку кода print(dialogue_keys_ru) и запустите игру из редактора godot в консоли вы увидите такой вывод:если кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.[{name:Player, text:Лето было в самом разгаре. Я прогуливался в одиночестве, а солнце уже клонилось к закату.}, {name:Lorry, text:Привет ! Гуляешь под закат ?}, {name:Player, text:Привет ! Не ожидал тебя здесь встретить !}, {name:Lorry, text:Ну я иногда люблю полюбоваться на заходящее солнце после тяжелого дня.}, {name:Player, text:У тебя был сегодня тяжелый день ?}] то есть полный дамп всего содержимого переменной dialogue_keys_ru, в момент, когда она будет полностью загружена данными при вызове из метода index_dialogue() dialogue[0] - это будет 1 фраза текста, хранящая значения в полях name - имя персонажа, который говорит данную фразу и text - сам текст фразы.если кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.имя говорящего мы пока не выводим. Но это легко исправить - над текстовой панелью слева вверху можно будет сделать вывод иконки лица говорящего из объекта Sprite и имя персонажа из объекта Label. Но об этом чуть позже. А пока продолжим рассматривать код, отвечающий за вывод фраз диалогов. для загрузки фраз на английском код полностью идентичен коду загрузки русскоязычных фраз, с тем лишь отличием, что имя файла задается другое - dialogue_file = dialogue_file_en; dialogue = load_dialogue(dialogue_file) dialogue_keys_en.clear() for key in dialogue: dialogue_keys_en.append(dialogue[key]) Проследим как работает код: Когда мы только запустили игру - открывается сцена select_lang_sceneесли кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.если кликать картинку она будет последовательно меняться в размерах от 640 до 1920 пиксель.в скрипте select_lang_scene.gd есть такой код сразу же его прокомментирую var selected_lang = 1; #по-умолчанию задаем 1 - выбранный русский язык для фраз диалогов func _on_ru_lang_button_button_up(): #это обработчик клика по кнопке RU (выбор русского языка - флаг России), если быть точным фиксируется момент #отпускания кнопки selected_lang = 1;#если была нажата кнопка RU - ru_lang_button - задаем 1 start_main_scene(); #и запускаем главную сцену #pass # Replace with function body. func _on_en_lang_button_button_up(): #для обработчика кнопки EN (флаг Великобритании) selected_lang = 2; #задаем 2 - будет английский для фраз print("lang = en"); #эта строка не играет никакой роли - просто выведет в консоль: lang = en - то есть мы будем знать - обработчик кнопки сработал ! start_main_scene(); #аналогично обработчику для RU - запускаем главную сцену #pass # Replace with function body. func start_main_scene(): #запуск главной сцены visible = false; #все что мы тут делаем - скрываем сцену для выбора языка #$main_scene.visible = true; #и поскольку так вызывать главную сцену из данного скрипта мы не сможем get_node("/root/main_game_node/main_scene").visible = true; #то вызываем так. То есть делаем видимой главную сцену main_scene #которая отобразит экран с заставкой и кнопкой Start Как работает кнопка Start вы должны помнить из предыдущей главы - Глава 3 - Визуальная новелла на godot 3.4 часть 1 - основа будущей игры см. видео #302 визуальная новелла на godot 3.4 часть 1.3 начиная с момента 4:50 с момента 10:10 показывается как добавлять для кнопки обработчик клика по ней. main_scene.gd содержит такой код (и я сразу его прокомментирую) func _on_start_button_button_up(): #это обработчик клика по кнопке Start в экране главного меню (экран заставки) $main_scene.visible = false; #скрывает сцену main_scene - то есть сам экран главного меню $scene_1.visible = true; #а сцену 1 делаем видимой emit_signal("dialogue_started"); #и самое главное ! Посылаем сигнал dialogue_started !!! С этого момента я поясню для чего в godot нужны сигналы, хотя, если вы читали официальную документацию, должны уже быть знакомы с ними. Но самое главное - понимание назначения этой возможности. Дело в том, что игровые объекты и скрипты в godot могут взаимодействовать между собой только при помощи общих переменных и передачи друг другу сигналов. Другого способа сообщить одному объекту о том, что хочет сделать другой объект - по сути нет. То есть мы не можем из дочерних объектов вызывать методы родительских объектов, если это вам о чём-нибудь говорит. Вместо этого нужно использовать сигналы - signals. В данном случае мы используем сигнал dialogue_started для того, чтобы запустить метод func _on_main_game_node_dialogue_started(): цель проста если вы этого не сделаете - просто попробуйте закомментировать строчку emit_signal("dialogue_started"); в методе func _on_start_button_button_up(): то есть вот так func _on_start_button_button_up(): $main_scene.visible = false; $scene_1.visible = true; #emit_signal("dialogue_started"); сохраните изменения и попробуйте запустить игру. Вы увидите, что даже если вы в экране выбора языка нажали кнопку EN (с флагом Великобритании), то после перехода в сцену 1 увидите, что 1 фраза в текстовой панели все равно осталась на русском. И только если вы используете сигнал (раскомментируете строку emit_signal("dialogue_started") ), только тогда первая фраза в сцене 1 будет на правильном языке, выбранном в экране выбора языка. Демонстрирую в небольшом видео как это работает Проблема заключается в том, что сцена main_scene инициализируется еще до сцены select_lang_scene, а поэтому выбранный язык не окажет никакого влияния. И только при помощи отправки сигнала мы можем вызвать принудительно метод другого объекта - в данном случае select_lang_scene этого сделать не может и мы для кнопки Start в её обработчик внедряем emit_signal("dialogue_started"); С кодом, который отвечает за листание фраз вперед и назад Вы также должны быть знакомы по предыдущей главе - Глава 3 - Визуальная новелла на godot 3.4 часть 1 - основа будущей игры Но здесь будут изменения связанные с использованием 2-х языковых файлов вместо 1. И вот что именно поменяется: main_scene.gd #как только сцена стартовала будет однократно вызван метод _ready func _ready(): #в нём мы выполняем следующее - $select_lang_scene.visible = true; #отображаем сцену с выбором языка (кнопки с флагами России и Великобритании - Ru и En соответственно) $main_scene.visible = false; #остальные сцены пока скрываем и самое главное $scene_1.visible = false; start_dialogue(); #вызываем метод инициализации текстовых фраз диалогов $scene_1/text_panel_container/text.text = dialogue_text; #в качестве первой отображаемой фразы задаем содержимое переменной dialogue_text рассмотрим что происходит в методе start_dialogue func start_dialogue(): current = 0; #номер текущей фразы выставляем в 0 index_dialogue(); #вызываем данный метод set_dialogue_text(); #затем этот func index_dialogue(): мы уже рассматривали (см. выше) он выполняет загрузку текстовых фраз из 2-х языковых файлов json. вызывая метод load_dialogue для выполнения фактической загрузки этих файлов в память и наконец метод func set_dialogue_text(): #вся его суть в проверке значения переменной select_lang из объекта select_lang_scene #поскольку объект select_lang_scene дочерний для main_game_node с которым связан скрипт main_scene.gd #то поэтому здесь мы легко можем получить доступ к этому объекту и его переменной #что мы и делаем match $select_lang_scene.selected_lang: #ну и если выбран 1 - русский - то задаем для переменных dialogue_ text и name #значения из соответствующей языку переменной 1: dialogue_text = dialogue_keys_ru[current].text #то есть dialogue_text будет хранить текущую фразу на русском dialogue_name = dialogue_keys_ru[current].name #а dialogue_name - имя персонажа из русскоязычного языкового файла #тут все то же самое, только для EN - английского языкового файла 2: dialogue_text = dialogue_keys_en[current].text dialogue_name = dialogue_keys_en[current].name Для листания фраз используются обработчики func _on_next_button_up(): func _on_prev_button_up(): Проект со всеми необходимыми файлами для открытия из редактора godot 3.4.2.stable вы найдете в папке examples\chapter_4\ (ссылка на архив для скачивания скоро будет здесь) далее - Глава 5 - рефакторинг кода, полноэкранный режим, звуки и музыка
оцените статью:
0
0
megainformatic 2006 - 2024 карта сайта