Перейти к содержанию

Создание RTS стратегии с нуля


Рекомендуемые сообщения

Предыстория

В официальном блоге не так давно появилась новость о том, что Ashley (разработчик Construct 3) решил создать стратегию в жанре RTS с помощью Construct 3. Но есть нюанс. Ashley решил большинство механик реализовать при помощи встроенного в Construct 3 инструментария JavaScript. Как-то странно создавать игру с помощью Construct, не используя главную фишку Construct — систему событий.

И вот, мне тоже захотелось создать с нуля свою собственную RTS, только с использованием системы событий.

RTS (Real Time Strategy)

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

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

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

Разработка

Игра в жанре RTS представляет собой несколько базовых механик, объединённых в одну игру:

  • добыча ресурсов
  • строительство зданий
  • производство юнитов
  • управление юнитами
  • сражение юнитов
  • искусственный интеллект

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

Моя текущая цель — как можно раньше получить играбельную сборку. После чего можно будет развивать «в глубину» каждую отдельно взятую механику.

Если вам интересна данная тема и вы будете следить за ходом разработки — ставьте лайки!

  • Like 1
  • класс! 1
  • супер! 2
Ссылка на комментарий
Поделиться на другие сайты

УПРАВЛЕНИЕ ЮНИТАМИ
алгоритм поиска пути

Игровая карта представляет собой поле, разделённое на клетки. Одновременно на одной клетке может находиться только один юнит.

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

Существуют разные алгоритмы поиска пути. Например, "волновой алгоритм", "A*" и т.д. Если кому интересно, вот подробнейшая статья по этой теме.

Алгоритм поиска пути можно написать событиями (при помощи массивов) или воспользоваться сторонним поведением "EasyStar.js". Данное поведение добавляется на тайловую карту, после чего открываются полезные действия и выражения.

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

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

Если юнит не может найти путь (например, он со всех сторон окружен другими юнитами), то запускается таймер, по истечению которого юнит может снова повторить попытку

RTS - pathfinding_0.png

RTS - pathfinding_1.png

Ссылка на комментарий
Поделиться на другие сайты

УПРАВЛЕНИЕ ЮНИТАМИ
способы выделения

Следующая задача — добавить различные способы выделения юнитов, а также их управление. Здесь всё просто — добавляем объекту Unit переменную isSelected (значением true/false), которая в дальнейшем будет играть роль фильтра в событиях для выбора выделенных игроком юнитов.

Добавил в проект основные механики:

  • одиночный выбор юнитов
  • выбор всех (двойным тапом по экрану)
  • скроллинг карты
  • рамка выделение юнитов
  • закрепление выделенных юнитов в группу

Остановимся на последнем пункте.

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

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

группы_0.png

Когда игрок удерживает кнопку в течении 0.5 сек — происходит запись выбранных юнитов в группу. Когда игрок нажимает на кнопку (без удержания) — происходит выбор юнитов. У каждой кнопки есть свой массив (в контейнере), каждая ячейка массива содержит UID каждого выбранного юнита.

группы_1.png

выбор юнитов_1.png

выбор юнитов_0.png

Ссылка на комментарий
Поделиться на другие сайты

СРАЖЕНИЕ ЮНИТОВ
стрельба и нанесение урона

Все юниты (как дружеские, так и вражеские) являются одним объектом. Чтобы различать юнитов находящихся в разных командах была добавлена переменная (0 - юниты игрока, 1 - юниты врага). А чтобы в событиях можно было одновременно работать с разными копиями одного объекта, спрайт Unit был помещён в семью. Все переменные и поведения нужно накладывать сразу на семью.

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

battle_events.png

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

battle_func.png

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

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

В будущем можно будет добавить:

  • стрельбу очередями
  • вероятность попадания пули
  • разные типы пуль (пуля / снаряд / ракета)
  • возможность нанесения урона в радиусе попадания снаряда (например, если такой снаряд выпущен артиллерией)
  • очки прочности для ракеты (которую смогут сбивать ПВО/ПРО).

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

Советы

Чтобы избежать нагромождения событий, а также дублирования одних и тех же событий, используйте функции. Функции помогают избегать дублирования событий, сохранять лист событий легко читаемым, простым, понятным и лаконичным. Особенно радует добавленная не так давно в C3 возможность автоматического переноса в функцию выбранных копий объектов (copy picked). Раньше для этого требовалось добавлять в функцию дополнительные условия для фильтрации объектов.

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

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

 

Изменено пользователем ViGaCi
добавил ссылку на обсуждение урока
Ссылка на комментарий
Поделиться на другие сайты

ТУМАН ВОЙНЫ

В стратегических играх сбор информации о противнике является важной частью геймплея. 

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

Туман войны бывает двух видов:

  • статичный
  • динамичный

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

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

Разработка

Для юнитов добавлена переменная Vision, которая обозначает дальность видимости (в клетках) каждого конкретного юнита.

fog.png

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

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

fog_map.png

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

Ссылка на комментарий
Поделиться на другие сайты

В 23.11.2022 в 18:55, ViGaCi сказал:

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

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

23 часа назад, ViGaCi сказал:

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

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

П.С. Извини что здесь ответил, хотел конкретные места процитировать.

Ссылка на комментарий
Поделиться на другие сайты

3 часа назад, dmitryartist сказал:

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

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

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

3 часа назад, dmitryartist сказал:

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

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

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

Дальше буду развивать игру уже отталкиваясь от этой сборки.

Изменено пользователем ViGaCi
Ссылка на комментарий
Поделиться на другие сайты

ГЕЙМДИЗАЙН
ресурсы

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

Age of Empires

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

Существует несколько видов ресурсов:

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

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

Command & Conquer

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

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

Total Annihilation

В игре существуют два вида ресурсов:

  • металл (используется для строительства зданий и производства юнитов).
  • энергия (используется для обслуживания зданий и содержания юнитов).

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

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

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

Новые идеи

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

Чего мне (как игроку) больше всего не хватает в классических RTS стратегиях, так это цепочек производства. Я говорю про такую механику, где у игрока один завод производит боеприпасы, другой делает стволы для танков и артиллерии, а третий собирает готовую технику из тех модулей, которые имеются в данный момент на складах.

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

Ссылка на комментарий
Поделиться на другие сайты

СТРОИТЕЛЬСТВО
теория и реализация

Все постройки в RTS стратегиях можно разделить на несколько основных типов:

  • административные (добыча ресурсов и обслуживание зданий)
  • производственные (производство юнитов)
  • оборонительные (защита базы)

Есть два разных способа строительства:

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

Разработка

В игру добавлены здания:

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

Здания бывают разных размеров:

  • 3x3 клетки (Штаб, Завод)
  • 2x2 клетки (Электростанция, Экстрактор)
  • 1x1 клетки (Турель)

Механика строительства:

  • игрок нажимает на кнопку "построить здание"
  • выбирает одну из предложенных в списке построек
  • размещает постройку в зоне строительства
  • подтверждает строительство
  • здание строится в течении некоторого времени

Чтобы построить здание, необходимо:

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

Зона строительства

  • Штаб и Электростанция формируют вокруг себя зону строительства
  • если ячейка находится на клетке с препятствием / тумане войны / клетку занял юнит, то такая клетка исключается из зоны строительства
  • здания нельзя строить рядом друг с другом (тайлы вокруг зданий тоже исключаются из зоны строительства)

 

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

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