Войти на сайт

Авторизация, ждите ...
×
  • Страница:
  • 1
  • 2

ТЕМА: Godot Engine. Проект "Арканоид"

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128061

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
Рабочая программа «Разработка компьютерных игр на движке Godot Engine»
Аркады. Проект «Arkanoid»

Оглавление разделов
1. Концепция
2. Создание тележки (игрок)
3. Управление тележкой. GDScript
4. Создание сцены уровня. Основная сцена
5. Создание шарика
6. Создание кирпичика
7. Создание уровня
8. Прочные кирпичики
9. Механика траектории шарика
10. Сердечки и игровые очки
11. Добавление звука
12. Система уровней и оповещение

ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


Калейдоскоп узлов и концепций проекта
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


Приветствую вас форумчане, меня зовут Доктор Баг. В реальной жизни я работаю педагогом, провожу дополнительное образования (иными словами провожу кружки). Мое желание открыть кружок по разработки компьютерных игры, к сожалению, RPG Maker программы не подходят для этих целей, так как подобная серия программ заточена под определенный шаблон жанра. Конечно скриптами, плагинами можно изменять сам мейкер, но моя цель научить детей использовать свои знания не нагромождая их лишней информацией.
Мой выбор пал на игровой движок Godot Engine, по нескольким причинам
• Он бесплатный
• У него имеется язык программирования схожий на язык python (нынче я открываю кружок по основам python)
• И у Годота нету проверки лицензии (как у меня было постоянно с Game Maker Studio 2 особенно с моим крутым в кавычках интернета, привет OffSide)
• Он кроссплатформенный
• На нем можно создавать и 3D игры

Мои планы таковы, я желаю развивать GameDev в образовательной сфере. Нынче у меня откроется кружок «Основы программирования Python», а на следующий год планирую открыть еще два кружка «Pixel Art» и «Разработка компьютерных игр на движке Godot». Пока что как таковой рабочей программы по «Разработка компьютерных игр на движке Godot» у меня нету. Но я собираюсь использовать Светлую для заметок, для создание методических рекомендаций, мол напоминания для себя, алгоритм действий что показывать детям. Но чтобы создать подобную программу, придется самому как следует разобраться в годоте. Я нашел способ: я буду изучать различные гайды, от начало до велико, различных авторов. Потому здесь я буду разбирать эти уроки, и открывать новые элементы самого годота. Скажем честно документация Годота желает оставлять лучшего.

Рабочая программа будет разбита на жанры игр.
Первый Цикл уроков посвящен жанру Аркады: Другие разделы: казуальные игры, головоломки, платформеры, и рпг подобные игры (так как разнообразие рпг жанра слишком большое, будет браться только часть элемента), будут разбираться, когда я дойду до них, возможно буду создавать отдельные странички.
Подобную страничку можно использовать и для тех, кто хочет освоить сам годот, только вам еще нужно знать хотя бы основы программирования не обязательно языка годота. Ребята если буду долго не выкладывать информацию, подпинывайте меня, я бывает ленюсь =D
1. Концепция

Прежде чем мы будем создавать игру, мы должны выбрать идею игры. В нашем случаи мы будем создавать игру жанра аркады, под названием «Арканоид». Сама игра «Арканоид» была создана в 1986 году. Наша задача создать копию игры для совершенствования навыка создание компьютерных игр.
Но какой игровой процесс имеет арканоид?
Игрок контролирует небольшую платформу-ракетку, которую можно передвигать горизонтально от одной стенки до другой, подставляя её под шарик, предотвращая его падение вниз. Удар шарика по кирпичу приводит к разрушению кирпича. После того как все кирпичи на данном уровне уничтожены, игрок выигрывает игру. Если же шарик упадет более трех раз мимо ракетки игрок проигрывает. В некоторые кирпичики нужно попадать больше одного раза, в анимации будут отображаться трещинки, говорящие о том, что кирпич разрушиться при дальнейшем контакте с шариком.
Зарисуем как будет выглядеть игровой уровень, без графических излишеств.
Концепция «Арканоид»
Шарик будет ограничиваться не большой локацией состоящий из стен. Внизу будет пропасть для мяча, в случаи если мяч пролетает вниз у игрока забирается попытка (она жизнь игрока) виде сердечки. В случаи потерь всех попыток игрок проигрывает.
Ракеткой можно отбивать мяч. Ракетка будет двигаться с помощью клавиш. Шар будет изначально прикреплен к ракетки игрока, при нажатие на пробел шар отскочит и полетит верх под углом 45 градусов, либо в левую сторону, либо в правую. Попадая в пропасть шар будет снова прикрепляться к ракетки. Ударяясь шарик об ракетку, в зависимости от центра ракетки, шар будет слегка смещаться в сторону, это нужно сделать для того чтобы исключить не проходимость игры.
Кирпичики будут иметь запас прочности. Всего будут три вида прочности, отвечающий сколько раз шарик ударил их, до момента разрушения. Первый слой (самый нижний) кирпичиков будет иметь самый слабый запас прочности, они будут уничтожаться после первого попадания. Следующие три слоя будут иметь большей запас прочности, для их уничтожения понадобиться двойное пробитие. И самый верхний слой, самый прочный имеют три удара для уничтожения. Очки игрока будут заполняться в зависимости от уничтоженных кирпичей. Начиная с первого слоя будут начисляться очки виде 10 единиц, каждый последующий слой будет повышать количество очков за кирпич на 5 единиц. Второй слой цена за кирпич 15 единиц, третий слой – 20 единиц и т. д.
Набрав определенное количество очков игрок получает дополнительные попытки (жизни). Когда кирпичиков не остаётся на поле игрок побеждает.
В нашей игре есть такие игровые элементы как: ракетка игрока, шарик, кирпичики, локация (со стенами), жизни и очки игрока.
Для графики возьмем бесплатный набор (assets) от сюда.
Так должна выглядеть наша игра

В наборе есть заранее заготовленный фон, размером 384х216. Соотношение сторон, которое является 16:9, большинство мониторов имеют такое соотношение сторон (не размеров ширины и высоты).
Вместо ракетки игрока у нас будет тележка (далее буду называть вместо ракетки тележку), которая будет двигаться вперед или назад, у тележке будет анимация.
Также в наборе имеются шарик и разные цветовой палитре кирпичи, даже с анимацией трещины.

Разобьем создание игры на этапы.
  1. Создание тележки (игрок)
  2. Управление тележкой. GDScript
  3. Создание сцены уровня. Основная сцена
  4. Создание шарика
  5. Создание кирпичика
  6. Создание уровня
  7. Прочные кирпичики
  8. Механика наклона шарика при ударение об ракетку
  9. Создание «Попытки» игрока (жизни игрока) и добавление игровых очков
  10. Добавление звука
  11. Добавление системы уровней. Добавление оповещений проигрыша и выигрыша игрока
(Этапы изменялись входе разработке)
Этапы входе разработки могут изменяться, дополняться или даже удаляться, но придерживаться основного плана.
Нам необходимо создать новый проект. Откройте годот выберете место и назовите игру «Arkanoid»

В моем случаи проект располагается в папке «Arkanoid» в папке с проектами.
Скачаем бесплатный набор спрайтов (ассет) с сайта: https://artemouse.itch.io/breakout-pixel-assets
Или скачаем здесь.
Разархивируйте папку и перенесите в проект с игрой. Переименуйте папку в название «Assets»

Убедитесь в файловой системе игры в годоте отображается набор.

Мы будем использовать не все элементы набора.
И так как мы собираемся использовать только 2D-направление в игре, то давайте уберем лишнее элементы в Godot. 3D – проекция нам не нужна и узлы связанные с 3D также не нужны.
Зайдите в меню «Редактор», а далее в «Управление возможностями редактора…»

У нас откроется окно, далее нам надо создать будущий шаблон. Нажмите на кнопку «Создать профиль», и назовите будущий профиль как вам будет удобней, я назвал будущий профиль «2D-Game», символизирующий 2D-направление.

Нажмите создать.
В окне «Настроить выбранный профиль:» найдем чек-бокс «3D Редактор», выключим, теперь у нас на самом вверху программы не будет редактора по 3D.

Спуститесь ниже и отключите ряд узлов «Spatial», тем самым убрав из списка ненужные элементы.

Нажмите «ок». Теперь при поиске нужных нам узлов нам не будут попадаться узлы, связанные с 3D-направлением, как и не будет 3D-редактора в меню.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 10 мес. 3 нед. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, DarchanKaen, poca, Jas6666, Snake Fightin

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128062

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
2. Создание тележки (игрок)

Игра у нас будет двухмерной, потому сразу перейдем в 2D.
В качестве ракетки у нас будет тележка, которая будет двигаться вперед или назад, в зависимости от игрока. Мы используем текущую сцену для создание тележки игрока. Так как нам нужно динамическое тело, а не статическое, ты мы первым узлом выберем «Другой узел» из представленных наших узлов. Выберем узел «KinematicBody2D», как мы помним это кинематическое тело может взаимодействовать с физическими телами.

Переименуйте его в «Player». Прошлый раз для ракетки в проекте «Понг» мы использовали узел спрайта «Sprite», но на этот раз мы воспользуемся другим узлом, который позволит нам анимировать нашу тележку. Давайте прикрепим наш новый узел, начните набирать такие слова «Anim…».
Нам понадобиться узел под названием «AnimatedSprite»

AnimatedSprite похож на узел Sprite, за исключением того, что он содержит несколько текстур в виде кадров анимации. Анимации создаются с использованием ресурса SpriteFrames, который позволяет импортировать файлы изображений (или папку, содержащую указанные файлы), чтобы предоставить кадры анимации для спрайта.
В инспекторе мы создадим новый ресурс под названием «SpriteFrames», что позволит использовать кадры спрайта.

Кликните по созданному «SpriteFrames» еще раз. И вы попадете в спрайт кадры, окошка с настройками будущих кадров анимации.

В окне «Анимации» есть по умолчанию (default) анимация. Здесь так же можно создавать и другие анимации, кликая по значку бумаги с плюсиком. В окне кадры анимации будут отображаться будущие кадры спрайтов. Так же мы можем задавать скорость проигрывание анимации.
Что же давайте добавим спрайт анимации тележки. У нас есть спрайт лист из двух кадров тележки под названием «sp_paddle_strip2.png», расположенный в нашем наборе в папке «paddle». Вот его и возьмем.

Нажмем на кнопку похожий на решетку в «кадре анимации»

Далее мы попадем в корневую папку нашего проекта, переходим в Assets/paddle/ и находим наш файл «sp_paddle_strip2.png». Открываем его.

Далее нам открывается еще одно окошко, здесь мы должны разбить по кадрам наш будущую анимацию.

Если картинка выглядит слишком мелкой, вы можете увеличить её нажимая на плюсик.
Так как кадры у нас идут по горизонтали, и их только два кадра, то в опции по горизонтали выставим двоечку, а по вертикали всего единицу. Тем самым мы разрезали кадры в нужных пропорциях.

Далее нам нужно будет выбрать эти кадры, кликните по ним.

И нажмите кнопку «Добавить кадров: 2»

Наш спрайт выглядит размазано, это потому что мы импортировали без пиксель пресета (особая настройка для загрузки пиксель стилей спрайты). Исправим это.
Перейдите к файловой системе, раскройте набор спрайтов, найдите файл нашей тележки «sp_paddle_strip2.png», кликните по нему один раз и после в дереве сцен перейдите в вкладку «Импорт».

Во вкладке «Пресет» выберете «2D Pixel»

После переимпортируйте спрайт и вас сразу увидите изменения нашей пиксельной тележки

Вернемся к нашей сцене с узлом «AnimatedSprite». В инспекторе есть опция, которая позволит запустить нашу анимацию тележки, кликните по опции «Playing»

И вы увидите анимацию нашей тележки, также заметите как сменяются индексация кадров в опции «Frame». Как вы могли заметить отчет анимации идет не с единицы, а с нуля, а второй кадр — это единица. Вы можете подкорректировать скорость анимации тележки если захотите. Я поставлю скорость 7 кадров в секунду.

Далее давайте сохраним нашу сцену игрока. Нажмите «Сцена» - «Сохранить сцену как»

Создайте в папку «Player» и сохраните сцену там как вам подсказывает Годот.

Как вы можете заметить у узла «Player» справа в дереве сцен есть восклицательный знак в желтом треугольники, а так как мы используем физическое тело узла «KinematicBody2D», то мы должны придать форму столкновений. С предыдущего проекта вспоминаем, за форму столкновения в 2D-направления существует два узла «CollisionShape2D» и «CollisionPolygon2D». Первый узел придает форму из готовых геометрических фигур, второй узле придает форму столкновению по вашему желанию, как вы выстроите.

Но мы воспользуемся готовыми вариантами, прикрепим к нашему игроку форму столкновения узел «CollisionShape2D»

И мы снова видим восклицательный знак только теперь у нашей формы столкновения, Godot подсказывает нам выбрать форму в опции «Shape» в инспекторе. Обычно для формы мы брали прямоугольник или круг, но на этот раз мы возьмем овал, он же «CapsuleShape2D».

Все что теперь нам нужно сделать это настроить наш овал столкновения используя красные точки, или же можно точно настроить в инспекторе, кликнув еще раз по форме, по овалу (откроются параметры формы).

Давайте повернем нашу фигуру на 90 градусов в опции «Transform» - «Rotation Degrees». А радиус будет 8 единицам, высота сделаем 20. И сместим вверх на -1 по оси Y.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 6 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, poca, Jas6666, SirAndriy

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128063

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
3. Управление тележкой. GDScript

В прошлом проекте «Pong» мы использовали готовы ключи для нажатий клавиш, в этом же проекте мы сможем управлять стрелками на клавиатуре, и клавишами «A» и «D» чтобы перемещать нашу тележку влево или вправо.
Зайдем в настройки проекта.


Перейдем к «Списку действий»

Добро пожаловать в обитель все кнопочек, рычажков и сенсоров. Здесь вы можете настроить или создать собственный ключ которому будете привязывать те или иные клавиши, клавиатуры, мыши, джойстика или даже сенсорных нажатий.
Спустите список до ключей под названием «ui_left» и «ui_right». И вы увидите, что здесь уже есть первоначальные настройки и что к ним привязаны клавише стрелки влево и вправо, а также кнопки геймпада. С помощью плюсика мы добавим еще пару клавиш, в «ui_left» мы добавим клавишу «A» (английскую), а в «ui_right» добавим клавишу «D».

Когда вы нажмете плюсик у вас выскочит окошко с выбором устройств которых вы хотите использовать, выберете клавиши.

А после вам нужно будет нажать на соответствующую кнопку в клавиатуре.

И подтвердить действия кнопкой «ок».

Проделайте тоже самое только с ключом «ui_right». У вас должно получиться так:

Здесь высвечиваются наши клавиши.
Вернемся к нашему игроку, теперь пропишем его механизм перемещения под управлением игрока. Как мы помним для этих целей нам понадобиться скрипт, прикрепленный к игроку. Выберете узел «Player» и прикрепите скрипт.
Только давайте сделаем пустой скрипт, в шаблоне скрипта выберете опцию «Empty», это позволит загрузить чистый скрипт без комментариев и заранее прописанной встроенной функции «_ready». Название скрипта пускай останется прежнем, тот вариант что предложил сам Годот.

У нас будет переменная скорости, в которую мы поместим вектор х и у. Вспоминаем вектор2 из прошлого проекта. Объявим переменную «velocity» туда поместим наш вектор «0» он же Vector2.ZERO. Эта переменная будет принимать численное значение и передвигать нашу тележку.

Далее нам понадобиться встроенная функция «_physics_process» которая будет обновлять координаты нашей тележки. Эта функция будет вызываться 60 кадров в секунду, при условии, если мы это пропишем. Снова зайдем в наши настройки проекта, найдите настройки «Debug», далее в параметрах «Settings» ищем параметр «Force Fps» выставите значение 60. Теперь игра у нас будет просчитывать 60 кадров в секунду.

Вернемся к нашему не законченному скрипту.

А вот теперь будем прописывать условия по нажатию клавиш игрока. Модуль Input отвечает за ввод пользователя. А метод «is_action_pressed» отвечает за нажатие кнопки. Прописывая метод Годот будет давать подсказки виде ключей, тем самых ключей которые мы настраивали в настройке проекта – списке действий. Выберете ключ «ui_left» и завершите условие двоеточием.


Заглушка pass нужен для того чтобы годот не ругался при отсутствие кода в условиях или функция и т.д.
Так как мы поместили в переменную скорости «velocity» вектор, мы можем обращаться к Х или У этого вектора. Мы будем двигаться влево при нажатие клавиш стрелки влево или кнопки «А» или при нажатие на клавишу влево на геймпаде. А так как слева направо начинается отсчет координат по оси Х, то мы и будем отнимать минус 500 единиц, дабы двигаться в левую сторону нашу тележку. Давайте сразу пропишем условие и на нажатие правую сторону клавиш, и будем прибавлять на этот раз 500 единиц.

А теперь мы применим наше вычисление перемещения игрока. Используем метод «move_and_slide()» который перемещает тело вдоль вектора. Если тело сталкивается с другим телом, оно будет скользить вдоль другого тела, а не сразу останавливаться. Если другое тело является KinematicBody2D или RigidBody2D, на него также будет влиять движение другого тела. Вы можете использовать это для создания движущихся и вращающихся платформ или для того, чтобы узлы толкали другие узлы. Поместим туда нашу переменную velocity.

Что же, давайте сохраним сцену и запустим её через кнопку F6

Упс… ничего не потеряли? Присмотритесь в левый верхний угол, там наша тележка. Перейдите к сцене игрока нажав кнопку 2D верху

Мы сейчас перетащим нашу конструкцию в середину экрана, временно, для теста. Только чтобы все перетащить правильно мы закрепим нашу анимация и форму столкновения через специальную иконку. Выберете узел игрока и нажмите эту иконку.

А после переместите тележку в центр игрового поля левой кнопкой мыши. Не забываем, что в рабочем пространстве указаны границы экрана

Запустите игру и попробуйте нажать клавиши влево или вправо, или клавиши «А» или «D»

Я нажал влево, и тележка рванула без установочно в левую сторону. Если нажать вправо тележка логично отправить в правую сторону, так же без остановки. Сможете понять почему так происходит? Сравните код в предыдущим проектом по понгу и вы поймете, если будете внимательны.
Сейчас ускорение нашему вектору задают магические числа 500, которые через месяц могут и позабыться, давайте обернем их в переменную и назовём «acceleration» (ускорение), не забудьте объявить переменную.

Так то лучше, избавились от магических чисел.
Мы будем создавать тормозящий момент тележки. Чтобы после тонко настроить нашу движущую машину уби…тележку =)
Создадим еще одну переменную «friction» (Трение), она будет отвечать за трение и сбавлять скорость после отпускание кнопки управления. Дадим ей 200 единиц

Далее впишем такую конструкцию, а после разберем её

Метод относящийся к вектору move_toward будет смещать наш вектор используя второй параметр (в нашем случаи это friction) до значения первого параметра, но не превышая его. После мы перезаписываем значение вектора. Ниже представлен пример с меньшем трением, и как будет действовать если игрок будет двигаться вправо или влево, или если значения вектора по х будет положительным или отрицательным.
Иными словами, метод move_toward создает тормозящий эффект с учетом трения, можно создать тележку которая будет останавливать не сразу, а со скоростью тормозящей дистанции.
И последний момент этой главы, у нашей тележки есть анимация, значит мы можем запускать анимация тогда, когда она движется, а когда скорость ровна нулю анимация будет останавливаться.
Обратимся с узлу анимации, через встроенную функцию _ready

Функция get_node равносильно знаку «$», можно обращаться к узлу и таким образом. Создадим переменную «animation» которая будет хранить в себе узел анимации нашей тележки. Объявим переменную, вызовем встроенную функцию «_ready». Обратимся к узлу анимации «AnimatedSprite»

Далее создадим условие если переменная velocity не будет ровна 0, то мы запускаем анимацию спрайта, иначе нет. Условие поместим после нажатие клавиш

Чтобы разглядеть анимацию давайте сбавим наше ускорение до 200 а трение до 20. Оставим временно пока такие параметры. Запустите игру через F6 и по управляйте тележкой влево или вправо, вы увидите анимацию тележки и эффект тормозящего пути.


В следующий главе мы добавим фоновое изображение, настроим размеры экрана, что позволит лучше разглядеть нашу тележку, установим стены.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 6 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, poca, Jas6666

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128106

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
4. Создание сцены уровня. Основная сцена

Теперь займемся основным уровнем, нашей главной сцены. Мы создали отдельную сцену с игроком, теперь создадим сцену с уровнем. Нажмите на меню «Сцена» и создайте новую сцену.



За основу новой сцены будет выступать узел «Node» поэтому мы и закрепим наш новый узел выбрав другой узел. Переименуйте узел в «Level»

Теперь поговорим о размерах игрового поля. Наша игра будет в пиксель-арт стиле, а пиксель-арт графика используют очень низкое разрешение. Обычно нужно, чтобы оно было кратно 2х, 4х, 8х, или больше, чем оригинальное разрешение. Это означает, что один пиксель оригинального изображения отображается как квадрат 2×2, 4×4 или 8×8 реальных пикселей на экране.
Так как у нас уже есть готовая пиксельная графика, то разрешение игры мы будет затачивать под фоновую картинку, конечно это не всегда правильных подход, но разрешение 384х216 идеально подойдет в соотношение экрана 16:9.
Создадим простой спрайтовый узел, он будет фоном «Sprite» и поместим туда нашу фоновое изображение. Узел спрайта прикрепите к узлу «Level»

Фоновое изображение называет «bg.png» и расположен по пути «Assets/Misc». Раскройте папку в файловой системе и перетащите текстурку в инспектор спрайта в «Texture»

Разместив нашу фоновую текстуру отменим центрирование, и фон сместиться в нижний правый угол. Теперь текстура будет позиционироваться через верхний левый угол. Зайдите в опцию «Offset» и снимите галочку с под опции «Centered».

Только не забываем импортировать фоновую текстуру в пиксель арт, зайдите в импорт и установите соответствующий пресет на пиксель арт
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Теперь давайте сохраним нашу сцену. Создайте папку «Level» и сохраните туда нашу сцену с тем же названием что предлагает Годот.

Так должно выглядеть в файловой системе годота, если вы все сделали правильно.

Наша сцена уровня, будет основной сценой. Нажмите F5 или значок треугольника (Запустить игру)

Выскочит окошка с вопросом сделать сцену главной, согласитесь, сделайте её главной.

Теперь как мы можем наблюдать наш фоновый рисунок слишком маленький для игрового экрана. Сейчас мы это поправим.

Так как размеры нашей картинки равняются 384х216, и остальные спрайты текущего набора заточены под фоновый рисунок, то наша задача поменять игровой экран до размеров 384 пикселей на 216 пикселей.
Для этого зайдем в настройки проекта

Спустимся до опции «Display» - «Window».

И поменяем размер экрана: ширину (Width) 384 пикселей, а высота (Height) 216 пикселей.

Далее спустимся к опции «Stretch» - здесь мы можем настраивать сохранение картинки при растягивание экрана, а режим «2d» как раз и сохраняет целостность картинки при растягивание, выберете эту опцию и запустите игру.

Как мы можем наблюдать окошко вышло довольно маленькое, но если потянуть окно игры за край, то картинка будет растягиваться, плюс наше фоновое изображение занимает весь игровой экран.

Но включать игру с таким маленьким разрешением, а после каждый раз растягивать, выглядит не круто. Это мы тоже можем исправить. Зайдите обратно к настройки проекта, найдите ту же опцию с «Display» - «Window». Поменяем размер игрового экрана, не затрагивая масштаб размер фоновой картинки.
Так как размеры экрана 384х216 для нашего глаза будут маловаты, мы можем увеличить фактический размер игрового окна. Разрешение экрана у нас является 16:9, а это значит, что мы можем придерживаться тех же разрешений, но увеличить ширину и высоту. Введите фразу в браузере в поисковике «разрешение 16:9», и вам тут же попадутся различные размеры экрана в разрешение 16:9. Я решил взять размеры 1280 x 720. Таким образом не будет ломаться пиксель арт, а игровое окно увеличиться. Но куда это вписывать? За это отвечают опции «Test Width» и «Test Height». Впишите туда размеры экрана 1280х720. А после запустите игру.

Если вы все сделали правильно игра существенно увеличиться. И будет смотреться замечательно.
Следующие что нам нужно сделать поместить нашего игрока в сцену уровня.
Выберете узел «Level» и добавьте дочернею сцену игрока «Player».

Не забудьте перетащить нашего игрока в центр экрана, запустите игру

Если вы все сделали правильно у вас будет отображаться тележка, которой вы можете еще и управлять.
Следующая задача установить наши стены, чтобы тележка и будущий шарик не выходили с определённой зоны. Для этой цели мы воспользуемся физическим узлом «StaticBody2D».
Статическое тело для 2D-физики. StaticBody2D — это тело, которое не предназначено для перемещения. Он идеально подходит для реализации объектов в окружающей среде, таких как стены или платформы. Кроме того, для статического тела может быть задана постоянная линейная или угловая скорость, которая будет воздействовать на сталкивающиеся тела так, как если бы оно двигалось (например, конвейерная лента).
Привяжем к узлу уровня узел «StaticBody2D».

Переименуем его в «Wall_left» (стена слева), заодно переименуйте фоновое изображение, он же «Sprite» в «Bakcground» (Фон)

К нашей стене привяжем форму столкновения, которая будет идти вдоль широкой палки. Используем узел «CollisionShape2D»

И как всегда к этому узлу мы будем использовать форму прямоугольника. В опции «Shape», выберем наш прямоугольник, и далее растянем его вдоль левой стены.

Теперь надо сделать и правую стену. Мы можем скопировать наш статический узел горячими клавишами комбинацией ctrl+D а после переименовать в «Wall_right». Попробуйте проделать это самостоятельно, и переместить на правую широкую палку форму столкновение.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Запустите игру и протестити стены на столкновение тележки.

Стоит немного подкорректировать саму тележку, слишком она большая и шустрая. Выберете узел «Player» и в опции «Transform» - «Scale» уменьшим нашего игрока на одну четвертую или на 0.75 единиц по Х и Y. «Scale» - отвечает за масштаб объекта: 1 = 100% масштаб, 0.5 = 50%, а 0.75 = 75% масштаб, или одна четверть.

Так же перейдите на сцену самого игрока, в скрипт, снизьте скорость и трение нашей тележки чтобы создать менее шустрого игрока. Здесь вы можете сами лично подобрать нужную скорость и трение, я же выставлю скорость 70, а трение 2

И вернемся к нашем стенам, снова скопируем стену и разместим выше нашего игрового экрана, прямо на стыке верхушки. Назовем стену «Wall_top». Правда придется удалить форму столкновение и снова привязать узел формы столкновения «CollisionShape2D», так как при изменение предыдущего узла, на него будут реагировать скопированные узлы столкновения других стен.

Будьте внимательны, стены не должны соприкасаться между собой, так как надо будет вычислять с чем столкнется шарик в будущем. А пересекающие стены между собой будут реагировать на столкновение.

Почти доделали, но мы добавим еще один элемент в этой главе, на этот раз мы прикрепим пользовательский интерфейс узел под названием «TextureRect». Он похож на другой пользовательский узел интерфейса «ColorRect», который задаёт цвет, только он отличается тем что мы можем загружать готовый спрайт, картинки или фон. Почему же для фоновой картинки мы не использовали это узел, использовать его можно, но надо помнить, пользовательские интерфейсы крепятся к игровому экрану, и если в игре у вас есть узел камеры («Camera2D») которая будет двигаться вместе с игроком, то и сцена будет смещаться в игровом экране, а узлы пользовательского интерфейса нет. В принципе, можно использовать «TextureRect» для создание фона, вместо узла спрайта «Sprite», но спрайтом было удобно подгонять размер экрана.
Прикрепите к уровню узел «TextureRect»

Переименуйте его в «Score_board» (Табло), этот элемент будет отвечать за отображение игрового счета и попыток, виде сердечек. Как и с узлом спрайта, в узле «TextureRect» нужно перетаскивать картинку в опцию «Texture» в инспекторе.
Мы воспользуемся нашим набором, раскройте в файловой системе Годота папку «Assets», далее папка, отвечающая за наш интерфейс «UI» и найдите файл под названием «sp_hud_long.png», вот этот спрайт мы и перетаскиваем в опции «Texture» в инспектор.

Так как этот узел является пользовательским интерфейсом мы можем позиционировать на игровом экране через опцию макет, чтобы в ручную не перемещать элемент и установить точно по середине. Раскройте опцию «Макет» и там выберете «Внизу посередине». Иконка «Макет» появляется только на узлах пользовательских интерфейсов.

Как мы можем наблюдать, наше табло разместилось ровно по середине, лишь пару пикселей снизу имеются свободных, возможно просчет годота, либо иная причина, вы можете это поправить просто сместив наш элемент чуть вниз. А можете и оставить как есть.

Теперь все что вам осталось переимпортировать этот элемент с пресетом 2D Pixel. Мы уже это делали, так что вы справитесь с этой задачей.
В следующий главе мы начнем создавать шарик и прописывать его отскоки. Здесь же вам остается лишь подправить тележку, чтобы она чуть касалась табло, и можете еще раз под настроить скорость и трение тележки.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 10 мес. 3 нед. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, poca, Jas6666

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128128

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
5. Создание шарика

Создание шарика будет аналогично как в проекте «Pong», мы применим нужные узлы, а также пропишем схожий скрипт. Все же будет некоторое отличие, мы добавим новый функционал. Шарик будет следовать за тележкой, расположенный на верхушки. И после нажатие пробела шарик под углом 45 градусов влево или вправо, отправиться вверх в путешествие, покорять неведомый стенки и будущие кирпичики.

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

Для начало мы создадим новую сцену.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


Это сцена нашего мяча. Так как наш шарик динамичный объект, то мы применим к нему физическое тело, узел «KinematicBody2D». Переименуйте узел в «Ball» (Мяч, шарик). Далее сразу прикрепим к узлу «Ball» два узла, один узел спрайта «Sprite», а другой узел форма столкновения «CollisionShape2D». И да, соблюдайте правильную иерархию узлов, физический узел должен быть в главе остальных узлов в текущий сцене.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Сохраним нашу сцену с мячом. Сохраняя сцену поместите её в папку «Ball», для это понадобиться создать папку. Возможно вы заметили, что Годот предлагает сохранять сцену по названию самого первого узла, а наш первый узел — это узел «Ball». Сохраните сцену как предлагает Годот.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


Теперь займемся спрайтом, в нашем наборе по пути Assets/Misc есть файл под названием «sp_ball.png» - это спрайт будущего шарика, поместите его в спрайт в инспектор в опцию Texture
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

И не забудьте настроить пресет «2D Pixel» в импорте нашего спрайта шарика
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Далее настроим форму столкновения нашего узла «CollisionShape2D». Перейдите к опции «Shape» в инспекторе узла и выберете форму круга «CircleShape2D»
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

После настройте форму уменьшая или увеличивая форму, контролировать этот процесс можно через красную точку, регулирующую радиус круга.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Не забывайте периодически сохранять сцену, чтобы не потерять прогресс.
Теперь займемся кодингом. Выберете узел шарика «Ball» и прикрепите новый скрипт. Далее можете сохранить скрипт там куда предлагает сам Годот.

Мы возьмем схожий код, как и в проекте «Pong», у нас будут переменные скорости «speed» и направления «velocity». Задайте скорость 500, а в направление поместим вектор «Vector2» с нулевым направлением «ZERO». Помним «Vector2» это массив с двумя значениями [0, 0], в нашем случаи они символизирует [x, y] оси. И к вектору можно будет обращаться через Х и Y

Затем мы сгенерируем направление и поместим генерацию в собственную функцию под названием «start». Далее запишите такую конструкцию.

Почему мы решили использовать свою функцию запуска нежели встроенную функцию «_ready»? Функция «_ready» будет запускаться при инициализации самого шарика на экране, а нашу функцию мы будем вызывать только тогда, когда будет нажата клавиши пробела.
Повторим пройдённый материал с предыдущего проекта «Pong».
Функция «randi» генерирует псевдослучайное 32-битное целое число без знака в диапазоне от 0 до 4294967295 (включительно).
Далее знак процента называется оператором по модулю «%», который возвращает остаток после деления левого операнда на правый операнд.
Получается мы делим случайное число на 2, но в значение идет остаток
Пример случайных чисел:
85 692 / 2 = 42 846‬ (без остатка) значит остаток 0
7 778 945 / 2 = 3 889 472,5‬ здесь есть остаток и это 0,5, но так как речь идет о целых числах, то любая дробная часть выше нуля будет считаться за единицу. При простом деление целых чисел (если у вас не значение сплывающей точкой) остаток будет игнорироваться.

Иными словам конструкция [randi() % 2] – будет давать случайные числа от 0 до 1, а они в свою очередь будут индексировать массив и давать значения либо -1 либо 1.

Другими словами, мы будем направлять наш мяч либо влево, либо вправо, случайным образом.
Если вы не поняли, что происходит в этой конструкции просто перечитайте все выше заданное, используйте команду print для выведение значений в консоль что находится внизу в середине. Экспериментируйте!
Ну и последняя строчка кода, 8 строчка. Здесь мы просто указываем куда нужно лететь. Так как нам нужно чтобы шарик взлетел вверх при запуске, мы просто указываем отрицательное значение. Так как координаты оси по Y идут сверху вниз.

Теперь займемся обновлением нашего шарика. Запустим встроенную функцию _physics_process(), в ней мы будем задавать движение по направлению, а после пропишем и отскок нашего мяча. За столкновение возьмем метод move_and_collide(), в котором и будем задавать наше движение. Давайте снова вспомним чем же отличаются методы move_and_collide() от метода move_and_slide():
move_and_slide()move_and_collide()
Эта функция высчитывает столкновение объектов, и она позволяет скользить им по поверхности. Подобную функцию часто используют для игр жанра платформер. И игры в которых нужно просчитывать скольжение.При столкновение объекты этой функции останавливаются, но столкновение возвращает объект с которым произошло столкновение.
Мы будем использовать метод move_and_collide() для фиксирование столкновение с объектом, пропишем туда нашу скорость и направление. А также укажем и дельту. Помним, что дельта очень важна, она гарантирует то что объекты будут двигаться с одинаковой скоростью на разных устройствах с разной частотой процессора. Компенсируя или забирая нужное количество скорости, так как обычно делтьта это число с плавающий запятой.

Но если мы запустим игру, то нечего не произойдет, дело в том, что наше направление мы прописали в функции start. Если мы пропишем функцию start во встроенной функции _ready, то наш скрипт конечно же запуститься, но наша задача запускать шар при условие нажатие на пробел, а еще отслеживать запущен шар или же нет.
Для начало давайте заглянем в «Список действий», мы уже там бывали. Здесь мы настраиваем ключи для клавиш. Снова переходим в настройки нашего проекта, а далее выберем вкладку «Список действий».
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Клавиша пробел на английском звучит «Space» и если вглядеться в разные ключи, то как минимум в двух местах уже используется пробел. Используются они в интерфейсах ключей подтверждения и выбора. Если предположить, что в будущем у нас может быть меню, то при нажатие «Новой игры», может случайно запуститься наш шарик, что не совсем желательно. Для запуска выбора или подтверждения пойдет клавиша «Enter». По крайне мере в ключе «ui_accept» уже есть клавиша «Enter».
Вот что мы сделаем:
1. Удалим клавиши «Space» с других ключей
2. Создадим свой собственный ключ под названием «Fire», символизирующий запуск нашего шарика.
Кликните по иконки «мусорного бака» над каждым ключом где видите клавишу «Space» (он же пробел)

Далее если вы хотите добавить свой собственный ключ, то введите название нового ключа «Fire» в текстовое поле «Действие» и далее нажмите на кнопку добавить.

Поздравляю вы создали свой собственный первый ключ. Теперь заполним его клавишей пробела «Space». Кликаем плюсик, выберем клавишу, нажимаем пробел, жмем «ОК»

Вот что должно получиться

Возвращаемся к нашему скрипту и в функции физического обновления «_physics_process» пишем следующие конструкцию.

Команда ввода нажатии клавиши, под ключом «Fire», с привязкой пробел будет запускать наш мяч. Метод is_action_just_pressed отличается от is_action_pressed тем что запускается лишь раз. Метод is_action_pressed запускается с интервалом при условие нажатие на клавишу. В случаи is_action_just_pressed сработает лишь раз если вы будете держать палец на клавише, он сработает повторно только при условие повторного нажатия.
Перейдите в режим 2D и закрепите на узле «Ball» другие узлы чтобы они не выбирались при нажатие на шарик

Поместите наш шарик в центр экрана и запустите сцену F6. Нажмите на пробел, и наш шарик отправиться в путешествие, выбрав случайное направления.
Но есть еще одна не большая проблемка. Если мы будем нажимать несколько раз пробел, шарик будет периодически менять направление, а нам подобное не нужно. Для проверки запуска мяча будем использовать булевое значение. Давайте объявим переменную run (запустить) и укажем ложь.

И дополним условие ввода клавиши связав их с логическим оператором «И» которое будет проверять на истинность первое условие и второе. Оператор «И» можно вызывать либо словом «and» либо знаками «&&». Ниже пропишем переменную run на истину, дабы не запускать повторно нашу функцию start(). Восклицательный знак впереди переменной run указывает на отрицательность условии, мол если run но ложь, то это истина и условие прошло проверку.

Про тестите игру, прожимая на пробел несколько раз.
Что же мы сделали только часть дела. Дальнейший код будем прописывать, когда загрузим сцену шарика в нашу главную сцену уровня.
Перейдите в сцену уровня и добавьте дочернюю сцену шарика к узлу «Level».

Разместите шар выше тележки и снова запустите игру, на этот раз главную сцену F5. Нажав на пробел наш шарик отправляется в путь и… прилипает к стенки, это потому что мы не прописали отскок, но подобную вещь возможно в будущих проектах вы захотите использовать. Вернемся к скрипту шарика.
И вспомним проект «Pong», точнее повторим.
Функция «move_and_collide()» возвращает объект с которым столкнулся шарик, так что мы используем это. Поместим объект столкновение в переменную «collision_object» чтобы вычислять объекты с которым столкнулся наш шарик.
Используем условие. Поместим переменную «collision_object» в условие, если переменная имеет объект столкновение, то в условие будет отправляться «Истина», если же нет, то «Ложь».
И после разместим конструкцию отскока.

НеМного повтора с предыдущего проекта.
А теперь позвольте объяснить, что здесь происходит, про иллюстрировав происходящие. Здесь вы видите шарик сталкивающийся со стенкой, и здесь мы хотим, чтобы он отскочил от стенки, и для этого нам понадобиться то что называется нормалью. А нормаль — это просто направление в котором направлена плоскость. Сейчас наша стена (она же плоскость или поверхность) направлена вверх, и мы можем использовать нормаль для вычисление отскока шарика в нужном направлении. И чтобы направлять наш шарик в нужном направлении мы и используем метод «bounce» который применяет аргументом объект столкновения, а точнее его нормаль.

Запустите игру, и попытайтесь не упустить шарик преградив его тележкой.
По плану у нас идет привязка шарика к тележке, пока она не запущена, она перемещается вместе с тележкой
В скрипте шарика мы создадим собственную функцию и назовем её «cling» (Цепляться). В неё мы будем прописывать код который будет перемещать шарик вместе с тележкой.

Первое что нам надо определить так это координаты тележки, которые находятся в другой сцене, в сцене уровня. Для этой цели создадим и объявим переменную «player», далее встроенной функции _ready найдем нашу тележку, он же узел «Player».

Снова обратимся предыдущему проекту и вкратце пробежимся по коду.
Метод «get_parent» возвращает родительский узел если есть, а если нет возвращает значение «null» что означает отсутствие узла.
Следующий метод «find_node» ищет нужный узел из родительского узла, по имени узла. В нашем случаи, когда запускается игра скрипт шарика ищет родителя, это наш узел сцены уровня «Level», а после находит нашу тележку, узел по имени «Player» и помещает объект в переменную player.
Далее для того чтобы зацепить шарик к позиции игрока, нам всего лишь понадобиться координаты тележки, а как мы помним к методам инспектора мы можем обращаться через объект. Координаты тележки и шарика находятся в опции «Transform» в инспекторе, наведите курсор на слова «Position» и сам годот подскажет как можно обратиться к методу. Через точку мы можем обратиться и к оси.

Чтобы обратиться непосредственно к позиции шарика нам всего лишь нужно прописать position, так как наш шарик будет прикреплен к тележке, а сама тележка катается по горизонтали, то нам нужен ось Х. Туда мы поместим координаты нашего найденного объекта по той же схеме.
Ну и поместите саму функцию cling между отскоком и запуска шарика.

Запустите игру и попробуйте прокатиться тележкой влево и вправо, и после запустить наш шарик.

Шарик перемещается вместе с тележкой, работает не плохо, пока мы не запустим наш шар, он предательски будет двигаться вертикально игнорируя наш угловые направление, так происходит из-за того, что мы постоянно переписываем координаты оси Х. Все что нам нужно сделать, так это условие, которое будет отслеживать запуск шарика, и у нас уже есть такая переменная. Подправим функцию «cling».

Вот теперь будет запускаться как надо, хоть иногда и противоречиво (шарик летит в одну сторону, а тележка в другую), но пока сойдет и так.
Осталось пару мелочей.
Поместите узел «Ball» выше узла «Score_board» в главной сцене, чтобы шарик пролетал за табло.
Когда шарик улетает за край экрана, он улетает… в бесконечность…
Поэтому мы исправим и эту ситуацию. В проекте «Pong» наш мяч пересекал границы узла «Area2D», но здесь мы поступим иначе. Мы так же воспользуемся узлом, только на этот раз узлом «VisibilityNotifier2D».
VisibilityNotifier2D определяет, когда он виден на экране. Он также уведомляет, когда его ограничивающий прямоугольник входит или выходит из игрового экрана или окна просмотра.
Этот узел вам нужно будет прикрепить в сцену со шариком, к узлу «Ball».

Он чем-то похож на форму столкновения «CollisionShape2D», он тоже имеет форму, только сразу. Как вы заметили форма прямоугольника мяча слишком большая, перенастройте её регулируя красные точки.

Чтобы воспользоваться нашим узлом, нам нужно обратиться к методу «is_on_screen()», который указывает на истинность если объект виден на экране, и ложь если объект за экраном. Когда наш шарик улетает за экран мы указываем переменную run ложь, после разместим на поверхности нашей тележки и снова привяжем его по координатам. Выйдет пару строчек, потому предлагаю создать функцию в которой все это будет указано, назовем её «is_ball_out».

Здесь мы проверяем на истинность выражение: если НЕ (за это отвечает восклицательный знак спереди) виден шарик, точнее его прямоугольник, то устанавливаем переменную run на ложь, устанавливаем на прямую координаты шарика, правда чутка смещаем вверх по оси Y, и устанавливаем направление на ноль.
Далее вызываем нашу функцию между столкновением с отскоком и между функций cling, которая как раз будет устанавливать координаты шарика по оси Х, если он не запущен.

Ну и последнее, иногда при ударе шарика об тележку, тележка смещается, либо вниз, либо вверх. Чтобы это исправить добавьте в код самого игрока, тележки установку по координату Y на постоянном обновляющей основе. Только определите в инспекторе где размещен игрок по оси Y. У меня это число 170. Значит он постоянно будет на этой величине.

На этом наша глава оканчивается, в следующий главе мы займемся кирпичиками.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 6 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128205

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
6. Создание кирпичика

Для создание кирпичей нам понадобиться отдельная сцена, набор нужных нам узлов схож с построением тележки и шарика, только вместо спрайта используется анимированный спрайт. Далее мы сохраним кирпичик, название сцены будет зависеть от назначение на него цвета спрайта. Затем мы создадим уровень в которым заранее будем выставлять кирпичики и пересмотрим название нашего главного узла «Level», мы его переименуем в узел игрового мира «World», так будет более логично. Уровни мы будем загружать в наш игровой мир отдельной сценой. Так же мы с вами поработаем с группами, для определение столкновений нужного кирпичика.
Но для начала давайте заглянем в наш набор спрайтов и глянем где расположены кирпичики и какого цвета и сколько кадров имеют. Мы перейдем непосредственно в корневую папку нашего проекта, можно конечно открыть и найти папку в проводнике, но мы перейдем сразу в нужную папку через сам Годот. В секции файловой системе, кликните правой кнопкой мыши по корневой папке и выберете опцию «Открыть в проводнике».

Перейдем в папку «Assets» (наборы) и выберем папку «brikcs», там расположены наши кирпичики, вместе с системными файлами импорта в Годот.


Здесь я собрал весь набор кирпичей в один рисунок. Он довольно обширен.

Для арканоида я возьму лишь некоторые кирпичики, вы же можете после создать свои понравившиеся кирпичики. Возьмем зеленый, голубой и красный цвет – это будут кирпичи которые будут уничтожаться с первого удара. Затем мы возьмем серебренные (silver) и золотые (gold) кирпичи. Как вы могли заметить серебренный и золотой кирпич имеют несколько кадров, серебряный имеет один дополнительный кадр, а золотой два кадра, отображающие трещины кирпичиков, мы воспользуемся этим в анимации спрайта для отображение состояния целости кирпичей.
Создайте новую сцену, основу кирпичей будет отвечать статический физический узел «StaticBody2D» и после переименуйте его в «Brick_green» (кирпич зеленый). Сразу же мы сохраним сцену, в корневой папке мы создадим общую папку для всех кирпичей «Bricks», сохраните туда нашу сцену так как предлагает Годот «Brick_green.tscn». Мы будем по немного ускоряться, так как вы уже набираетесь нужным набором знаний.

Следующие что нам нужно добавить так это узел анимации спрайта «AnimatedSprite». Мы будем использовать и на простых кирпичиках анимацию спрайтов для правильного вычислений ударов в скрипте. В инспекторе анимации спрайта кликните на «Пусто» возле опции «Frames» и создайте новый «SpriteFrames».

Теперь кликните созданный спрайт кадры «SpriteFrames», чтобы открыть редактор анимации.

После мы кликаем на добавление кадров со спрайта листа, на иконку виде решетки. Затем нам надо найти зеленый кирпичик по пути Assets/bricks/ sp_brick_green.png.


Когда вы выберете зеленый кирпич у вас откроется окно выбора кадров. Сам кирпичик будет очень мелким, увеличьте видимый размер через иконку плюсик в левом углу окна.

У нас здесь идет разбивка на кадры: по горизонтали на 4 кадра и по вертикали 4 кадра. Так как у нас кирпич в единственном кадре, то и разбивку мы установим на единицу.
А теперь кликните по кирпичу, чтобы его выбрать и добавьте кадр.

Да кирпич отображается не в пиксель арт стили, исправим это. В файловой системе найдите кирпичик, можете выделить все кирпичи для обработки, и переимпортируйте их в пресете 2D пиксель арта, будем придерживать одного стиля.

Еще одна, но очень важная мелочь, в инспекторе отожмите опцию «Centered», позиционировать кирпич мы будет по верхнему левому углу, а не по центру, так будет удобно размещать и привязывать к сетки мира.

Вернемся к дереву сцен, следующие нам нужно добавить форму столкновения, думаю вы уже сталкивались с этим узлом, но на всякий случай напомню, узел «CollisionShape2D», вызовите и настройте форму.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Минимальный набор для кирпичика мы сделали, давайте теперь разместим наш кирпичик на главной сцене. Вернитесь к сцене уровня, и да, давайте переименуем наш узел уровня «Level» в название «World» (Мир).

Теперь поместим нашу сцену кирпичика. Помните, как это делается?
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Теперь в нашем уровне «Мира» есть зеленый кирпичик, мы можем в ручную расположить его на игровом поле, в зоне поражения мячика, однако, здесь нам понадобиться привязка к сетки. Да в Годоте мы можем перемещать объекты с привязкой карте.
Если нажать на иконку, которая изображена ниже, то появиться сетка и теперь объекты по карте будут перемещаться с определенным интервалом. Попробуйте переместить зеленый кирпичик (выглядит голубоватым из-за формы столкновения) в центр игрового поля.


Наш кирпичик не совпадает с нашей сеткой по размерам, и даже это мы можем исправить. Но для начала нам нужны размеры самого спрайта кирпича, по ширине и высоте. Для этих целей перейдите в корневую папку проекта и найдите наш зеленый кирпич, в свойствах вы сможете найти размер спрайта.

По крайне мере размер по ширине составляет 19 пикселей, а по высоте 9. Вернемся к Годоту.
Там, где мы прожимали иконку привязки к сетки, рядом расположились три вертикальные точки, кликните по ним, а далее выберете опцию «Настроить привязку…»

У вас откроется окно с настройками привязки, все что вам нужно указать так это шаг сетки: 19 пикселей на 9 пикселей, тем самым задав ширину и высоту сетки.

Ну а теперь, когда мы настроили сетку разместите наш кирпич.

Давайте еще продублируем наш кирпич, пару штучек. Горячие клавише ctrl + D по объекту будет создавать его копию. Сделайте пару штучек раскидайте по карте и запустите игру, проверим еще заодно коллизию (оно же столкновение).


У нас получились самые прочные кирпичики, зеленые кирпичики.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 6 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128208

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
7. Создание уровня

Прежде чем мы будем решать вопрос уничтожение кирпичиков, давайте с группируем будущие кирпичи, заодно увидим одну вещь которая нам пригодиться.
Прикрепите к узлу мира «World» простой двухмерный узел «Node2D» и переименуйте его в уровень «Level», да, да в тот самый уровень который изначально назывался наш главный узел.

Далее по иерархии поместите в этот узел все наши кирпичи.

Зачем он нам нужен? Если глянуть на узлы, написанные синим текстом, то в каждом таком узле есть основа «Node2D», кроме него самого конечно же (у него основа Node). А в инспекторе этого узла не так много параметров, но они важные, с помощью этого узла размещаются координаты объекта, угол объекта, масштаб и даже его Z-уровень (Отвечает за глубину спрайтов, чем больше, тем ближе к экрану). Все это можно настраивать. А теперь все наши кирпичики становиться дочерними элементами узла уровня, а это значит, что перемещая сам уровень, будут подхватываться и наши кирпичики. Плюс мы группируем множество узлов и можем свернуть для удобство узел, чтобы не засорять главную сцену.

Хм… а что если прямо здесь нам эту связку узлов превратить в отдельную сцену, и даже это нам под силу. Все что нам нужно так это выбрать узел уровня «Level» и нажать правой кнопкой мыши по нему, в контекстном меню выбрать опцию «Сохранить ветку как сцену». Давайте сохраним сцену в папку «Level», только есть у нас одна проблема. Мы переименовали нашу главную сцену в «World», но только узел, а не сам файл с главной сценой. Перейдите к файловой системе Годота, найдите сцену уровень в папке «Level» и кликните правой кнопкой мыши по сцене и выберете переименовать в «World».


А теперь, когда мы переименовали нашу сцену, вернитесь к узлу уровня и превратите его в отдельную сцену через опцию «Сохранить ветку как сцену», название соответственно будет «Level».


Теперь нам надо поработать с нашей сценой кирпича. Для определения столкновения с нужным кирпичом нам помогут группы, в проекте «Pong» мы уже работали с ними. В сцене с зеленым кирпичиком, кликните по узлу «Brick_green» и в инспекторе, в узле, выберете группы. Давайте добавим группу с названием «Bricks_group»

Теперь, когда мы добавили группу, иконка группы должна отображаться возле узла «Brick_green»

Идея такова, каждый раз, когда шарик будет ударяться об кирпичик и объект будет принадлежать группе «Bricks_group», то мы будем выполнять у этого объекта функцию, которую мы же и пропишем.
Создайте скрипт на узле «Brick_green». Название скрипта будет у нас звучать как «Brick.gd», а не зеленый кирпич, так нужно для вызова одно и того же скрипта на других кирпичах. А сохраним мы наш скрипт в папке кирпичей «Bricks»

Первое что мы сделаем так это объявим переменную, которая будет отвечать за прочность нашего кирпичика, она же и жизнь. Назовем её «durability» (Прочность), и присвоим значение единицу, так как это кирпич будет уничтожаться при первом прикосновении шарика.

Далее создадим функцию удара «hit», в которой будет уменьшаться на единицу прочность кирпичика, а еще там же пропишем условие при котором будет проверяться прочность кирпичика, и если оно будет равно нулю или того меньше, то мы уничтожаем кирпичик.

Функция queue_free() уничтожает объект.
Затем перейдем к скрипту шарика, можете выбрать в быстром доступе этот скрипт, если конечно он открыт.

Спустимся в скрипте шарика к столкновению и отскоку, и продолжим условие, будьте внимательны с отступами. Запишите такую конструкцию.

В переменную шарика «collision_object» помещаются данные о столкновение. Далее идет условие если объект столкновение принадлежит группе «Bricks_group», (объект помещается в «collider»), то выполняем функции объект удара он же «hit». Метод «is_in_group» проверяет на принадлежность объекта к группе.
Запустите игру и посмотрите, уничтожаются кирпичики или нет.

Практически все объекты, они же узлы, имеют наследственность. Возьмем к примеру статическое тело «StaticBody2D»:
«PhysicsBody2D < CollisionObject2D < Node2D < CanvasItem < Node < Object»
Столько имеет родительских элементов статическое тело. Если глянуть в инспектор, то по такому порядку будут расположены и элементы узла сверху вниз.

В основе объектов расположен узел «Node» как и в остальных узлах. Даже в нашем табло, пользовательского интерфейса так же имеется иерархия узлов:
«Control < CanvasItem < Node < Object»
И так же в инспекторе расположены сами элементы сверху вниз.

Каждый такой набор имеет свои параметры, которые настраивают модульность узлов, делая их более динамичным и в тот же момент не зависимым друг от друга. И проходя по цепочки и документации Годота, мы будем находить свойства и методы присущи только конкретным узлам. Когда мы дойдем до методов и свойств узла «Node» (который и сам наследуется в дальнейшем в Object) то мы как раз и встретим метод проверки групп «is_in_group», а еще найдем, например, свойство «name», которое выдает имя объекта. Если мы запишем: «collision_object.collider.name», то еще и узнаем с кем мы столкнулись.
Справка на сам узел «Node».
У этого узла вы еще можете встретить встроенные функции, они же методы «_ready» или «_physics_process», или метод поиска родительского элемента «get_parent», там расположено много методов которые мы уже использовали.
Но вернемся к разработке.
Теперь ваша задача создать похожем способ еще два вида кирпичика: голубого и красного цвета. Посоветую просто скопировать сцену зеленного кирпича в папку «Bricks» соответственно назвать «Brick_blue» и «Brick_red» ну и поменять их спрайт в анимации спрайта. Задать им один и тот же скрипт «Brick.gd».
Вы можете продублировать сцену прямо файловой системе Годота. Просто найдите сцену и правой кнопкой мыши по ней, выбирайте дублировать, не забудьте поменять название сцены.

Вот что у вас должно получиться

Разместите их на сцене уровня, не на главной сцене мира. Создадим три ряда для не прочных кирпичиков. Максимально у нас будет помещаться 6 штучек. Не забудьте переименовать имена главных узлов кирпичей на красный и голубой

Сохраните сцену уровня, чтобы обновленные данные подтянулись к основной сцене игры, сцены мира. Только сохраняйте правильность иерархии, чтобы случайно при ударе об другой цвет кирпича не удалился целый ряд кирпичей. Если кирпичики слишком смещены вниз, вы можете ухватиться за узел уровня и аккуратно перетащить их вверх все разом.

Можете испробовать игру.
В этом моменте у вас должны работать кирпичики как надо.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 6 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666

Godot Engine. Проект "Арканоид" 1 год 6 мес. назад #128210

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
8. Прочные кирпичики

Перейдем к серебряному кирпичику, так же продублируйте один из готовых сцен кирпичей с названием «Brick_silver». Зайдите в сцену серебряного кирпичика и в узле анимации спрайта удалите текущий кадр и загрузите новый.

Найдите спрайты кирпичиков, и выберете «sp_brick_silver_strip2.png».

Это спрайт имеет два кадра, нам следует разделить наш спрайт на две части.
Увеличьте видимость спрайта через плюсик и разделите спрайт напополам, вертикальный разделитель укажите на 1 единицы, а горизонтальную на 2. И затем выберете эти два спрайта. Ну и нажмите кнопку «Добавить кадры: 2»

Теперь в окне спрайта анимации у нас есть кадры, которые имеют индекс вызова, число при которым мы можем их вызывать. Если мы будем в инспекторе переключать опцию «Frame», то в рабочем пространстве наш кирпичик будет изменяться. А если включим опцию «Playing», то будет проигрываться анимация, но нам этого не нужно делать.

Мы можем привязать анимацию кадров к нашей переменной «Прочности» кирпичика. Чем больше прочность, тем целее выглядит кирпичик. Но есть небольшая не состыковка, переменная «durability» имеет нарастающую величину, чем прочнее кирпич, тем выше это значение, но наша анимация имеет обратный эффект, чем выше индекс кадра, тем менее целее становиться кирпич. Но это легко решаемо, просто переставьте кадры в самой анимации кадров.

Кадры легко переставляются и меняют индекс кадра, а то что кадр начинается с 0 не проблема, просто при вызове анимации мы будем указывать прочность и отнимать единицу, только сделаем проверку чтобы анимация не ушла в минус Давайте это и сделаем. Для начало пропишем установку анимации во встроенную функцию «_ready» и пропишем объявление переменной «animation» (анимация).

В функции удара «hit» будем проверять прочность, и по ней будем сверять и устанавливать кадры.

Но тут есть еще одна проблема, наш скрипт един для всех видов кирпичиков, прочность тоже, подобная проблема легко решаема. Подымитесь к вверху и добавьте слово «export» перед объявлении переменной прочности

Теперь это переменная будет высвечивать в инспекторе, и новое значение будет перезаписывать значение по умолчанию. Подобным способом можно экспортировать не только численные и строковые значения, но и текстуры для спрайтов. Мы не прописывали текстурки, так как у нас идет анимация спрайта и манипуляция с кадрами. Хотя смена экспорта анимации так же возможна.
Вот так будет выглядеть в инспекторе новый элемент отвечающий за прочность кирпичика. Выставите 2 прочности серебренному кирпичу.

Теперь вам остаётся лишь добавить новый кирпич в четвертый ряд сцены уровня и протестировать игру.

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


И добавить в уровень на пятый ряд золотые кирпичики. А чтобы у вас в редакторе отображались кадры не треснутых кирпичей измените в инспекторе анимации спрайтов кадры «Frame» на последний кадр. И сохраните. Скрипт выставит сам нужный кадр.

Так будет выглядеть сцена с уровнем

А так в самой игре. Запустите и про тестируйте, если вы все правильно сделали, то получите кирпичики разной прочности.


На этом все, в следующий главе займемся проработкой тележки. В зависимости куда попадет шарик, туда и полетит.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666

Godot Engine. Проект "Арканоид" 1 год 5 мес. назад #128261

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
9. Механика траектории шарика

Давайте обсудим как наш шарик меняет траекторию после удара об объект. Когда шарик движется по направлению вектора, то при ударе меняет свое направление, шарик отскочив от препятствие летит в противоположную сторону. Подобное действие пойдет стенам и кирпичикам, но не пойдет для тележки. В какой-то момент в игре может сложиться тупиковая ситуация, в которой шарик будет двигаться по одной и той же траектории, не задевая последние кирпичики и не давая возможность игроку сдвинуть тележку, ибо шарик может упасть в игровую пропасть.
Эту проблему можно решить изменив отскок шарика в зависимости от центра удара об тележку. Например, если условно разделить тележку напополам и шарик ударился в правую часть ближе к краю, то направление шарика измениться в правую сторону, но под более острым углом или шарик ударил ближе к центры — значит направление будет более вертикальным. Как это будет выглядеть:

Иными словам чем ближе шарик к центру тележки, тем угол отскока будет стремиться к 90 градусов, а чем ближе к краю тележки, то к 0 градусу или 180 градусов.
Чтобы создать такую траекторию шарика нам понадобиться размер тележки, пару формул и желание понять, как все это работает %D
Но для начала нам нужно определить действительно ли шарик ударился об тележку игрока. Давайте это узнаем, пропишем такое выражение в скрипте шарика.

Если мы запустим игру, то увидим множество объектов, с которым столкнулся наш шарик, среди них будет, и наша тележка под названием «Player»

В переменную «collision__object» помещается данные связанные с «KinematicBody2D». Если обнаружено столкновение, возвращается объект KinematicCollision2D. Этот объект содержит информацию о столкновении, включая сталкивающийся объект, оставшееся движение и положение столкновения. В «collider» помещается объект столкновения, а «name» идет из самых глубин объектов, который имеет все узлы.
С помощью подобного выражения мы и будем вычислять объект столкновения игрока, то есть тележку. Изменим наш код.

Запустите игру, и проверьте консоль, когда шарик будет ударяться об тележку.

А теперь разберем схему по которой будет вычисляться отклонение шарика при отскоке.
Первое нам понадобиться глобальные позиции шарика и тележки, чтобы вычислять относительную позицию по оси Х.
• relative.x (Относительная позиция) = ball.x – player.x
Далее нам надо будет получить процент позиции шарика относительно тележки, иными словами как далеко находится от левого края тележки наш шарик. Для этого нам понадобиться размер самой тележки. Следующая формула будет выдавать диапазон от 0 до 1 (мол от 0% до 100%). Все что нам надо сделать так это поделить относительную позицию на ширину тележки.
• percent (процент) = relative.x / player.width
Следующие нам нужно получить из данной формулы диапазон от -0.5 до 0.5. Зачем нам нужен подобный диапазон? Все просто, при вычислении нам надо точно знать находиться ли шарик левее или правее центра тележки и после наклонять в нужную сторону. Но чтобы точнее управлять подобным диапазоном нам надо будет превратить в диапазон от -1 до 1, это позволит нам направлять шарик по вектору оси Х.

Только придется подправить саму сцену тележки. Для правильно вычисление траектории шарика, нашу тележку надо изменить. Убрать галочку с анимации спрайта «Centered» и поправить форму столкновения. Давайте это и проделаем.

А еще немного подправим в скрипте тележки правильное позиционирование, сейчас у нас стоит 170, но мы исправим на 163 (вы можете вычислить точные координаты на главной сцене, выбрав нужный объект)

Следующие что нам надо указать так это ширину нашей тележки. Если мы откроем папку с нашем набором спрайтиков и найдем файл «sp_paddle_strip2.png», спрайт тележки, то просмотрев сведенья мы обнаружим что наш спрайт равняется по ширине 68 пикселя.

А так как у нас два кадра то делим напополам, и того ширина кадра является 34 пикселя, давайте создадим переменную «width» отвечающее за ширину тележки. Пропишем скрипт игрока, а еще во встроенной функции «_ready» предварительно установим модификатор «Scale», так как в самой игре, в главной сцене мы уменьшали до 0.75 (уменьшили спрайт 1/4) саму тележку.

Прописанный в скрипте метод «scale» как раз вызывает ту саму функции в инспекторе тележки «Scale». Только метод «scale» это массив состоящий из двух значений, значение ширины и высоты, прописывая scale[0] мы вызываем именно ширину.

При вызове print(width) мы будем получать размер 25.5 пикселей (34 пикселей умноженное на 0.75). Так теперь исправим положение шарика, нам надо позиционировать в центре тележки при запуске игры. У нас есть доступ к самой тележки, а значит мы можем воспользоваться его шириной, чтобы вычислять местоположение центра. Откройте скрипт шарика.
В функции «is_ball_out» в скрипте шарика, мы исправим позицию по Y на 3. Это связанно с тем что теперь наш объект позиционируется не с центра, а с верхнего левого угла, потому нам не стоит сильно задирать шарик вверх.
А в функции «cling» мы будем прикреплять шарик к позиции тележки и плюс половинка его ширины, дабы центровать шарик относительно тележки.

В условие столкновение с тележкой мы создадим функцию которая будет возвращать направление вектора по оси Х и назовем эту функцию «get_x_bounce_direction». В этой функции и будут все наши расчеты.

Скорость по вертикали и горизонтали летящего шара с определенной скоростью равна, но если шарик начинает лететь по диагонали, то скорость немного увеличивается, визуально, но метод «normalized» исправляет это. Этот метод возвращает вектор, масштабированный до единицы длины в любом направлении.

Запустите игру и испробуйте шарик, можете даже чутка скорость добавить. Теперь вы можете более прицельно попадать по кирпичикам, когда приловчитесь. В следующий главе мы добавим жизни игроку и будем подсчитывать очки за уничтоженные кирпичи.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666

Godot Engine. Проект "Арканоид" 1 год 5 мес. назад #128347

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
10. Сердечки и игровые очки

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

Так же мы ведем игровые очки, за каждый разбитый кирпичик будут начисляться игровые очки. И пропишем комбинацию ударов, если шарик будет биться только об кирпичики, не задевая стену, дополнительно пару очков.

Начнем с сердечек – нам понадобиться узел анимации спрайта «AnimatedSprite», узел мы будем создавать на главной сцене мира «World». Есть одна тонкость, в нашем арсенале имеется кадровая анимация спрайта сердечек, к сожалению, в ресурсе который мы используем нету отдельных кадров сердечки, можно было бы упростить создание жизней тележки.

Конечно можно было воспользоваться сторонним программном обеспечением, дабы вырезать сердце, но хотел воспользоваться ресурсами в рамках этого проекта не тронутыми.
Что же давайте создадим наш узел анимации и назовем его «Hearts».

Здесь, как и при анимации кирпичей и тележки мы создадим «Новый SpriteFrames».

Теперь кликните по «SpriteFrames», дабы открыть окно с анимацией.
Раскроем местоположение наших сердец по пути Assets/UI файл «sp_heart_strip3.png»

Теперь найдем его в анимации, кликнем на решетку, и найдем тот самый спрайтик с сердцами.


Увеличьте видимость спрайта через плюсик и разбейте кадры по горизонтали на 3 частей, по вертикалей на одну часть. Далее кликните по всем кадрам и нажмите кнопку «Добавить кадров: 3»

Теперь у нас получилось индексация кадров с нуля до двойки

Если прибавить единицу, то как раз у нас будут подсчитываться жизни от одной до трех сердечек. Предлагаю сделать две вещи, первое разместить спрайтик сердец в указанном месте на табло и второе указать прорисовки со третьего кадра «Frame = 2»

Теперь, когда мы прописали визуальную часть, пропишем скрипт.
Перейдем к скрипту шарика, создадим переменную, которая будет отвечать за жизни игрока.

Так как у нас уже есть способ отслеживание шарика за пределами экрана, пропишем вычитание сердец. Но надо быть осторожным, пропишем условие если сердец окажется меньше или равно 0, мы перестанем уменьшать сердца.

Теперь обратимся к узлу анимации, предоставим место под переменную «animation_hearts» найдем её так же, как и узел игрока. Помним, что мы обращаемся к стороннему узлу из сцены шарика «Ball»

Отделим визуальную часть от логической, создадим функцию для проверки и установки кадров анимации сердца. Создам функцию «drawing_hearts». Здесь мы и будем проверять переменную «hearts» и устанавливать нужные кадры анимации.

В случаи если попыток окажется больше ноля, то нам надо менять кадр анимации, отчет кадров идет с 0, потому мы и вычитаем единицу выставляя сердца (3 сердца = 2 индекс анимации, он же третий кадр анимации), но если сердец оказалось равно 0 или и того меньше, то мы просто скрываем анимацию спрайта. Это залог на будущие, мы не удаляем, а скрываем сердца. Поместите функцию в физический процесс для обновление анимации сердечек.


Давайте протестируем нашу игру. Сохраните и запустите игру. Заметим то что в игре почему-то отображаются только два сердца вместо трех.

И как оказалось с этим связан метод узла «VisibilityNotifier2D» под названием «is_on_screen()». При первом запуске этот метод всегда будет равняться ложью, даже если условие выставлены на истину. Это занимает ровно один кадр, для загрузки метода. А так как при первом запуске метод «is_on_screen()» вызывает ложь, Годот непроизвольно выполняет нашу функцию «is_ball_out()», в которой удаляется сердце, выставляются координаты и обнуляется направление шарика.

Мы создадим имитацию предзагрузки метода, ограничив первый кадр всех методов и функций которые мы используем в скрипте шарика. Создадим специально для этих целей переменную «preloaded» которая будет держать булевое значение истины. Идея заключается в том, что при первом обновлении шарика будет переключаться переменная на ложь и завершать функцию, а так как встроенная функция «_physics_process» запускается при каждом новым кадре, мы тем самым и пропускаем первый кадр. Вот как это будет выглядеть.

Это условие сработает лишь раз, больше оно не будет включаться, если только мы не перезапустим игру.
Теперь наша задача удалить шарик после окончание попыток. Метод «queue_free()» уничтожает объект на сцене, воспользуемся этим. Мы допишем условие в котором мы проверяем выход шарика за экран. Там в условиях мы дополним такую конструкцию:

Здесь проверяется переменная «hearts» (сердца), если их стало равно нулю или меньше, то объект (шарик) уничтожается.
Займемся игровыми очками. Мы воспользуемся шрифтом «Pixel Digivolve Cyrillic», который поддерживает символы кириллице. Шрифт был скачан с сайта «Шрифты онлайн» на этом сайте вы можете найти много разных шрифтов. Но будьте аккуратны при использование шрифтов для коммерции, читайте условия их применения.
Ссылка на сам шрифт: Здесь

Выньте шрифт из скаченного архива или же сразу же скачайте шрифт отсюда: ссылка (google-диск).
Название нашего шрифта звучит «pixeldigivolvecyrillic» формата «otf». Создайте в корневой папке проекта новую папку, которая будет хранить наш шрифт, назовите её «Font» и поместите туда скачанный шрифт. Вы можете создавать новую папку непосредственно в самом Godot в файловом системе.

Далее мы воспользуемся простым узлом пользовательского интерфейса «Label», именно здесь мы и будет прописывать игровые очки. Создайте подобный элемент и привяжите к узлу мира «World» и назовите её «Score» разместите её поближе к табло.

Пропишете текст «Игровые очки» в инспекторе узла, в опции «Text». Так как шрифт по умолчанию не поддерживает кириллицу, то текст не будет показан на экране. Подгрузим наш шрифт.
Наш узел «Label» унаследован от родительского узла «Control» прародитель всех узлов пользовательского интерфейса. В его распоряжение имеется занятный параметр в которой мы и будем устанавливать наш будущий шрифт. В параметре «Theme Overrides» мы можем перезаписывать стандартную тему для шрифта. Для начала мы создадим динамичный шрифт в опции «Font»

Далее, когда мы создали динамичный шрифт кликните снова поэтому же шрифту, у вас откроются дополнительные параметры и в параметр «Font Data» (Данные шрифта) мы и поместим наш новый шрифт. Просто перетащите его из файловой системе в этот параметр. Как только вы это сделаете, у нас появиться текст в углу экрана.

В проекте «Pong» мы устанавливали узел «Label» на весь экран, с помощью макета (опция вверху экрана), на этот раз предлагаю вручную перетащить к позиции окна в табло. Размеры нашего экрана фиксированные, иными словами как бы мы не масштабировали наш экран, элементы пользовательского интерфейса останутся на своих местах.

Далее займемся стилем текста. В параметре «settings» мы можем уменьшить размер нашего шрифта до 10.

Если еще уменьшать шрифт, то сам текст будет выглядеть не очень красивым. Но в наше окошечко табло он не помещается, но не беда, мы можем просто изменить размер самого прямоугольника элемента до 80%

Теперь выровняйте сам прямоугольник, он должен совпадать с границами нашего окошка табло по ширине, а вот по высоте оставьте немного пространства, там мы будем размещать наши значение игровых очков. Так же текст должен располагаться по центру, так красивее, но это уже по вашему усмотрению, будет оно располагаться по центру или левому или правому краю.

Так же подправим цвет, в параметре «Color» есть параметр «Font Color» который окрашивает цвет нашего шрифта, имеются и другие параметры окраски текста. Давайте выберем через пипетку темный цвет бордового из самого табло. Вы так же можете подобрать самостоятельно понравившийся вам цвет.

Следующие что нам понадобиться сделать это создать элемент значений игровых очков. Чтобы нам не совершать все этапы настройки нашего узла «Label», мы просто продублируем наш узел «Score» горячими клавишами ctrl + D. Назовите узел «Score_value», и поменяйте текст на число «0» ну и соответственно сместите прямоугольник ниже.

Сохраните проект, и запустите. Посмотрите, как это будет смотреться.

Визуальную часть мы настроили, займемся логикой игровых очков.
Для начало нам понадобиться переменная, которая будет задавать игровые очки каждому кирпичу. Объявим переменную и будем её экспортировать в инспектор, переменную назовем «score». Перейдите к скрипту «Brick.gd».

Сохраните и далее давайте начислять игровые очки каждому категорию кирпичей.
В нашем распоряжение зеленые, голубые, красные, серебряные и золотые кирпичи, начиная снизу-вверх мы будем задавать числа кратные 10 игровым очкам.

Первые кирпичи у нас зеленные. Откройте сцену с зеленными кирпичами и начислите им в инспекторе 10 единиц игровых очков.

Сохраните сцену, и обновленные данные подтянуться в нашу сцену с уровнем. Теперь все зеленные кирпичи имеют 10 единиц очков, удобно. Вам не понадобиться вручную прописывать игровые очки каждому кирпичику в уровне. Теперь проделайте те же действия с другими кирпичами: голубые кирпичи – 20 очков, красные – 30, серебряные 40 ну и золотые очевидно 50 очков. Очки выставляйте открывая сцены нужных кирпичей и обязательно сохраняйте.
Но если вы захотите сделать особый кирпичик в котором могут начисляться больше игровых очков, то вы можете в ручную в сцене уровне задать собственные игровые очки. В этом случаи приоритет будет на стороне выше по уровню сцен.

Уровни могут сменяться, игровые очки должны оставаться, желательно привязать скрипт к главной сцене, здесь мы будет проводить подсчет всех ударов об кирпичик и обновлять текст с игровыми очками. Создадим скрипт и привяжем к узлу «World». При создание Годот спросит где сохранить скрипт, а так как главная сцена находиться в папке «Level», то сохраним туда же.

Здесь мы сразу же объявим переменную в которой будет храниться узел «Score_value» значение игровых очков. А через встроенную функцию «_ready» присвоим переменной сам узел.

Но как связать нам разные сцены, при чем мы должны получить информацию непосредственно от самих кирпичей? Наша сцена с кирпичиками находиться на самом низком уровне: сцена кирпича (любого), далее сцена уровня, а после главная сцена мира. И подобные связки не редкость в игрострое, дабы связать определенные данные нам помогут глобальные переменные.
Как таковой в Godot не существует глобальных переменных, с которыми мы могли бы перекидываться данными между сценами, переходя от одной сцены к другой переменные теряют свою силу. Но мы можем создать синглтон (Singleton).
Одиночка (англ. Singleton) — порождающий шаблон проектирования, гарантирующий, что в однопоточном приложении будет единственный экземпляр некоторого класса, и предоставляющий глобальную точку доступа к этому экземпляру. (информация с википедии)
В нашем случаи будет глобальный скрипт в котором мы и будем хранить данные.
Первое с чего мы начнем, так это создание глобального скрипта «Global».
В скриптах, нажмите на файл, далее на новый скрипт.

Назовите скрипт «Global» символизирующий глобальную позицию для всего проекта (название скрипта не влияет на глобализацию). Сохраним скрипт в корневой папке, не будем создавать под него отдельную папку.

Далее нам понадобиться её добавить в автозагрузки, чтобы скрипт стал глобальным. Перейдите в Проект – Настройки проекта – Автозагрузка.
Кликните на папку неподалеку от параметра «Путь», найдите наш скрипт в корневой папке.

А потом кликните на кнопку «Добавить», чтобы глобализация вступила в силу.

Теперь этот скрипт будет запускаться раньше всех сцен. Перейдите к коду скрипта. Объявим переменную игровые очки «score» и сразу же присвоим число ноль.

Теперь, когда мы создали глобальную переменную мы можем с лёгкостью обратиться к ней, и нам не понадобиться много кода для этого. Перейдите к скрипту мира.

Все что нам понадобиться для обращение к глобальному скрипту так это его название, ну и после обращение к переменной. Мы будем обновлять данные узла «Score_value», но чтобы указать именно текст, целые числа нам надо конвертировать в строки, дабы не получить ошибку (иронично, не текст не хочет дружить с числами), с этим справляется метод str.
Последнее что нужно прописать, так это сами игровые очки. Мы будем начислять игровые очки вовремя уничтожение кирпичиков. Перейдите к скрипту кирпичика «Brick.gd». Нам нужно добавить лишь одну строчку

Как все это будет работать? Так как глобальный скрипт будет запускаться тогда, когда запускается игра, он будет всегда хранить переменную очки. Переписанные экспортом игровые очки кирпичей будут перезаписывать очки по умолчанию (которые у них равняются 1), а после уничтожения они будут суммировать свои очки к глобальным. Ну а в скрипте мира просто показываются сами игровые очки.
Запустите игру и постарайтесь уничтожить все кирпичики, посмотрим сколько вы наберете игровых очков.

Каждый раз, когда игрок будем уничтожать все кирпичики, то будет всегда получаться одни и те же значение игровых очков, давайте добавим бонусный эффект. Бонусные очки будут начисляться в том случаи, когда шарик будет биться только об кирпичики, иными словами если шарик ударил по кирпичику после еще раз ударил по другому кирпичику, то будут начисляться бонусные очки. Но если шарик ударился об стенку или платформу игрока, то бонус обнуляется.
Для подобной механики понадобится три переменные. Первая переменная «bonus_point» будет отвечать за бонусные очки, вторая переменная «combo_hit» проверка того что следующий удар будет по кирпичу, а не по другому объекту, ну и третья переменная счетчик «check», эта переменная будет умножать бонусные очки.
Объявим их и присвоим им значения, работаем со скриптом шарика.

Так как у нас есть проверка на удары по кирпичам, пропишем такую конструкцию.

Переменная «combo_hit» будет активировать счетчик «check» только после второго удара. В свою очередь счетчик будет умножать бонусные очки «bonus_point» и далее суммировать с остальными игровыми очками. В случаи если попадание было не по группе кирпичей, то тогда обнуляем счетчик и переменную проверяющий на второй удар по кирпичам. А так как у нас постоянно происходит вычисление бонусов умножением, то при отсутствие ударов по кирпичам нулевой счетчик будет обнулять бонус умножением.
Глобальные очки = 5 (бонусные очки) * 0 (счетчик) = 0
На этом глава все, в следующий главе мы по работаем с звуковыми эффектами.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 9 мес. 6 дн. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666

Godot Engine. Проект "Арканоид" 1 год 5 мес. назад #128399

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
11. Добавление звука

В этой главе мы с вами займемся звуковым оформлением. Добавим в игру звуки удары мяча и фоновую музыку. Мы снова воспользуемся бесплатными ресурсами с портала itch.io. Звуковые эффекты мы будем генерировать, в дальнейших проектах нам очень может пригодиться подобная программка, кроме фоновой музыки, скачивать будем готовый вариант.
Автор всего проекта дает полный контроль по использованию программы генерации звуковых эффектов, как для коммерческих проектов, так и для простых проектов. Ссылку на программу «GMXR2».
Для фоновой музыки воспользуемся ресурсом автора Tallbeard, мы возьмем музыку под названием «Ludum Dare 38 - Track 9» из альбома «Abstraction - Ludum Dare 38 Loops». Ссылка на сайт в itch.io. Условие использование музыки не в чистом виде, иными словами мы можем использовать музыку в созданных проектах или других видах контента, но не можем транслировать чисто музыку в каком-либо интернет ресурсе (пример: ютуб или другие соц.сети). Вы можете выбрать сами понравившиеся музыку, и использовать её в качестве фоновой музыки.
Ссылка с гугл-диска на GMXR2
Ссылка с гугл-диска на музыку «Ludum Dare 38 - Track 9»
Теперь давайте обсудим где и когда будет запускаться звуковые треки. Фоновая музыку будет запускаться, когда будет запускаться уровень. Это будет сделано для того, чтобы при смене уровня мы могли менять и музыку.
Звуковые эффекты удара шарика об кирпичи, стен и игрока будем прописывать непосредственно на сцене с шариком. Так как там происходит проверка столкновение объектов. Звук проигрыша шарика, когда тот будет улетать за пределы игры.
Что же начнем, сначала нам понадобиться соответствующая папка в которой будут храниться все звуковые файлы. В наборе «Assets» создадим новую папку с названием «Audio».

Теперь запустите программу «GMXR2.exe», установка этой программы не требуется. Перед вами откроется окно с множеством настроек будущего звука.

Как вы могли заметить тут есть много регулирующих настроек, а также кнопки которые имеют не большой шаблон. К примеру кнопка «jump» будут генерировать звук прыжка, а кнопка «shoot» звуки выстрела. Нам понадобиться кнопка «impact» который как раз и будет генерировать звуки удара. Предлагаю нажать несколько раз на кнопку чтобы найти приглушенный удар, удар об стенку игрового мира. Как только вы найдете нужный удар, нажмите кнопку «save» чтобы сохранить файл, назовите файл «hitting_the_wall». Следующий звук удар об тележку игрока «hitting_a_cart», после звук удара об кирпич. Насчет кирпичей, предлагаю вам на каждый тип кирпича сделать отдельный звук, особенно на серебряный и золотой кирпич, выберете что-то более звонкое. Если не смогли найти подходящий звук с кнопки «impact» попробуйте другие кнопки. Все эти звуки сделаны в стиле 8-битных и 16-битных игр, стиль «Chiptune».
Chiptune или chip music – это музыка, написанная в звуковых форматах, где звуки синтезированы в реальном времени компьютером или звуковой картой игровой консоли, а не в программе с сэмплами-заготовками.
Название для кирпичей:
Зеленый кирпич - «hitting_the_green_brick»;
Голубой кирпич - «hitting_the_blue_brick»;
Красный кирпич - «hitting_the_red_brick»;
Серебряный кирпич - «hitting_the_silver_brick»;
Золотой кирпич - «hitting_the_gold_brick»;
А так же звук проигрыша, когда у нас пропадает сердечка «loss». Кнопка «explode» создает звук взрыва, но думаю можно попробовать взять звук оттуда.
Когда будете сохранять файл, не сотрите формат «.wav», иначе файл не сможет запуститься.
Теперь, когда у нас есть готовые файлы, мы столкнёмся с еще одной проблемой. Годот не принимает формат «.wav», но это можно решить, найдя в интернете онлайн конвертер.

Нам понадобиться конвертировать из «wav» в «mp3», введите эту фразу в в браузер в поисковик.

Все что теперь вам понадобиться найти интернет ресурс, который конвертирует в нужный формат.

Теперь поместите туда трек фоновой музыки «Ludum Dare 38 - Track 9», правда так же предварительно конвертируйте в нужный формат, так как сейчас трек в формате «.wav»

Перейдем к установки фоновой музыки. Перейдите к сцене уровня и прикрепите узел «AudioStreamPlayer».

Узел «AudioStreamPlayer» позволяет воспроизводить звуковой трек. Назовем узел «Background_music»

Далее в инспекторе узла поместите наш фоновый трек, нужно будет поместить в параметр «Stream», просто перетащите из файловой системы аудио трек «Ludum Dare 38 - Track 9».

Настроим фоновую музыку: немного сбавим звук, примерно на -5 единиц, выставим галочку в чек-боксе параметра «Autoplay» - что позволит запустить сразу же музыку, когда сцена загрузиться. Запустите игру и насладитесь фоновой музыкой.

Теперь перейдем к сцене с шариком. Там мы добавим несколько узлов «AudioStreamPlayer». Но чтобы сгруппировать узлы мы добавим простой узел «Node», переименуйте его в «Sounds»

Теперь добавьте в узел «Sounds» звуковые узлы «AudioStreamPlayer».

Нам понадобятся 8 штук звуковых узлов, переименуйте их в название звуковых файлов, только пишем заглавную букву. Для удобства вы можете дублировать узлы горячими клавишами ctrl + D, а для того чтобы не переписывать в ручную узлы, вы можете копировать название аудио треков прямо из файловой системы, выбирая файл, нажимая F2. Далее вам понадобиться добавить в эти узлы соответствующие звуковые треки, в параметр «Steam»
Вот что должно получиться

Для проверки звука вы можете кликнуть на параметр «Playing», звук начнет циклически повторяться, что нам тоже не совсем подходит. Когда мы перетаскивали звуковые треки мы невольно устанавливали параметры по умолчанию. Перейдите к файловой системе, выделите все аудио файлы с помощью кнопки «Shift» (на клавиатуре), кроме фоновой музыки и перейдите в раздел импорта в древе сцен. Снимите галочку с параметра «Loop» (цикл), и звуковые эффекты перестанут циклически повторяться. Только не забудьте нажать на кнопку «Переимпортировать»

Теперь перейдем к скрипту шарика. Объявим 8 переменных, название их будут соответствовать названием звуковых эффектов. Первую букву переменной сделаем строчной.

Теперь назначим узлы со звуком переменным. Метод «get_node» позволяет получить узел который размещен по иерархии ниже. А чтобы не писать весь текст пути узлов, вы можете перетаскивать сами узлы прямо в скрипт.

Первое что мы пропишем, удар по тележке. Чтобы воспроизвести звуковой эффект в скрипте, достаточно прописать метод «play()». Так как у нас есть место отслеживание столкновении шарика об тележку, то и пропишем там звуковой эффект.

В игре у нас не так много объектов с которым может столкнуться наш шарик. Для кирпичей мы пропишем уникальные имена, но позже. В месте где сталкивается шарик с кирпичами есть и обратная сторона, вот за эту сторону и отвечает наша стена. Пропишем звук и там.

Пропишем сразу и потери жизни

Теперь обсудим как мы будем отслеживать в какой кирпич попал шарик. Думаю, можно прописать уникальное имя кирпича, это будет переменная и она будет экспортируемая. Таким образом мы сможем задавать уникальное имя категорию кирпичей и по имени отслеживать в какой конкретно попали кирпич.
Откройте скрипт кирпича. Создайте экспортируемою переменную «unique» (уникальный).

Теперь пропишем в каждой сцене кирпича, всего у нас их пять, уникальные имена: «Green», «Blue», «Red», «Silver», «Gold».

Теперь, когда мы прописали имена у сцен кирпичей, вернемся к скрипту шарика.
Мы знаем место где происходит удары по кирпичам, и мы туда впишем созданную нами функцию «brick_sound», которая будет искать и подставлять нужный звук.
Для начала напишем эту функцию, так же будет аргумент который и будет отслеживать какой кирпич нам попался.

Аргумент «brick» - это наш кирпич, а так как мы прописали уникальные имена, мы можем отслеживать и подставлять нужный звук удара.
Осталось последнее, поместить функцию в нужное место и поместить туда объект столкновения.

Если вы сохраните скрипт и запустите сцену, то каждый кирпич будет выдавать свой собственный звук. Ударяясь об стены и тележки свое звучание. Ну и потеря жизни так же, имеет свой звук.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666, SirAndriy

Godot Engine. Проект "Арканоид" 1 год 4 мес. назад #128447

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
12. Система уровней и оповещение

В нашем распоряжение имеется узел с уровнем, но мы хотим улучшить игру и не останавливаться лишь на одном уровне. Как мы это сделаем? Первое мы будем загружать уровни программно, а не напрямую подгружая сцену. Далее в главном мире мы будем создавать массив состоящий из названий уровней (Сцен). Благодаря такому массиву мы сможем отслеживать, когда закончиться последний уровень.
Уровень заканчивается, когда последний кирпичик уничтожается. Чтобы проверить, когда уничтожился последний кирпич, нам понадобиться общее количество кирпичей на экране. Метод «get_child_count()» позволяет определить у узла количество дочерних элементов. Благодаря этому методу мы сможем отслеживать последний кирпич.
И последнее что нам останется сделать, так это прописать оповещение, когда игрок выигрывает уровень, игру или же проигрывает. И создать возможность перезапуска игры.
Откройте проект годота «арканоид» и удалите сцену уровня.

Перейдите к скрипту мира. Теперь наша задача загрузить сцену программно.

Мы создаем переменную «scene», с помощью функции «load» мы загружаем сцену, а метод «instance()» создает экземпляр сцены. Что значит экземпляр сцены?
Экземпляр сцены – это дубликат, обладающий такими же свойствами, как и оригинал. Вы можете делать бесконечное количество экземпляров сцен и изменять их как угодно, оригинал сцены не будет изменяться. Подобный термин идет прямиком из ООП (Объектно-ориентированное программирование)
Загрузим сцену. Мы должны добавить её в древо сцен, с этим легко справляется функция «add_child» загружая сцену в древо сцен как дочерний элемент.
Если же нам понадобиться удалить сцену, мы воспользуемся обратной функцией «remove_child(scene)»
Сцену можно загружать по-разному: функция «load» подгружает сцену, когда Годот доходит до строчки кода, функция «preload» предварительно загружает сцену, когда просчитывает компилятор сценарий, а не до момент считывание кода в годоте.
Нам понадобятся массив для хранение название уровней «levels», в нашем случаи сцен. Далее нам понадобиться переменная, которая будет пробегаться по индексу массива, а еще будет отвечать за уровень игры «level_number».
И желательно все это обработать отдельной функцией, которая будет запускаться перед запуском новых уровней и будет контролировать какую сцену запускать «level_manager». Изменим и дополним скрипт.

В массив «levels» мы поместили название нашей сцены уровня, так как уровней будет больше одного мы будем дополнять список массива. В функции «level_manager» мы воспользовались локальной переменной «name_level» которая видна лишь в пределах функции и предназначена для названия уровня.
Еще нам понадобиться переменная «last_level» (последний уровень), которая будет хранить максимальное количество уровней. Она нужна для отслеживание победы игрока над всеми уровнями, а также предотвращении ошибки выхода за пределы диапазона индекса массива.
Чтобы определить максимальное количество элементов воспользуемся методам массива «size»

Следующая переменная так же важна, переменная под названием «level_passed» (уровень пройден). Это булевое переменная, она будет отвечать за прохождения игроком уровня. Если уровень пройдет, выставляет истина, и переменная «level_number» увеличивается, при условии, что не превышен максимальный уровень.

Второе условие с «elif» позволяет проверить игрока на победу над всеми уровнями.
Теперь давайте перейдем к сцене с уровнем. Чтобы уровень был успешно пройден, на игровом поле не должно остаться кирпичиков. Для проверки этого нам понадобиться число, максимальное количество кирпичей на игровом поле. Но как это сделать? Мы воспользуемся методом «get_child_count()» который позволяет показать количество дочерних элементов. Но у нас же там есть фоновая музыка которая так же может попасть под прицел, а что если мы захотим поместить новые игровые элементы? Эта проблема решаема, нам всего то и нужно добавить новый узел, думаю узел «Node2D» сойдет. Добавьте узел и переименуйте его в кирпичи «Bricks» а далее по иерархии поместите все кирпичики в этот узел.

Все теперь нам буде проще отслеживать разрушаемые объекты. И такая иерархия должна соблюдаться в каждом уровне. Создайте скрипт уровня и сохраните там же где и уровни.

Этот скрипт будет привязан во всех уровнях. Создайте переменную «bricks» и после найдите нужный узел через метод «get_node». Далее можем воспользоваться методом «get_child_count()» он определяет количество дочерних узлов.

Запустите программу, и вы увидите в консоли число 30 (или любое число сколько вы там поместили кирпичей).

Теперь желательно число передать глобальной переменной. Чтобы мы могли с лёгкостью отслеживать её в другой области проекта.
Мы создадим глобальную переменную «number_of_bricks» (количество кирпичей). Откройте скрипт «Global.gd», дополните ряды переменных.

Теперь вернитесь обратно с уровню и передайте число.

Только что мы зафиксировали что в уровне имеются определенное количество кирпичей, теперь мы можем вычитать каждый уничтоженный кирпичик с глобальной переменной. Перейдем к скрипту кирпича «Brick.gd», в месте где уничтожается кирпичик вычтем один кирпичик.

А в скрипте мира мы будем следить за количеством кирпичей, если их станет ноль или и того меньше, то уровень пройден. Чуть не забыли выключать переключатель если наступает следующий уровень.

Если вы все правильно сделали, то запустив игру и разбив все кирпичики в консоли будет отображаться надпись «Победа».
Далее немного изменим функцию цепляющий шарик к тележки в скрипте шарика.

Теперь, шарик будет цепляться и по высоте, когда переменная запуска (run) станет ложью.
Снова вернемся к скрипту мира, теперь нам стоит добавить шарик. Когда уровни будут заканчиваться мы цепляем шарик к тележки, и все что нам нужно будет сделать поменять переменную «run» на ложь. Сначала выделим место под шарик, загрузим, а после применим переменную.

Теперь если вы запустите игру и собьёте все кирпичики, то шарик зацепиться за тележку и не отцепиться, даже если мы будем нажимать пробел. Это связано с тем что сейчас у нас всего лишь один уровень и когда он заканчивается происходит вечное применение переменной «run» ложью. Испытайте это, запустите игру и сбейте все кирпичики.
Что же пара добавлять новые уровни!!!
Чтобы не создавать уровень с нуля, мы просто будем дублировать наш уровень. Перейдите к файловой системе раскройте папку уровни и правой кнопкой мыши кликните по сцене уровня «Level.tscn», выберете дублировать. Назовите уровень два «Level2»


Последующие уровни вы можете называть, как угодно. Название уровней вы будете помещать в массив, который будет запускать уровни по очереди пока не закончиться весь его список.
Давайте добавим новый уровень в список, скрипта мира.

Теперь раскройте сцену второго уровня кликнув на файл сцены два раза в файловой системе. Преобразите уровень по-своему. Да изначально я поменял свой первый уровень для теста, оставив там всего пять кирпичей разного рода. На втором уровне я так же добавлю немного кирпичей.

Следующие что нам нужно сделать вызвать функцию менеджер уровней, именно здесь мы прорабатывали смену уровней. Поместим функцию лишь при смене выигрыше уровня, но не всей игре.

В этом месте проверяется условие, если уровень пройден, но текущий уровень не является последним, значит включаем следующий уровень. Переменная «level_number» увеличивается, функция менеджера уровня ухватывает переменную и подгружает новый уровень как дочерний. Только есть одна проблемка, мы не удаляем старый уровень, это надо исправить перед запуском нового уровня.
Метод «remove_child» удаляет дочерний элемент сцены, в нашем случаи именно уровень. Этот метод должен вызываться перед функции менеджера уровней.

Теперь, когда вы пройдете второй уровень, ваш шарик зацепиться за тележку и тут же запуститься второй уровень.

Мгновенный запуск следующего уровня выглядит так себе, давайте добавим задержку перед запуском следующего уровня. В эту задержку можно будет добавить надпись победы и запуска следующего уровня.
Прикрепим узел таймера к нашей главной сцене.

Переименуем его в названием «Time_next_level_start», время следующего запуска уровня.
Узел отвечающий за время. Когда таймер запускается и заканчивается узел испускает сигнал, этот сигнал мы и будем ловить. Давайте для начало мы установим 5 секунд в инспекторе таймера.

Следующие что нам понадобиться вызвать таймер и запустить его.

Методы «remove_child» и «level_manager» не должны запускаться после запуска таймера, они должны запускаться только после окончание время счета таймера. Но как это отследить?
Все просто, мы обратимся к сигналу самого таймера. Узел испускает определенный сигнал, когда приходит время завершение подсчёта. Этот сигнал мы и используем. Перейдите в раздел сигналов таймера.

Как мы могли заметить у узла таймера есть немного разных сигналов наследуемые от родительских элементов, но нам понадобиться сигнал «timeout()». Кликните по нему два раза. И присоедините сигнал к главному узлу мира «World», название функции оставим такой какой предложил сам годот.

Небольшой значок с зеленой стрелкой указывает функцию на привязанность к сигналу. Поместите в эту функцию наши методы.

Давайте запустим игру, и протестируем. Когда вы пройдете уровень, наступит время таймера, после 5 секунд загрузиться следующий уровень. Создайте третьи уровень и протестируйте снова игру.
Игра будет не корректно работать, и на, то есть несколько причин. Первое в инспекторе таймера мы должны активировать параметр «One Shot», который запускает таймер лишь один раз, после не повторяет циклически сам таймер. У нас кирпичи запускались на следующих уровнях

Следующий хитрый прием, (хотя можно назвать это костылью) мы применим в условиях запуска переменной «level_passed». Пока работает таймер, здесь проходит условие, что ломает игру. Для того чтобы обойти систему, мы просто добавим один кирпичик что условие повторно не запускалось.

Спросите зачем добавлять один кирпичик? Глобальная переменная перезаписывается каждый раз, когда загружается уровень. Но не обновляется при игровом процессе, даже когда заканчиваются все кирпичики, информация не обновляется, этим мы и воспользовались.
Но допустим мы захотели добавить дополнительные кирпичи, нам это не помешает, добавляя кирпичи, мы должны оповещать глобальную переменную, главное, чтобы это происходило до окончание всех кирпичиков.
Теперь, когда мы приготовили почву для надписи разного рода текста, пора поговорить о оповещении.
Оповещении:
1. Надпись, когда игрок проходит уровень. В течении пару секунд будет весить надпись о победе уровня.
2. Надпись, когда игрок проходит всю игру. Появиться надпись которая будет находиться на экране до конца игры
3. Надпись запуска нового уровня. В течении пару секунд будет показана надпись. Блокируя запуск шарика.
4. Надпись проигрыша. Будет расположена на экране пока игрок не нажмет на пробел. Будет возможность рестарта игры, сбросом всего прогресса
Создадим дубликат узла «Label» из «Score», комбинацией ctrl + D. Назовите узел «Inscription», поменяйте сам текст на надпись, так же смените цвет на белый, чтобы не сливался с фоном. Ну и поместите в центр экрана.

Следующие что мы пропишем, в скрипте мира, объявим переменную надписи, сбросим текст на пустую строку.

После победы над уровнем, отобразим текст победы «Уровень пройден!», а по завершение таймера сбросим текст.

Следующая ситуация, когда игрок проходит всю игру, текст «Вы победили!»

Протестируйте игру

Следующее надпись нового уровня и блокировка запуска игрока. Для этих целей нам понадобиться таймер. Блокировка будет после помещения шарика в тележку. Прикрепите узел «Timer» и назовите его «Timer_new_level».

Таймер будет запущен на 3 секунд. Установите в параметре таймера «Wait Time» на 3 секунды и поставьте галочку в чек боксе «One Shot», чтобы таймер не запускался циклически снова и снова.

В течении этого таймера будет отображаться надпись. Снова закрепим через сигнал таймер к главной сцене мира.

Добавим надпись «Уровень » и переменную «level_number» (уровень игры), а когда таймер закончиться сбросим текст. Ну и конечно мы добавим новый таймер в скрипт (узел «Time_new_level»). Команда «str» превратит число в строку, так как отображать уровень будем именно в тексте.

Для блокирование игрока мы воспользуемся глобальным переменным. Перейдите в скрипт глобальной переменной и создайте булевое выражение «stop_start» и присвойте ему истина. Если нам нужно остановить шарик эта переменная должна быть истинной.

Мы будем завершать функцию «_physics_process» благодаря этой переменной, в определенном месте, тем самым блокируя кнопку запуска шарика. Поместите строчку чуть выше запуска шарика, в функцию «_physics_process» в скрипте шарика «Ball.gd»

Ну и теперь будем включать и выключать эту глобальную переменную в скрипте мира. Помним, если истина, значит выключить запуск, если ложь, включить.

Теперь последнее, нам нужно прописать надпись, когда игрок проигрывает, и дать игроку возможность перезапустить игру.
Прежде чем мы пропишем надпись проигрыша, мы изменим реакцию шарика после окончание сердечек. Первое, мы не будем уничтожать шарик, второе мы будем его скрывать, чтобы потом мы могли его показать на сцене. И мы изменим условие, вместо иначе «else», мы поместим проверку на количество сердец равное нулю или и того меньше. Все это прописываем в скрипте шарика.

Вернемся к скрипту мира, допишем такую конструкцию.

Мы будем проверять сердца у шарика и выдавать надпись проигрыша.
Теперь все надписи работают как надо. Займемся перезапуском игры, в случаи если мы проиграем все попытки (сердечки)
Нам понадобиться переменная «restart» булевого назначения. В случаи если переменная будет истина, мы запускаем возможность нажать кнопку и перезапустить все, иначе такой возможности не будет. За перезапуск будет отвечать пробел.

Включим переменную, когда заканчиваются сердечки. Поместим в функцию «_process» скрипта мира

Далее внесем систему ввода клавиша пробела, ключ у нас уже иметься.

Этот механизм будет срабатывать только когда переменная перезапуска будет активна, далее проверка на нажатие пробела. Временно пока заглушку «pass» поставили дабы не вызывать ошибку. Нам понадобиться отдельная функция в которой мы будем все сбрасывать.

Здесь идет установка уровня, возобновление количество сердец (попыток), включение отображение шарика, сбрасывание перезапуска, удаление текущий сцены и загрузка новой сцены, а так как уровень первый, грузиться будет первый уровень. Теперь установим функцию в нужном месте и многое другое.

Следующее что хотелось исправить так это полет шарика, особенно когда шарик внезапно начинает лететь чуть ли не горизонтально. Мы создадим функцию которая будет постепенно изменять угол полета шарика. Назовем функцию «ball_angle_adjustment»

Замысел функции прост, если шарик будет иметь наклон по высоте меньше 20 градусов как в положительную сторону или отрицательную, то мы добавляем градусы каждый шаг выравнивая шарик и тем самым немного ускоряя его путь. Поместите функцию в функцию «_physics_process». И добавьте в качестве аргумента направление шарика по Y оси.

На этом наш проект «Arkanoid» считаю законченным. Да мы не добавили много вещей, таких как пауза, или особые кирпичики которые дают те или иные бонусы, или анимацию текста, и на, то есть причины. Все эти элементы мы будем изучать в будущих проектах. Следующие занятие будет бонусным, мы будем изучать: главное меню и меню пауза. Приятно было с вами работать, а теперь вы можете загрузить игру и испробовать её сами. Здесь.
Да новых встреч, с вами был Доктор Баг. :laugh:
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 4 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, Jas6666, Erckert

Godot Engine. Проект "Арканоид" 10 мес. 4 нед. назад #129339

  • Snake Fightin
  • Snake Fightin аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 701
  • Спасибо получено: 856
  • Проект месяца 3 местоРазработчикПроект месяца 2 местоПроект месяца 1 местоОраторОрганизатор конкурсов
"Спуститесь ниже и отключите ряд узлов «Spatial», тем самым убрав из списка ненужные элементы."

Это на самом деле нетривиальная задача. В этом окне нет клавиатурного поиска, стоит указать что эти узлы в самом конце списка.
"Почти доделали, но мы добавим еще один элемент в этой главе, на этот раз мы прикрепим пользовательский интерфейс узел под названием «TextureRect». Он похож на другой пользовательский узел интерфейса «ColorRect», который задет цвет, только он отличается тем что мы можем загружать готовый спрайт, картинки или фон."
Задаёт, видимо.
Последнее редактирование: 9 мес. 1 нед. назад от Snake Fightin.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Doctor_Bug

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129465

  • Snake Fightin
  • Snake Fightin аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 701
  • Спасибо получено: 856
  • Проект месяца 3 местоРазработчикПроект месяца 2 местоПроект месяца 1 местоОраторОрганизатор конкурсов


Не понял, что тут от меня хотят. Нужно выставить телегу верхним левым углом в перекрещение двух цветных линий?
Но у меня нет эти двух линий, куда выставлять?

После изменения механики траектории виснет с такой ошибкой:

scr1-2.png
Последнее редактирование: 9 мес. 1 нед. назад от Snake Fightin.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: IGPB

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129474

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
Snake нужен код тележки и скрин инспектора и рабочего окна самой тележки
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Snake Fightin

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129475

  • Snake Fightin
  • Snake Fightin аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 701
  • Спасибо получено: 856
  • Проект месяца 3 местоРазработчикПроект месяца 2 местоПроект месяца 1 местоОраторОрганизатор конкурсов
extends KinematicBody2D
 
var velocity = Vector2.ZERO
var acceleration = 70
var friction = 2
var animation
var width = 34 
 
func _ready():
	animation = get_node("AnimatedSprite")
	width = 34 * scale[0]
 
func _physics_process(delta):
	position.y = 162
	if Input.is_action_pressed("ui_left"):
		velocity.x = -acceleration
	if Input.is_action_pressed("ui_right"):
		velocity.x = acceleration	
 
	move_and_slide(velocity)
 
	if velocity != Vector2.ZERO:
		animation.playing = true
	else:
		animation.playing = false
	print(velocity.x)
	velocity = velocity.move_toward(Vector2.ZERO, friction)

scr1-3.png
Администратор запретил публиковать записи гостям.

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129476

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
Снейк обрати внимание у тебя в ошибки ссылается на параметр "wight" а ширина пишется width. Что значит wight?
Покажика мне скрипт шарика ^_^
Ошибка там в скрипте шарика
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Snake Fightin

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129478

  • Snake Fightin
  • Snake Fightin аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 701
  • Спасибо получено: 856
  • Проект месяца 3 местоРазработчикПроект месяца 2 местоПроект месяца 1 местоОраторОрганизатор конкурсов
wight опечатка, ошибка та же
extends KinematicBody2D
 
var speed = 50
var velocity = Vector2.ZERO
var run = false
var player
 
func _ready():
	player = get_parent().find_node("Player")
 
func start():
	velocity.x = [-1, 1][randi() % 2]
	velocity.y = -1
 
 
func _physics_process(delta):
	var collision_object = move_and_collide(speed * velocity * delta)
	velocity = velocity.normalized()
 
	if collision_object:
		velocity = velocity.bounce(collision_object.normal)
 
		if collision_object.collider.name == "Player": 
			velocity.x = get_x_bounce_direction()
		if	collision_object.collider.is_in_group('Bricks_group'):
			collision_object.collider.hit()
 
	is_ball_out()
	cling()
 
	if Input.is_action_just_pressed("Fire") and !run:
		start()
		run = true
 
func get_x_bounce_direction():
	var relative_x = position.x - player.position.x
	var percentage = relative_x / player.widht
	return (percentage - 0.5) * 2 
 
func cling():
	if !run:
		position.x = player.position.x + (player.width / 2)
 
func is_ball_out():
	if !$VisibilityNotifier2D.is_on_screen():
		run = false
		position.y = player.position.y - 3
		velocity = Vector2.ZERO
Администратор запретил публиковать записи гостям.

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129481

  • Snake Fightin
  • Snake Fightin аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 701
  • Спасибо получено: 856
  • Проект месяца 3 местоРазработчикПроект месяца 2 местоПроект месяца 1 местоОраторОрганизатор конкурсов
Давайте протестируем нашу игру. Сохраните и запустите игру. Заметим то что в игре почему-то отображаются только два сердца вместо трех.

Не, у меня сразу три сердечка и их число не меняется от падения шара.

ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]
Администратор запретил публиковать записи гостям.

Godot Engine. Проект "Арканоид" 9 мес. 1 нед. назад #129489

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • 3 местоПроект месяца 3 местоВетеран3 место в КодировкеПроект месяца 1 местоПрограммист Ruby
Снейк вроде проверил все нормально, а дальше ошибка появляется если продолжить обучение? Иногда это помогает решить проблему
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
  • Страница:
  • 1
  • 2
Время создания страницы: 0.596 секунд