Найти в Дзене
XotGames

Создаем Space Swords (2/3) - GameJam: алгоритм и меню.

В прошлом посте я описал как пришла идея, какой визуал у игры и прочее, то есть грубо говоря про дизайн. Рассказ же про разработку оказался слишком большой, поэтому вынес в отдельный пост. Также я здесь расскажу про алгоритм и создание меню, поскольку там больше именно разработнического, нежели дизайнерского. Разработка Начнем самый главный процесс. Реализация игры. !!!!!!!!!!!!!! Поскольку времени у меня было мало, очень много чего будет неоптимизированно и даже местами нелогично, что будет исправлено после. Приходилось придумывать многое на ходу. !!!!!!!!!!!!!!!!!! Какие сущности нам нужны для начала? Астероид, корабль, уровень. ---Уровень--- Что это за сущность такая? Это класс, который в себе будет содержать информацию об этом уровне. Сколько космонавтов надо переслать, сколько уже переслано, какое ограничение по времени, где порталы стоят, сколько осталось кораблей и т.д. В общем здесь будет храниться информация уникальная для каждого уровня и процессе прохождения этого уровня.
Оглавление

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

Разработка

-2

Начнем самый главный процесс. Реализация игры.

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

Какие сущности нам нужны для начала? Астероид, корабль, уровень.

---Уровень---

Что это за сущность такая? Это класс, который в себе будет содержать информацию об этом уровне. Сколько космонавтов надо переслать, сколько уже переслано, какое ограничение по времени, где порталы стоят, сколько осталось кораблей и т.д. В общем здесь будет храниться информация уникальная для каждого уровня и процессе прохождения этого уровня. Некоторые данные будут храниться в экземплярах отдельных классов.

Особое внимание нужно обратить на информацию об астероидах-островах. Для них создадим отдельный класс. Данные в этом классе будут следующие:

  • Астероид. Здесь будет храниться ссылка на объект.
  • Иконка. Здесь будет храниться спрайт, который будет обозначать астероид. Он будет выводиться на табличке над астероидом, и в запросе астронавта.
  • Цель. Здесь будет храниться ссылка на объект этого же класса, куда нужно переправить космонавта. Если цели нет, то в ней будет храниться "ничего" (NULL)

Так же стоит выделить класс для хранение характеристик и прогресса уровня. Данные в него вынесем следующие:

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

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

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

---Астероид---

Как я написал выше, у уровня будут ссылки на объекты класса Астероид. Что нам нужно в этом классе?

  • Чтобы знать, где ставится портал, создадим ссылку на картинку, которая будет обозначать место установки. Ее будем включать и выключать;
  • Ссылка на картинку портала, которую он будет включать и выключать;
  • Для управления астронавтами сделаем отдельный класс. Он будет воспроизводить разные анимации космонавта, включать и выключать его.

---Космический корабль---

Ну и, само собой разумеется, нам нужна сущность корабля.

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

  • Характеристики управления кораблем, скорость разгона, торможения, максимальная прочность (скорость после которой корабль взрывается), действующая скорость.
  • Ссылка на анимацию установки портала;
  • Ссылка на системы частиц, которые будут запускаться при ускорении;
  • Ссылка на систему частиц, которые имитируют взрыв;

Алгоритм и методы

Корабль

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

Для упрощения тестирования, сделаем управление с клавиатуры. Пишем методы, которые отвечают отдельно за чтение клавиатуры и за движение. Если мы нажимаем W, A, S или D (эти кнопки предустановлены как кнопки управления. В дальнейшем сделаем возможность их менять), то в метод движения передаем, направление движения через параметры X и Y. Метод движения в свою очередь придает ускорение кораблю в указанных направлениях. Величину ускорения мы указываем в настройках корабля. Так же для красоты добавим самостоятельное торможение корабля. Понимаю, вакуум, все дела, но для удобства будет такая игровая условность как сила трения вакуума. Реализуем это просто через придачу ускорения в противоположное направление от движения, величину опять же берем из настроек корабля.

Частицы. Нам нужно проанимировать полет, чтобы поживее выглядело. В этом нам поможет система частиц. Всего их будет 4, направленные в разные стороны. запускаться будут в зависимости от направления. Значит нам нужны следующие методы:

  • Метод управляющий конкретной системой частиц. В зависимости от того выполнено ли условие, которое ему указывают, либо нет указанные частицы;
  • Метод управляющий всеми системами частиц. Он запускает 4 раза предыдущий метод, но каждому говорит, какие именно частицы нужно запустить, и какие условия проверять;
  • Во избежание конфликтов включения и выключения, создадим метод, который выключает частицы, если не сказано их включить. Это нужно в нашем случае, так как в каждом направление участвуют по 2 системы частиц.
Анимация корабля при движении влево
Анимация корабля при движении влево

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

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

  • В классе уровня уменьшаем количество жизней;
  • Прячем изображение корабля;
  • Перемещаем на его место и запускаем систему частиц взрыва;
  • Запускаем метода респауна

Кстати о нем. Корабль же должен как-то возраждаться, поэтому создаем метод. Делаем так:

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

Ну и последнее, что нам нужно, ставить и собирать портал.

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

В целом пока больше ничего не нужно.

Астероид

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

Какие методы нам нужны?

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

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

Методы здесь тоже простые:

  • Поставить иконку;
  • Показать/спрятать задачу;
  • Управление анимацией человечка;

Уровень

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

Чтобы ограничить некоторые параметры и не плодить лишние методы, класс имеет СВОЙСТВА. Это тоже своего рода методы, но воспринимается в коде как параметр. Это очень удобно использовать для ограничения записи и выполнении дополнительных действий при чтении и записи. Но для них обязательно нужен отдельный private (если его не скрыть просто теряется смысл свойства) параметр.

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

Из классических методов, у нас следующее:

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

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

Меню и прочее

-4

Что ж. Готовый уровень - это хорошо. Но одним уровнем сыт не будешь. Нужно больше уровней, меню выбора, да и главное меню.

Меню и общее оформление

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

Пока две кнопки, одна запускает игру, другая открывает настройки, и прячет кнопки.

Главное меню
Главное меню

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

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

Все оформили, осталось добить это кодом.

Доделываем код

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

Настройки

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

Менеджер игры

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

Менеджер игры хранит в себе класс с настройками игры и класс менеджера экранов.

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

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

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

Для второго уровня я просто продублировал первый, добавил там еще остров, переместил их и поиграл с параметрами уровня.
Выбор уровня
Выбор уровня

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

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

Создаем билд в формате WebGL и заливаем на itch.io.

Вот и все пока. Поиграл сам, вроде забавненько. В конце было, наверно, слишком сумбурно, но и времени было всего часа 3-4 на меню, настройки и т.д.

_____________________________

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

Если укажешь на ошибку, не обижусь, а исправлю ее)

Для генерации изображений я использовал ИИ

_______________________________

Все страницы данной рубрики:

1 - GameJam: идея и визуал

2 - GameJam: алгоритм и меню

3 - GameJam: что не успели

4 - Рефакторинг - пишется

_______________________________

Все ссылки можно посмотреть здесь

Мой канал на itch