Войти на сайт

Авторизация, ждите ...
×

ТЕМА: Изучаем Godot Engine вместе с д-ром Багом. Pong

Изучаем Godot Engine вместе с д-ром Багом. Pong 1 год 8 мес. назад #127631

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

Оглавление разделов
1. Что же такое Godot. Установка программы
2. Знакомство с Godot Engine
3. Разработка игры Pong. Игрок
4. Программирование в Godot
5. Создание уровня
6. Создание противника
7. Создание мяча
8. Создаем отскок мяча
9. ИИ соперника
10. Сброс мяча
11. Игровой счет
12. Добавление отчета запуска мяча
13. Финальный этап «Pong». Добавление звуковых эффектов.

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


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


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


Приветствую вас форумчане, меня зовут Доктор Баг. В реальной жизни я работаю педагогом, провожу дополнительное образования (иными словами провожу кружки). Мое желание открыть кружок по разработки компьютерных игры, к сожалению, RPG Maker программы не подходят для этих целей, так как подобная серия программ заточена под определенный шаблон жанра. Конечно скриптами, плагинами можно изменять сам мейкер, но моя цель научить детей использовать свои знания не нагромождая их лишней информацией.

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

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

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

Godot Engine (фр. gó-doh) — открытый кроссплатформенный 2D и 3D игровой движок под лицензией MIT, который разрабатывается сообществом Godot Engine Community.

В годот вы можете создавать игры как 2D игры, так и 3D игры. Когда вы создаете игру в годот, вы сможете сразу видеть как будет выглядеть игра. В годот можно перетаскивать элементы прямо на рабочую область и видеть изменения игры. Годот использует собственный язык GDScript который похож на язык python, что облегчает разработку своего проекта.
Годот бесплатный и для скачивание программы вам потребуется перейти по ссылке godotengine.org/, в раздел загрузки («Download») и загрузить подходящую версию программы.

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

Вам откроется менеджер проектов:


Здесь вы можете открыть существующий проект, либо создать новый.
Нажимаем кнопку «Новый проект».

Годот запрашивает название проекта и путь к нему. Мы можем выбрать место для нового проекта нажав кнопку «Обзор».

Выбираем нужную папку и нажимаем кнопку «Выбрать эту папку». В моем случаи папка располагается по этому пути

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

Отрисовщик выбираем «OpenGL ES 3.0».
Нажимаем кнопку «Создать и редактировать»
Понг (Pong) – довольно простая игра, и для описание некоторых особенностей годота, идеально подойдет. В понге у нас есть две ракетки (Игрок и ИИ) и мяч. Главная цель игры забить гол сопернику как можно больше. Мячик может отбиваться от верхнего и нижнего края экрана и от самих ракеток. Если мяч пролетит мимо ракетки то получает гол соперник.
2. Знакомство с Godot Engine

Прежде чем мы будем знакомится с интерфейсом годот, мы должны понять как работает годот на более фундаментальном уровне. Годот использует две концепции
Узлы (Nodes)Сцены (Scenes)
Узлы — это фундаментальные строительные блоки вашей игры. Они подобны ингредиентам в рецепте. Существуют десятки их видов, которые могут отображать изображение, воспроизводить звук, представлять камеру и многое другое. Узел так же может быть 3х-мерным объектом. Это могут быть разные объекты, элементы, у Годо их несколько сотен.

К примеру, ты можешь видеть игрока который состоит из нескольких узлов, такие как спрайты (картинка персонажа), коллизия и даже к примеру анимацией персонажа.
Сцены в годо служат двум целям:
1. Как холст для ваших заметок
2. Организация ваших элементов игры в отдельные сцены, а после объединение в одной главной сцене.

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

Открыв проект мы можем увидеть интерфейс проекта.

В середине программы Годот располагается «Видовой экран»

Здесь мы можем сразу наблюдать открытую 3д сцену игры. В этой области отображаются игровые элементы которые вы будете помещать. Так как мы будем создавать 2х-мерную игру, мы нажмем на кнопку 2D и перейдем в режим 2д игры видового экрана

Теперь мы увидим 2х-мерную сцену нашей игры.

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

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

С левой стороны годота мы наблюдаем вкладку «Дерево сцен»

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

Здесь нам понадобиться первый узел, который мы собираемся использовать «Sprite», чтобы найти его среди остальных элементов видите название в поисковик, он отобразит нужный узел

Выберите его из списка. И теперь узел «Sprite» отображается в дереве сцен.

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

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

Здесь отображается все содержимое (почти все, кроме системных файлов годота) в корневой папке текущего проекта. Здесь есть файл icon.png, это иконка Godot, картинка. Схватите её левой кнопкой мыши и перетащите в инспектор нашего узла, в атрибут «Texture». Как вы видите, подтаскивая спрайт к атрибуту, он подсвечивается синяя линия, отпустите мышку прямо над словом [пусто]
Теперь мы можем видеть спрайт на нашем видовом экране

Теперь в видовом экране мы можем перемещать спрайт и координаты этого узла будут меняться, если раскрыть атрибуты Transform, то там мы увидим положение (position), вращение (Rotation Degree) и масштаб объекта (Scale).

Можете попробовать задать свои значения.

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

Откроется окошко со сохранением сцены. Сцены имеют формат «.tscn».

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

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


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

Находим узел «Sprite» и добавляем его.

Верхний узел спрайта становиться родительским узлом, а нижний узел дочерним узлом

Так что все что есть у родительского узла наследуется дочернему. К примеру дочерний элемент позиционируется относительно родительского элемента. Если мы выберем родительский спрайт и начнем перемещать по экрану, вместе с ней будет перемещаться и дочерний элемент, и другие дочерние элементы если бы они были. Перемести дочерний спрайт в сторону и попробую после перемещать родительский спрайт, и ты поймешь, что к чему. Можешь даже повернуть или масштабировать родительский элемент, и дочерний элемент будет повторять действия и менять свое положение в координатах и поворотах, и масштабах относительно родительского элемента. Но если изменять сам дочерний элемент, он не как не взаимодействует с родительским элементом.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 10 мес. 3 нед. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: AnnTenna, Kerotan, DarchanKaen, Jas6666, yuryol, akito66, Snake Fightin, Alx_Yago, SirAndriy, Sepheyer

Изучаем Godot Engine вместе с доктором Багом 1 год 8 мес. назад #127632

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • Программист RubyВетеранПроект месяца 1 место3 место в Кодировке3 местоПроект месяца 3 место
3. Разработка игры Pong. Игрок
Чтобы создать ракетку игрока, нам потребуются пару моментов:
• Ракетка должна быть видимой (это значит, что мы должны привязать спрайт к ракетки)
• Мы должны контролировать ракетку (Это значит нажатием клавиш мы будем перемещать ракетку на игровом поле)
• Ракетка должна реагировать на физику (Иными словами наша ракетка должна иметь физику столкновения, будь то мяч или край игрового поля)
В Годоте существует четыре узла которые могут напрямую работать с физикой, по крайне мере в 2х-мерном пространстве.
Физические свойства в годот (2D)
KinematicBody2D
RigidBody2D
StaticBody2D
Area2D
Каждый из этих узлов работают по-своему, но разберем узел KinematicBody, который является самым мощным среди них узлом, так как обычно этот узел используется для персонажа игрока.
KinematicBody
• Он может влиять на другие физические тела, и на него могут влиять другие физические тела
• Сам узел не имеет физическое тело столкновений, и потому к нему придется привязывать другой узел форму столкновений
Вернемся к нашей сцене «Player», удалим дочерний узел спрайта, он нам не понадобиться, щелкните по нему правой кнопкой мыши и внизу выберите удалить

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

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

Вводите в поисковике «KinematicBody2D», пару букв будет достаточно чтобы определить узел, и выбираем

Если присмотреться, то есть и просто узел «KinematicBody», он предназначен для 3х-мерной сцены, но так как мы создаем 2D-игру нам нужен узел «KinematicBody2D». В годоте можно создавать и 3х-мерные игры, обратите внимания что все узлы которые связанные с 2D играми синего цвета, а для 3х-мерных игры, узлы подсвечиваются красным цветом. Есть и другие типы узлов, но о них поговорим позже.

Выберете «KinematicBody2D». А после переименуйте название узла на «Player», щелкнув по название узла два раза, или правой кнопкой по узлу и выбрав опцию «Переименовать».

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

Привяжем KinematicBody2D с еще одним узлом. Нажмите плюсик и наберете в поисковик «Collision», среди 2х-мерных узлов у нас красуются узлы CollisionPolygon2D и CollisionShape2D (а так же узлы, которые были в таблицы с физикой в 2D).
В узле «CollisionPolygon2D» мы можем сами вручную указывать границы столкновение, а в узле CollisionShape2D выбирать готовые формы для столкновений.

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

Выбрав узел CollisionShape2D, переходи на инспектор узла справа, там есть атрибут «Shape» (с англ. «Форма»). Кликните по «Пусто» и выберете прямоугольник «RectangleShape2D»

Это будет физическое тело вашего персонажа.

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

Это физическое форма будет стакиваться с нашем мячиком или упираться в край экрана. Обязательно установите позицию по нулям (Transform -> Position: x, y).
Если мы нажмем F6 мы запустим текущую сцену, но мы ничего не увидим, так как форма столкновений невидима. Поэтому мы должны дать нашей ракетки видимый образ. Но как мы видим в нашей файловой системе (а точнее в корневой папки с игрой) нету нужных нам ресурсов. Скачайте тут архив и распакуйте. Там вы увидите папку «Assets», в ней храниться два изображения: ракетка и мяч, а еще музыкальные файлы эффектов и шрифт.

Возьмите папку «Assets» и перетащите его в годот в файловую систему.

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

Теперь ваша задача добавить изображение игрока (использовать картинку «Paddle.png» для ракетки). Используйте узел который мы в самом начале рассказывали, добавив текстуру.
У вас должно получиться это:

В годоте все расположенные узлы в дереве сцен имеют особенность. Узел находящийся ниже, становиться ближе к игроку. Приглядитесь узел sprite перекрывает узел CollisionShape2D, так как узел спрайта находиться ниже. Давайте перетащим узел спрайта выше узла CollisionShape2D и настроим форму столкновения с размером спрайта ракетки.

Если зажимать Shift и перемещать объект на видовом экране, то объект будет перемещаться только по одной оси.

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

Теперь, когда мы собрали все нужные узлы, давайте про анализируем. У нас есть узел спрайта «Sprite» для отображения игрока (ракетки), есть узел взаимодействии с физикой «KinematicBody2D» и узел формы столкновения «CollisionShape2D», это все что нужно для создание игрока. Сохраним сцену горячей клавишами «ctrl» + «S», или через меню «Сцена» -> «Сохранить сцену»
Запустите сцену F6, и мы увидим, что ракетка у нас находиться не совсем там, где мы хотели.

Переместим нашу ракетку через transform – position в инспекторе «Player»

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

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

На дереве сцен, у узла «Player» появиться такой же значок, и теперь вы можете смело его перемещать по экрану, не боясь что что-то сломаете или возьмете не то. Так как при нажатие на видовом экране на ракетку автоматически будет выбираться родительский узел, он же «Player»
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, DarchanKaen, Jas6666, VarVarKa, akito66, Snake Fightin, Alx_Yago

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127687

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

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

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

Нажмите на иконку.
У вас откроется окошко с настройками скрипта, давайте их разберем.

Первая опция «Язык» здесь предлагается на выбор несколько языков. Один из низ относиться к визуальному программированию «VisualScript», особый вид визуального программирование путем перетаскиванием блоков и связей между ними. Но мы будем использовать язык по умолчанию «GDScript»

Каждый узел наследуется от другого узла, в нашем случая наш скрипт будет наследоваться от узла «KinematicBody2D», а он в свою очередь наследуется с такого списка: PhysicsBody2D < CollisionObject2D < Node2D < CanvasItem < Node < Object

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

Шаблон по умолчанию

Если выберете «Empty» то кроме наследование класса больше не увидите ничего. А если выбрать «No Comments», то будет скрипт выглядеть так же как по умолчанию, только без комментарий.

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

Что же давайте все же создадим наш скрипт. Настройки скрипта будут такими.

Нажмите кнопку создать.
После этого нас перекинет на текстовый редактор самого Годота, обратите внимание сверху, мы из режима 2D перешли на режим Script. Вы можете снова переключаться между режимами если кликните на нужный режим.

Переменная – ячейка памяти в которой вы можете хранить различные значения или даже объекты, будь то целые числа, строки (обыкновенный текст, завернутый в двойные кавычки) или вещественные числа (дробные числа), или даже классы, узлы.
Объявление переменной в Годот происходит через оператор «var», таким образ мы объявляем Годоту о том, что выделяем память под переменную которую собираемся использовать.

Первая строчка кода говорит о наследование из узла (класса) «KinematicBody2D».

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

А теперь давайте удалим все, кроме первой строчки и объявим переменную с названием «Speed» (Скорость) и присвоим ей значение 400

Названием переменное выдуманное, а целое (не дробное) число подобранно случайно.

И чтобы наш код заработал мы должны использовать функции. Но что же такое функция?
функция — это набор инструкций, объединенных для выполнения одной задачи. Блоки кода, однажды оформленные в виде функций, можно использовать в коде многократно.

Мы можем использовать встроенные функции или собственные. Если мы создаем собственные функции (созданные нами), мы должны их вызвать во встроенных функциях чтобы они заработали. Конечно для этого мы должны описать встроенные функции.

Встроенные функции необязательно нужно прописывать если вы не собираетесь использовать собственные функции в них, так как Годот в любом случаи их вызовет сам.
К примеру, у нас есть встроенная функция «ready» которая всегда будет срабатывать если сцена готова.
Функции обновлении. В годот существуют 2 функции похожие друг на друга, но имеющие отличие.
_process_physics_process
Используйте _process, когда вам нужна разница между кадрами, зависящая от частоты кадров. Если код, обновляющий данные объекта, должен обновляться как можно чаще, это правильное место. Здесь часто выполняются повторяющиеся логические проверки и кэширование данных, но все сводится к частоте, с которой нужно обновлять оценки.Вызывается перед каждым шагом расчёта физики с постоянной частотой кадров (по умолчанию 60 раз в секунду). Используйте _physics_process, когда вам нужна разница во времени между кадрами, не зависящая от частоты кадров. Если код требует постоянных обновлений с течением времени, независимо от того, насколько быстро или медленно идёт время, это правильное место. Здесь должны выполняться повторяющиеся кинематические операции и операции преобразования объектов.

Теперь напишем встроенную функцию _physics_process, будем использовать её.

С новой строки вписываем ключевое слово func а после начнем писать _physics_process. Как только мы будем прописывать название функции Годот подскажет какую функцию мы собираемся использовать, даже не написав название функции до конца, нажмите кнопку Enter на клавиатуре, чтобы сразу вписать выбранный вариант.

Функция состоит не только от ключевого слова func и название функции, в скобках иногда может находиться текст – это аргумент. Аргументы это передаваемые значение или объекты в функции из вне. Аргументы не всегда могут присутствовать функциях. И заканчивается первая строчка функцией двоеточием.

Когда мы выбирали подсказу в скобках прописался аргумент delta, она является числом с плавающие запитой, равным времени, прошедшему в секундах с момента последнего шага. При использовании частоты обновления физики по умолчанию 60 Гц она обычно будет равна 0,01666... (но не всегда).
Теперь наша строчка горит красным фоном, это говорит о том, что мы еще не создали функцию, то есть она пустая, нету содержимого. Давайте это исправим.
Нажмите Enter (курсор должен находиться на конце строчки функции), Годот переведет активный курсор на новую строку и сделает отступ. Это очень важный отступ, которые сообщает Годоту что любая команда, находящаяся ниже функции и имеющая отступ принадлежит этой функции. Подобный отступ сравним с языком python. И если вы создадите новые строки не имеющие отступы, это будет означать что эти команды не будут принадлежать текущий функции.
В функции _physics_process мы должны дать игроку двигаться, и чтобы это сделать мы должны пройти три шага.

1. Мы должны определить ввод игрока. Момент, когда игрок нажимает клавишу для перемещения ракетки на игровом поле.
2. Мы храним ввод игрока.
3. Здесь мы применяем наш хранимый ввод для ракетки чтобы перемещать его по полю.
Начнем с первого шага (внезапно), но для начала нам понадобиться переменная для хранения ввода и мы будем использовать еще одну вещь Годота Vector2.

Vector2 - Двухэлементная структура, которую можно использовать для представления позиций в 2D-пространстве или любой другой паре числовых значений. Иными словами, это массив имеющий координаты X и Y.
Vector2 = [x, y]

Векторы полезны для разработки игры и их часто используют. Вектор это по сути стрелка указывающие любое направление. Но для начало мы вызовем вектор который никуда не указывает. Но если мы нажимаем клавишу вверх, то вектор должен указывать направление вверх, и аналогично с клавишей вниз.
Объявим переменную и назовем её «velocity», вызовем наш вектор Vector2. И когда мы поставим точку после вектора, Годот снова даст нам подсказки.

Но мы впишем аргумент «ZERO»

Аргумент «ZERO» в векторе указывает нам что направление не задано. Она выставляет значение вектора равная = [0, 0]
Шаг номер два: ввод пользователя с клавиатуры. Мы вызываем ключевое слово Input (отвечает за ввод с клавиатуры) и после через точку обращаемся к методу «is_action_pressed()» который отвечает за нажатие клавиши, которая назначена в атрибутах. Этот атрибут является ключом, заранее прописанной строкой, в нашем случая «ui_up», которая указывает на клавишу стрелки вверх.

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

Условие работает, как и другие условия в других языках программирования. Дословно можно сказать так: Если ввод кнопки вверх нажата, то мы выполняем следующее выражение которое будет под условием.
Не забудьте поставить if и двоеточие в конце условия, нажмите enter. Теперь курсор совершит снова переход вниз и снова сделает отступ, символизирующие будущие содержимое условию. Отступы важны!
Шаг третий, будем перемещать нашу ракетку с помощью значений. Вызовем нашу переменную «velocity», так как мы её уже объявляли, она находиться в памяти, теперь нам не нужно добавлять ключевое слова «var» чтобы использовать переменную.
Так как в нашей переменной храниться вектор мы можем использовать одно из значений вектора «y» вызывая его через точку. Мы собираемся вычитать единицу с этого значения.

Подобное выражение на 8 строчке, это сокращение от этого выражения.

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

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

В Godot же начала координат идет от верхнего левого угла. По оси Х схожа, как и в декартовой системе, а вот ось Y отличается. От начала координат вниз ось Y увеличивается положительно, а вверх отрицательно.

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

А теперь сохраните сцену и запустите её через F6. Попробуйте перемещать нашу ракетку за счет клавиш вверх или вниз. Поначалу вам может показаться что ничего не происходит, но присмотритесь, ракетка движется, правда крайне медленно, а все потому что мы лишь направляем ракетку, но не применяем к неё скорость. Умножим на направление нашу скорость прямо в атрибутах метода.

Снова сохраните и запустите текущую сцену F6. И наша ракетка будет двигаться намного шустрее.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 7 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, Jas6666, yuryol, VarVarKa, Snake Fightin, SirAndriy

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127706

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

Вся наша игра состоит из сцены игрока, но этого мало, мы хотим, чтобы у нас в игре были и другие элементы. Чтобы был противник и мяч, и они были бы отдельной сценой. Но мы должны собрать их в одну большую сцену. И это сцена будет «Сценой Уровня» (Level Scene). Для понга не нужно много элементов, все что нам нужно это ракетки игрока и противника, мячик, стены и немного кода для объединение игры.

Перейдем к нашей игре и создадим новую сцену, нажмите на плюсик на видовом экране сверху

А теперь мы должны определить какой узел будем использовать для главной сцены уровня

Можно было бы выбрать узел 2D, но мы выберем самый базовой узел, который не обладает ничем примечательным. Нажмите на кнопку «Другой узел» и выберете узел «Node»

Этот узел является классом для всех объектов Годота. Сам по себе этот узел ничего не может сделать.

Переменяйте его в «Level» (Уровень)

Обратите внимание на инспектор этого узла, все что тут есть так это пауза и скрипт.

Давайте сохраним нашу основную сцену. Горячее клавиши ctrl + S (или через меню – сохранить сцену) открывает окошко сохранение, создайте папку «Level» и сохраните там свою основную сцену с таким же названием.

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

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

Нажмите на неё и выберете нашего игрока

Мы можем создавать не только экземпляр игрока, но и сам уровень сцены.

Теперь наш игрок добавился в Сцену Уровня и будет иметь те же свойства что имел раньше. А давайте запустим сцену уровня через F6 и вы сможете так же им управлять но уже на «Сцене Уровня», а не на сцене Игрока. И если подняться слишком высока или спуститься слишком низко, то наша ракетка будет скрываться за пределами экрана, что есть тоже не совсем хорошо. Поэтому нам нужно что-то что ограничивало бы ракетку выход за предела экрана. И есть много разных способов ограничить нашего игрока. Но прежде чем мы это сделаем давайте поговорим о размере экрана нашей игры. Как мы помним синий прямоугольник указывает нам размер окна нашей игры. Давайте изменим её.
Переходим в самый вверх и в меню: Проект – Настройки проекта.

Здесь есть все настройки для текущего проекта

Спустимся ниже (с левой стороны опции) и найдем под опцию: Display - Window

Справа мы можем изменить размер нашего видового экрана: Width (ширина экрана), Height (высота экрана). Как мы видим по умолчанию всегда выставляется 1024х600, но для нашей игры эти значения не пойдут. Выставим значения 1280х720.
Следующая опция указывает будет ли окошко игры изменяться в размерах, иными словами мы можем сами растягивать игру за край окна, если того пожелаем, при условии, что опция включена.

Опция «Borderless» - запускает игру без полей (аккуратно, а то придется выключать игру через сам движок, кнопкой остановкой или нажимать горячие клавиши alt + F4)

У меня даже игра не влезла в экран.
Опция «Fullscreen» -делает вашу игру полноэкранным, занимает всю область экрана.
Я не все описал опции, но пока что выстави разрешения экрана 1280х720 и этого достаточно.
Теперь наш игровой экран увеличился, его можно отслеживать по линейкам сверху и слева, синий прямоугольник. А так же при запуске игры, окошка нашей игры стал намного больше.

Теперь перейдем к ограничителям нашей ракетки и у нас есть два способа как сделать это. Первый способ ограничить ракетку через скрипт или второй способ ограничить ракетку другим физическим объектом. Мы будем использовать второй способ. Пока что мы использовали «KinematicBody2D» для игрока, но для созданий стен, ограничителей, мы будем использовать новый физический узел. И это узел «StaticBody2D», давайте поговорим о нем:
• Этот объект не может двигаться сам по себе (сами если прописать мы можем двигать), если на него действуют другие физические тела
• Но он взаимодействует с другими физическими телами. Иными словами, другие объекты сталкиваются с ним, но не могут пройти сквозь него.
Статическое тело для 2D-физики. StaticBody2D — это тело, которое не предназначено для перемещения. Он идеально подходит для реализации объектов в окружающей среде, таких как стены или платформы. Кроме того, для статического тела может быть задана постоянная линейная или угловая скорость, которая будет воздействовать на сталкивающиеся тела так, как если бы оно двигалось (например, конвейерная лента).
Давайте создадим стену прямо здесь в «Сцене Уровня». Выберете узел «Level» и найдите узел «StaticBody2D» в поисковике, как всегда пару букв в поисковик и уже выдает результат.

Не забываем синим цветом текст узла указывает на 2D игры, конечно есть и трехмерный узел «StaticBody», который подписан красным цветом. Берем узел «StaticBody2D». И конечно, как любое физическое тело требует жерт… формы, об этом указывает восклицательный знак.

Помните какой узел мы применяли для добавление специальной формы для коллизии, к узлу «KinematicBody2D»?
Выбираем наш узел «StaticBody2D», и добавляем к нему узел «CollisionShape2D».

Учтите, что у вас должно выглядеть именно так, в узле «Level», должны быть дочернее элементы: узел «Player» и узел «StaticBody2D», а в узле «StaticBody2D» должен быть дочерний узел «CollisionShape2D». Иерархия здесь очень важна, иначе ваши узлы будут работать не корректно. Если у вас что-то находиться не на том месте, просто возьмите и перетащите элемент левой кнопкой мыши прямо в Дерево Сцен.

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

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

В левом углу появилась форма, приблизите экран к нему немного.

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

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

Но вернемся к разработке. Это будущая стена нашего верхнего плана (и нижнего, когда будем копировать). Наша задача разместить её за границей видимого поля, мы можем растягивать её и перемещать. Для более точных настроек стены воспользуемся опциями в инспекторе узла «CollisionShape2D», в меню «Transform» в опции «Position» мы можем перемещать наш объект по х и y.

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

Размеры самого прямоугольника откроются в новой опции

Здесь указаны от центральной точки фигуры до его края. Считайте половинки прямоугольника.

Давайте сделаем ширину в 640 пикселей (по ширине станет 1280 пикселей), а по высоте 5 пикселей (по высоте будет 10 пикселей). Подобный размер по ширине соответствует ширине нашего игрового поля. А в Transform – Position по Х установим 640 пикселей, так как наш прямоугольник позиционируется на экране благодаря центральной точки и это с точностью сменит его положение на экране перекрыв область верхнего игрового поля сместив форму от левого края на половину.

А по Y установим -5, чтобы чуточку приподнять нашу форму. Теперь смотрите как точно мы смогли настроить нашу форму, перекрыв верхнюю область игрового поля.

Переименуем наш узел со стеной в «WallTop» (стена сверху).

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

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

Не забудьте переименовать новую стенку в название «WalBottom» (Стена снизу).

Давайте переместим его вниз. Мы просто высчитаем и укажем в позиции нашего объекта координаты. Ширину трогать не будем, а вот вверх переместим. С учетом того что высота игрового поля равна 720 пикселей, а наша стена в толщину равна 10 (в размерах прямоугольнику указана половина ширины 5 до центра прямоугольника). Попробуйте высчитать какие координаты должна иметь Y, в transform – position. Только на этот раз мы перемещаем не форму узла «CollisionShape2D», а статический узел со стеной «WallBottom», который позиционируется от центральной точки, а не от формы.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Сохраните сцену и запустите игру F6 и вы не сможете выйти за пределы экрана.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 7 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, yuryol, VarVarKa, Snake Fightin

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127733

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

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

Структура противника состоит практически из тех же компонентов что и игрок, только без привязи скрипта. Как всегда, мы начнем создавать противника из узла «KinematicBody2D», выберете другой узел и найдите этот узел. А после переименуйте в «Opponent». Если не помнете как это делается обратитесь к 3 главе «Разработка игры Pong. Игрок».

Привяжем узел спрайта (Sprite) к кинематическому телу, и после из «Файловой системы» из папки «Assets» применим текстуру (картинку) на спрайт, под названием «Paddle.png».

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

Далее нам надо сохранить сцену с нашем противником. Нажмите горячие клавиши ctrl + S, далее создайте папку с названием нашего противника название «Opponent» и после сохраните сцену как она была названа автоматически (Opponent.tscn)

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

Теперь просто перенесите противника в противоположную сторону.

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

Каждый раз мы запускали игру через клавишу F6 или значок «Запустить сцену», но пришло время запускать сцену по умолчанию, которая будет запускать другие сцены. Иными словами, когда вы создаёт свою игру, у неё должны быть сцена по умолчанию которая запускается первой, а далее уже и другие сцены как вы того пожелаете.
Мы будем делать сцену с уровнем главной сценой. Выше инспектора виднеются кнопки запуска игры, обратите внимание на первый значок «Запустить», которая привязана к горячей клавише F5. Нажмите на неё.

Годот сразу спросит вас должны ли вы сделать текущею сцену главной

Если вы выберете «Выделение», то Годот отправит вас в корневую папку, чтобы там уже вы выбрали нужную сцену.

Но так как мы находимся на сцене уровня мы и будем делать её главной, выберете кнопку «Выбрать текущий». Поздравляю вы сделали сцену с уровнем главной сценой. Игра снова запуститься, но визуально ничего не произошло. Но если мы будем запускать игру (которая через F5) находясь даже не в сцене уровня, он все равно будет запускать сцену с уровнем. Ну и для запуска отдельных сцен используется F6.
Давайте закраем не нужные вкладки.

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

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

Если посмотреть в инспекторе, то там мы можем настроить цвет этого прямоугольника.

Но прежде чем мы будем настраивать цвет и размер прямоугольника обратите внимания на цвет самого значка узла «ColorRect», он зеленый, а это значит, что он принадлежит пользовательскому интерфейсу. Всего существует четыре категории узлов:
• Синий цвет значка – относятся к 2D направлению
• Красный цвет значка – относится к 3D направлению
• Зеленый цвет значка – относится к пользовательскому интерфейсу
• Белый цвет значка – это остальные узлы которые не попали в другие категории, к примеру наш узел «Node».

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

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

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

1. RGB (аббревиатура английских слов red, green, blue — красный, зелёный, синий) или КЗС — аддитивная цветовая модель, описывающая способ кодирования цвета для цветовоспроизведения с помощью трёх цветов, которые принято называть основными. Выбор основных цветов обусловлен особенностями физиологии восприятия цвета сетчаткой человеческого глаза.
2. HSV (англ. Hue, Saturation, Value — тон, насыщенность, значение) или HSB (англ. Hue, Saturation, Brightness — тон, насыщенность, яркость) — цветовая модель, в которой координатами цвета являются:
• Hue — цветовой тон, (например, красный, зелёный или сине-голубой). Варьируется в пределах 0—360°, однако иногда приводится к диапазону 0—100 или 0—1.
• Saturation — насыщенность. Варьируется в пределах 0—100 или 0—1. Чем больше этот параметр, тем «чище» цвет, поэтому этот параметр иногда называют чистотой цвета. А чем ближе этот параметр к нулю, тем ближе цвет к нейтральному серому.
• Value (значение цвета) или Brightness — яркость. Также задаётся в пределах 0—100 или 0—1.
Так же есть режим Raw, но про него особа не знаю, что за формат, но высчитывает значения RGB в процентном соотношении.
А еще присутствует шестнадцатеричное значение, в котором вы можете также закладывать цвет формате RGB. Каждая координата записывается в виде трех шестнадцатеричных чисел («rr», «gg», «bb»), пример белый цвет будет выглядеть так: #FFFFFF.
Вы можете выбирать пряма на палитре нужный цвет или использовать более точные настройки виде форматов RGB или HSV, но мы воспользуемся шестнадцатеричным значением: # 142126. Впишите значения.

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

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127739

  • Sepheyer
  • Sepheyer аватар
  • Вне сайта
  • Бывалый
  • Сообщений: 70
  • Спасибо получено: 38
Баг, в контексте этого: "Баг изучает это Panda3D pygame" - Вы видели Урсину?

Это враппер (раппер) вокруг панды: www.ursinaengine.org/

Плюс, это то, что питон, и если у Вас уже все личные библиотеки на питоне, то их не придется переписывать.

Это то, что останавливает меня от использования Годот (спасибо за уроки, кстати). При изучении RPGM приходится "портировать" личные библиотеки на JS, и в каком-то контексте это был урок о настоящей цене перехода на новый язык.

Кстати, что значит, GDScript похож на питон? Допусим в моей личной библиотеке врапперы функций листов и словарей, в формате независимых функций - их легко перевести в GDScript?
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Doctor_Bug

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127741

  • Doctor_Bug
  • Doctor_Bug аватар
  • Вне сайта
  • Светлый дракон
  • Из горизонта события! ▪_■
  • Сообщений: 568
  • Спасибо получено: 880
  • Программист RubyВетеранПроект месяца 1 место3 место в Кодировке3 местоПроект месяца 3 место
За Урсуну спасибо, как то не попадался этот продукт, любопытно по изучать его.
Насчет перевода... думаю нету смысла, но, годот имеет офигенное преимущество, ты можешь делать проекты и на js и на других языках программирование, он имеет поддержку.
На счет js и Годота тут статейка есть, сильно не углублялся как он поддерживает другие языки, но слышал что имеют такую фишку.
ТУТ

А вот с пандой 3Д у меня все печально, я не смог его освоить, мало документацией или опыта, но у меня не получилось его освоить.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 7 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Snake Fightin, Sepheyer

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127756

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

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

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


Далее выберете узел «Sprite», и добавьте в текстуру «Texture» из файловой системы из папки «Assets» картинку «Ball.png»
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]


В форме столкновения «CollisionShape2D», в опции «Shape» выберем на этот раз другую форму, форму окружности «CircleShape2D».

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

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

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

После того как добавили сцену с мячом на сцену уровня, возьмите мяч и перетащите его к середине экрана.

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

Стираем все лишнее со скрипта кроме первой строчки.

Объявим переменную скорости и зададим примерное значение на 600 единиц.

И еще одна очень важная вещь, но прежде чем я расскажу про неё давайте откроем другой скрипт. Скрипт игрока, который расположен по пути корневая папка/Player. Раскройте папку «Player», в файловой системе, и как видите там храниться наш скрипт «Player.gd» и наша сцена «Player.tscn» игрока. Дважды щелкните на скрипт «Player.gd», чтобы открыть скрипт.

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

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


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

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

Когда мы нажимаем вверх или вниз наше направление меняется, и ракетка двигается в нужном направлении, но если бы не было обнуление направления, то скорость ракетки бы росла постоянно. Потому мы каждый кадр обнуляем скорость и после заставляем двигаться с постоянной скоростью лишь на мгновения, но так как программа считывается очень быстро мы этого не замечаем, мы видим, как ракетка плавно двигается.
Вернитесь к скрипту мяча, теперь наша задача задать случайное направление мяча.
Мы воспользуемся встроенной функцией «_ready». Когда Годот считывает какой-либо скрипт то сперва он ищет скрипт «_ready». Это функция запускается первой, а после передает на постоянный поток функциям «_proccess» или «_physics_process». Функция «_ready» подходить для инициализации данных, которые должны быть запущена лишь единожды.
Но прежде чем я посвящу в дальнейшим случайности мяча запишите такую строчку.

Давайте разбирать. Первое переменная направления «velocity» мы берем координаты Х, которые отвечают за ось Х (по горизонтали), здесь мы будем направлять наш мяч. Далее мы присваиваем массив.

Что такое массив? Массив - это контейнеры, способные хранить более одного элемента одновременно. В частности, они представляют собой упорядоченный набор элементов. Словно вы объединили переменные в одном месте и у них есть порядок, числовое значение (которое называют индексацией).

Как и в переменной в массиве можно хранить разные значения, будь то строка или числовые значения или даже объекты. А индексация, числовой порядок начинается с 0 и по нарастающей. К пример в массиве «arr» значение «а» будет иметь 0 индексацию, а значение «b» номер 1 (индекс 1). А в массиве «arr2» значение 30 будет иметь 2 номер индексации.
К примеру, если мы захотим получить значений из массива мы должны вести сам массив и в квадратных скобках указать индекс значения.

Вытаскивая значение из массива мы должны присвоить какому-то объекту.
И так указывая такую конструкцию

Мы можем тут же вызывать нужное значение по индексу.
Теперь разберем что твориться в этой конструкции

Функция «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 для выведение значений в консоль что находится внизу в середине. Экспериментируйте!
И теперь зададим случайности и по оси Y, создайте похожую конструкцию.

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

Не забудьте поместить переменную направление в метод.
Сохраните сцену и запустите игру.

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

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

И как бы это не казалось странно, но как говорила одна старая черепаха

Функция randi создает случайное число, но это случайное число всегда будет одинаковой при запуски игры. Да если использовать несколько раз функцию randi он будет постоянно выдавать случайные числа, пока вы не перезапустите игру. И при следующим запуске будет выдавать тот же набор случайных чисел что и в предыдущем запуске. И запустив еще раз игру вы будете вечно получать случайные одинаковые числа (одинаковые в пределах разных сессиях запуски игры). Таково природа рандома, компьютер не сможет создать самостоятельно по истине случайное число, ему надо как-то помощь. У любого рандома есть семя, и он работает благодаря ему, выдает случайные числа по алгоритму. Но если привязывать данные которые компьютер будет получать из вне, к примеру, в семя можно помещать дату, и рандом будет действительно разный, но он тоже будет повторяться в течение какого-то время, пока дата не измениться. И вот для таких случаях используется функция «randomize()». Подобная функция настраивает начальное значение на основе времени. Поместите эту функцию в «_ready».

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

Да наш мяч… не отскакивает от стены, думаю вы это заметили. Отскоком мяча мы займемся в следующем раздели.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 7 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, DarchanKaen, Jas6666, yuryol, Snake Fightin

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127783

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

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

Мы будем использовать функцию «move_and_collide()» для столкновение мяча, исправьте код в скрипте мяча. Мы умножим не только на направление и скорость, а еще и на дельту.

И позвольте рассказать, что такое «delta».
Delta – это количество времени прошедшая с момента вызова последнего кадра игры. Если игра привязана к частоте кадров, то она работает быстрее на быстром ПК и медленней на медленном. Дельта же уравновешивает это, так как она берёт время, пройденное с последнего кадра, в итоге на любом ПК игра будет работать идентично не важно лагает она или нет.
Дельта — это числовое значение с плавающий точкой. Дельта достаточна маленькое значение. Если у вас достаточно мощный ПК, то ваша игра будет работать намного быстрее, но дельта будет маленького значения и будет умножаться на скорость объектов достаточно часта. А если же медленный компьютер, то дельта будет больше и умножаться будет реже. Тем самым с помощью дельты мы можем уравновесить скорость игровых объектов.
Функция «move_and_collide()» также возвращает объект с которым столкнулись, так что мы используем это. Поместим объект столкновение в переменную «collision_object» чтобы вычислять объекты с которым столкнулся наш мяч.

Используем условие. Поместим переменную «collision_object» в условие, если переменная имеет объект столкновение, то в условие будет отправляться «Истина», если же нет, то «Ложь».

(pass – это заглушка для всяких условий, циклов, по сути эта команда ничего не выполняет, но предотвращает ошибку)
В пишем такую конструкцию:

А теперь позвольте объяснить, что здесь происходит, про иллюстрировав происходящие. Здесь вы видите мяч сталкивающийся со стенкой, и здесь мы хотим, чтобы наш мяч отскочил от стенки, и для этого нам понадобиться то что называется нормалью. А нормаль — это просто направление в котором направлена плоскость. Сейчас наша стена (она же плоскость или поверхность) направлена вверх, и мы можем использовать нормаль для вычисление отскока мяча в нужном направлении. И чтобы направлять наш мяч в нужном направлении мы и используем метод «bounce» который применяет аргументом объект столкновения, а точнее его нормаль.
Ну а теперь просто запустите игру, и вы заметите как мяч бодренько отскакивает от стенки или игрока, или противника.
В следующем разделе мы займемся создание ИИ нашего противника.
Баг изучает Godot Engine. А слушает эту музыку ~~> Мое сердце
Последнее редактирование: 1 год 7 мес. назад от Doctor_Bug.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666, yuryol, Snake Fightin

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127815

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

Создание нашего Искусственного Интеллекта будет на самом базовом уровне, но для начала немного пару слов о самом ИИ.
Иску́сственный интелле́кт (ИИ; англ. artificial intelligence, AI) — свойство интеллектуальных систем выполнять творческие функции, которые традиционно считаются прерогативой человека (не следует путать с искусственным сознанием, ИС).

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

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

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

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

Далее мы объявим новую переменную, но присваивать её ничего не будем. Переменная мяч (ball). Мы присвоим значение её позже

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

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

Так вот метод «get_parent» возвращает родительский узел если есть, а если нет возвращает значение «null» что означает отсутствие узла.
Следующий метод «find_node» ищет нужный узел из родительского узла, по имени узла. В нашем случаи, когда запускается игра скрипт соперника ищет родителя, это наш узел сцены уровня, а после находит узел по имени «Ball» и помещает объект в переменную ball.

Теперь в переменой ball находится наш узел мяча «Ball» и мы можем с ним работать.
Теперь опишем физический процесс, поместим метод движение и скольжение объекта. Мы собираемся двигать наш объект имитируя движение живого игрока. Внутрь поместим вектор направления, который будет обнулен. ZERO – сбрасывает вектор до нуля по х и y (0, 0).

Далее мы создадим собственную функцию, не встроенную

Это функция никогда не запуститься пока мы её не вызовем, так встроенные функции будут запускаться в определенные моменты Годота. Это функция будет определять направление соперника, когда ракетка должна двигаться вверх, а когда вниз.
Логика соперника будет проста.

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

Метод «position» отвечает за координаты объекта. В этом примере мы обращаемся к координаты мяча по высоте (по оси Y) и дальше вычитаем координаты по высоте ракетки соперника. Да любой объект который вам в будущем понадобиться переместить, можно использовать ключевое слово «position». Математическая функция «abs» превращает любое число находящийся в скобках в положительное число. Если было отрицательное, станет положительным, если было положительным, то так и останется.
Конструкция: abs(ball.position.y – position.y) высчитывает дистанцию между объектами. Позвольте показать.

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

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

Здесь говориться если мяч ниже ракетки соперника, то будем возвращать 1, а если выше соперника, то будем возвращать -1. Ну и если наравне, то 0.

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

Возвращение 0 принадлежит первому условию. Ключевое слово return возвращает полученное значение и завершает функцию. Поэтому если условие на 14 строчки было истинно, функция возвратит 1 и завершит эту функцию, игнорируя дальнейший код функции.
Мы создали функцию направления соперника, но куда мы её поместим. Давайте подкорректируем наш вектор и уберем команду ZERO.

Вектор имеет парные значения Х и Y, так что мы можем напрямую указывать направления через скобки. К примеру Vector(0, -1) будет приравниваться к Vector.UP или position.y += -1, что будет перемещать объект по высоте вверх, вы так же можете указывать и по Х.
А так как наша функция get_opponent_direction() возвращает числовое значение (направление) виде 1, или -1 или 0, то мы можем умножить на скорость соперника, для того чтобы заставить его двигаться.

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

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

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127865

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

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


Как и с другими физическими узлами, узел «Area2D» требуется форма столкновения (хотя по сути не будет столкновения), для обозначение области с которым будут взаимодействовать объекты. Снова прикрепим узел «CollisionShape2D» на этот узел. Для прикрепления узла есть горячие клавиши, ctrl + a, попробуйте.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

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

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

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

По умолчанию узлы «Area2D», ничего нам не сообщат если какой-либо объект их пересечет. Для этих целей нам понадобиться особый механизм, новая концепция – сигналы.

И все что делают сигналы, так делают заметки которые помогают нам общаться с другими узлами. И то что нам понадобиться это лишь то, что наши узлы «Area2D» сообщали нам, когда что-то попадает в их область. И чтобы подключить сигнал, нам понадобиться немного кода, так как сигналы создают новые встроенные функции которые работают на определенных экземплярах.
Начнем, только сначала переименуем наши узлы «Area2D» на «Left» (левая область) и «Right» (правая область) двойным нажатием на мыши по имени узла.

Выберете узел «Left», и правее инспектора узла, вы найдете еще одну вкладку под названием «Узел»

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

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

Сигнал «body_entered», срабатывает, когда в область попадает объекты похожие на мяч, любые физические тела. Он та нам и нужен, щелкните по нему два раза.
Проблема в том, что сигналы мы можем подключить лишь тем объектам которым прикреплен скрипт.

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

Почистим код оставив только первую строчку.

Далее вернемся с дереву сцен выберем наш узел «Left» (который Area2D), перейдем к сигналам и выберем сигнал ««body_entered»». Щелкните снова по нему два раза.

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

Нажмите присоединить скрипт.
И теперь у нас появилась новая встроенная функция в скрипте уровня, которая будет срабатывать в том случаи, если в область узла «Area2D», будет попадать физический объект.

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

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

Print очень полез для тестирование кода, туда можно помещать и переменные, функции которые возвращают булевою значение и не только.
Так как мы убедились, что область активируется, следующие что нам следует сделать это повлиять на сам мяч, и вернуть его в середину нашего игрового поля. Но на этот раз ситуация немного отличается, по сравнению с соперником. У соперника мы прописывали путь, по которой мы вычисляли сам мяч, начиная от родителя и заканчивая поиском самого мяча. В этот раз мы находимся в родительском узле, и нам нужно подгрузить дочерний узел, но как это сделать, все просто, добавьте знак «$» в код и наведите на нужный объект, в нашем случаи мяч. Да не забудьте удалить print, он нам не понадобиться.

Если выбор узлов не выскачет, просто ведите знак доллара и название самого объекта «$Ball». Таким образом мы обращаемся на прямую к объект мяч

Далее пропишем его позицию и зададим вектор 2, с координатами.

Заметка, обычно мы использовали вектор2 как источник направления движение объектов, но на этот раз мы используем его форму для указание точных координат. Как вы заметили мы используем метод «position», он нужен для указание координат. И да он находится в инспекторе любых объектов во вкладке «Transform», а координаты 640 и 360 это наша середина разрешение экрана 1280 на 720 пикселей.

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

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

Изучаем Godot Engine вместе с доктором Багом 1 год 7 мес. назад #127900

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

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

Как вы могли заметить наш узел «label» зеленного цвета, он относиться к группе «Пользовательского интерфейса» и потому имеет особые свойства присуще только этой группе.
Обратите внимание на инспектора справа, там есть форма для текста, давайте впишем туда строку «Test»

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

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

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

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

Опция «Align» отвечает за горизонтальное выравнивание, в ней содержится 4 параметра, right, center, left, fill. Выравнивание по правую сторону, по левую, по центру, fill что делает так и не понял, по правде говоря, вроде как должен заполнять весь участок по ширине. Опция «Valign» отвечает за вертикальное выравнивание и имеет схожие параметры, только вместо левого и правого направления, верхнее (top) и нижние (bottom) выравнивание.
Выставим наш текст точно по середине, а для этого выровняв по горизонтали и вертикали по центру.

Только сместите немного сам мяч, иначе он перекрывает текст.
Далее мы сместим текст с помощью «Margin» левее от центра, это будут счет игрока, помним, так же позже сделаем счет противника аналогичным способом, только сместим вправо. В опции «Margin» есть 4 параметра указывающие направления смещения: Left (влево), Top (вверх), Right (вправо), Bottom (вниз). Увеличивая или уменьшая (числа могут быть и отрицательные) мы смещаем наше поля в ту или иную сторону. Давайте сместим наш текст влево на -200 единиц.

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

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

Далее просто будем обновлять текст у узлов «Label» во встроенной функции процесса. Помним через знак «$» мы можем напрямую обращаться у дочернему узлу родителя, в нашем случаи родитель — это узел уровня «Level», а дочерние узлы это «PlayerScore» и «OpponentScore». Далее мы обратимся к атрибуту текста, и присвоим ему переменную.

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

Иными словами, если вызвать «узел.margin_left = -200», то результат будет такой же, как мы заранее прописали в инспекторе. И таким способом вы можете обращаться к любому атрибуту узла, только разные атрибуты иногда требуют разные типы данных. Помните это.
Но вернемся в нашему коду, по правде говоря он не сработает и связано это с тем, что атрибут узла «text» требует строковые значения, но наша переменная PlayerScore имеет числовое значение, и при запуске игры выскачет ошибка.

Чтобы это исправить мы превратим числовое значение в строковое в пределах текста.

Метод str превращает числовое значение в строковую. Запустите игру, и вы будете наблюдать как текст «Test» смениться на число.

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

Но как мы узнаем кто из игроков забил и кому забил? Так как у нас уже есть области где мяч сбрасывается, то мы можем их использовать для отслеживания счета. К примеру, в левой области узла «Left» (он же узел Area2D), как только мяч попадает в эту область мы прибавляем счет соперника на единицу. Аналогично и справой областью.

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

Запустите игру и протестити счет игрока и соперника.

Все должно работать идеально, осталось лишь слегка настроить стиль текста и добавить свой шрифт.
Нажмите на узел счета игрока и перейдите к инспектору, там вы найдете переопределение темы «Theme overrides» далее «Fonts», а после нажмите на [пусто]. У нас есть два варианта выбора шрифта, растровый шрифт или динамический, возьмем динамический шрифт «Новый DynamicFont»

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

В нашем случаи в папке assets есть готовый скаченный шрифт формата ttf, под названием «PoetsenOne-Regular». Вы можете найти любой шрифт который вам понравиться в интернете.
p.s. шрифт по умолчанию не имеет кириллицы, поэтому для отображение русских букв вам понадобится шрифт с кириллицей.
Далее мы перетащим наш шрифт из папки assets из файловой системы в инспектор в Font Data.

После это отобразиться шрифт в опции Font Data, и на экране снова появиться наш счет игрока.

Настроим его размер, раскройте вкладку settings и увеличьте размер шрифта Size до 40 единиц.

Так текст стал выглядеть более наглядно и крупнее. Теперь изменим цвет шрифта, на более мягкий не совсем белый цвет, вы можете выбрать любой цвет, но я возьму 16-теричный цвет d9d8d7. Цвет он же «Colors» располагается выше вкладки «Fonts».
И это все что нужно чтобы текст выглядел красиво.

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

А когда запустите игру то счета игрока и соперника будут красиво смотреться на местном фоне.

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

Изучаем Godot Engine вместе с доктором Багом 1 год 6 мес. назад #128002

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

Есть узел отвечающий за время, подобный узел можно использовать для создание отчета по времени на какое-либо событие. Мы будем использовать узел «Timer» для задержки выхода мяча, когда мяч вылетел за область экрана. А также мы будем отображать наш таймер на экране, чтобы игрок мог наблюдать время, когда мяч заспавнится. Отчет должен идти от 2, 1, 0 и после должен появиться мяч. Но вы можете и увеличить таймер, все будет завесить от вас.

И так привяжем наш новый узел таймер «Timer» к узлу уровня.

После переименуем в «CountdownTimer» таймер обратного отсчета (так дословно переводиться с английского языка, countdown – обратный отсчет, а timer -таймер)

В инспекторе узла мы можем увидеть опцию «Wait time» - отвечающая за время ожидание, в нашем случаи здесь указана 1 секунда, поставьте на 2 секунды. Опция «One shot» запрашивает будет ли таймер запускаться снова или нет после просчета времени, если стоит галочка (она же истина - true) то проигрываться будет лишь единожды. Поставьте галочку.

Как должен отрабатывать наш узел таймера? Когда мяч вылетает за область экрана, она попадает в левую область или правую области наших узлов «Area2D», и после того как мяч залетает туда, должен запускаться таймер, после его истечение таймер должен испускать сигнал об окончание отчета, а после мяч должен появиться в центре экрана, и игра запускается вновь.
У узла таймера есть только один, но очень важный сигнал, сигнал оповещающий истечение времени. Когда время отчета заканчивается срабатывает этот сигнал. Пройдите к сигналам узла таймера и выберете первый и единственный сигнал узла (там есть и другие сигналы, но они передаются по наследству от других узлов) «Timeout».

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

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

Какова будет логика: когда мяч попадает в область с левого или правого края, мяч возвращается в середину экрана, и в тот же момент запускается наш таймер. И после того, когда таймер закончится наш мяч должен запуститься.
Пока что мы не прикрутим наш таймер к тексту, наша задача влиять на мяч который находиться в собственной сцене из нашего сцены уровня. Но как это сделать? Есть несколько способов как влиять на объекты со собственной сценой, но мы воспользуемся группой.
Это еще одна концепция Годота, похожая на сигнал, но с небольшим отличием.
Сигналы можно передавать от одного узла к другому, и наоборот. Для группы мы все еще начинаем с одного узла, но можем воздействовать на другие узлы, при чем на столько сколько захотим. Так что любой узел который входит в какую-либо группу может быть нацелен на него. А еще не важно где будет узел, группа узлов можно использовать от куда угодно, даже из другой сцены. Далее мы поместим наш мяч в группу, и затем из сцены уровня нацелиться на группу. А затем эта группа скажет мячу выполнять определенные действия.
Вернемся к разработки и перейдем в сцену с мячом, нажав на иконку для перехода в сцену мяча.

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

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

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

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

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

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

Для этого нам понадобится такие методы.

Давайте разбираться с конца команды: метод call_group вызывает группу который записывается первым аргументом, второй аргумент вызывает функцию узла этой группы. Но что значит «get_tree()»?
Давайте запустим игру, но перейдем самому редактору при запущенной игре.
Мы увидим в дереве сцен две опции «Удаленный» и «Локальный». В удаленной сцене отображаются все текущие элементы игры, нажмите на неё. Вы заметете корневой узел все узлов которые запустились во время игры «root», функция get_tree() позволяет получить доступ ко всем узлам корневого узла «root», а это значит что мы можем обращаться функции таким которые привязаны к группам, что мы не могли бы сделать с определенного узла.

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

Запишите такую строчку и на другой области.

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

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

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

Не забудьте и в другой области прописать вызов таймера.
И теперь должно сработать. Запустите игру, когда мяч вылетит за границы экрана, он вернётся в середину экрана, а после 2 секунд запуститься снова.

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

Мы можем поместить дублирующий код в свою собственную функцию, что же давайте это и сделаем, спуститесь ниже функции отчета таймера и создайте функцию ball_launch() «Запуск мяча» - функция которая будет устанавливать позицию мяча в центре экрана и запускать таймер отсчета таймера. А теперь скопируйте дублирующий код, кроме подсчета очков.

А далее удалите дублирующий код и поместите там функцию ball_launch().

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

Переменяем его в CountdownLabel (ярлык обратного отсчета), далее переместите к другим узлам пользовательского интерфейса.

Так как элементы игры по умолчанию отображаются чем ниже в дереве сцен, тем ближе к игроку, и было бы странно если бы текст перекрывал сам мяч во время полета (хотя тут уже зависит от самого разработчика, как отображать тот или иной элемент).
И снова в макете текста устанавливаем «Полный прямоугольник», дабы заполнить область поля текста на весь экран. А в самом узле в тексте укажем «Countdown» (обратный отсчет), для отображение текста на экране и указание вне игры что за элемент находиться. Далее разместите текст по центру используя опции Align и Valing.
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

Задерем наш отсчет вверх через опции Margin, воспользуемся верхом «top» установим примерно в -300 единиц.

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

А теперь подключим наш узел текста к таймеру, а точнее к отсчету таймера. Мы так же будем размещать отображение текста в функции _process. Обратимся к узлу «CountdownLabel» через знак «$», к методу «text». Мы будем помещать туда остаток времени от таймера, за эту процедуру отвечает метод «time_left».

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

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

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

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

Если этот метод будет ложь, то отображение выключиться, а если истина, то включиться.

Мы сталкиваемся с еще одним типом данных, булевое выражение где ложь это false, а истина true. Да и выключите видимость текста отсчета в инспекторе, чтобы при запуске не отображать текст. Когда будет visible установлен в false, текст не будет отображаться, а если будет значение true, то будет отображаться.
Так же мы будем включать видимость текста обратного отсчета при удаления мяча за экран. Чтобы потом прокручивать таймер снова.

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

Изучаем Godot Engine вместе с доктором Багом 1 год 6 мес. назад #128007

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


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

Как вы заметили, высветилось сразу три узла под названием «AudioStreamPlayer», лишь окончание узлов отличается. К примеру узел «AudioStreamPlayer3D» будет воспроизводиться с учетом пространства и дистанции от источника звука, или к примеру какая-либо стена которая приглушала бы уровень громкости звука. С узлом «AudioStreamPlayer2D» ситуация аналогичная, только для 2д игр. Но мы воспользуемся простым звуковым эффектом который не будет реагировать на дистанцию или пространство вокруг себя «AudioStreamPlayer». Добавьте этот узел.
Переименуем наш звуковой узел в «ScoreSound» (Score – счет, а Sound - звук).

Теперь добавим звуковой эффект который находиться у нас в assets, у нас имеются два звука.

Для озвучивания получения счета подойдет звук «ping_pong_8bit_plop.ogg», хватайте этот звук и перетаскивайте в инспектор звукового эффекта узла «ScoreSound» в опцию «Stream»

Давайте изучим некоторые опции узла звукового эффекта

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

Ниже мы можем заметить опцию «Loop» - виновник нашего торжества. Опция циклически заставляет воспроизводить звук. Отключите её. И переимпортируйте файл.

А теперь вы можете прослушать звук в инспекторе если еще раз попробуете включать или выключать опцию проигрывание «Playing».
Давайте сразу переимпортируем наш второй звук «ping_pong_8bit_beeep.ogg», отключив цикличность в импорте. Проделайте это сами. Второй звук будет отвечать за отскок мяча.
Перейдем к скрипту нашего уровня. У нас есть собственная функция где идет позиционирование нашего мяча, когда тот вылетит за пределы экрана, вот там то мы и воспроизведем звук. Обратимся к звуковому узлу и пропишем ему метод «play()» который запустит звук когда мяч вылетит за экран.

Протестируйте игру, пускай мяч вылетит за пределы экрана, и вы тут же услышите звуковой эффект.
Теперь давайте зададим звук и мячу, перейдите в сцену мяча, заранее добавим узел звука. Добавите его прикрепив к узлу мяча. Выше уже рассказывалось как добавлять звуковой узел. И переименуйте его в CollisionSound (Collision – столкновение, Sound - звук).

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

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

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

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

Изучаем Godot Engine вместе с д-ром Багом. Pong 1 год 6 мес. назад #128076

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


вот проект (15 мб): drive.google.com/file/d/1VycwVTW8bFirzgx...ERf/view?usp=sharing

1. Если на рестарте есть рандомайзер (строки 25,26)

gif1-2.png


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

2. игре нужно завершение по достижении какого-то счёта

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


готов делать орконоид.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Kerotan, Jas6666, Doctor_Bug, Cuprum Buddy

Изучаем Godot Engine вместе с д-ром Багом. Pong 1 год 6 мес. назад #128109

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

План сейчас такой, приблизительно на жанр аркады.
  1. Проект "Понг"
  2. Проект "Арканоид"
  3. Бонусный урок: Главное меню
  4. Проект "Космический шутер"
  5. Проект "Астероид"
  6. Бонусный урок: Сохранение
В разделе жанра "Аркады" будет 4 игры и два бонусных занятий. Так как годот имеет модульность со сценами, то к примеру создав отдельной сценой "меню" после сможем её без труда связывать с другими нашими проектами, годот в этом плане очень динамичен, мы не привязаны к одной механики вокруг которой все вертеться.

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

Изучаем Godot Engine вместе с д-ром Багом. Pong 1 год 6 мес. назад #128119

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

да, есть минимум две тактики

gif1-1.png




1 отбить мяч торцом биты, чтоб мяч ушёл под острым углом, тогда ИИ не успеет за ним

2 пропустить несколько голов себе, чтоб скорость мяча возросла (ты ведь заметил, что я добавил это), тогда ИИ не сможет успевать за мячом
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Jas6666, Doctor_Bug
Время создания страницы: 0.489 секунд