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

Создание пошаговой стратегии с нуля


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

Нашел для себя отличный способ развивать навыки разработки в Construct 3. Суть в том, чтобы делать клоны j2me игр. Помните, были в начале 2000-х кнопочные телефоны, под которые в своё время разрабатывались довольно неплохие игры. Доната в этих играх ещё не существовало, а потому разработчики старались придумать максимально хорошую игру, чтобы вы могли и сами поиграть и другу посоветовать.

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

Вот моя концепция:

  • ‌находим интересующую j2me игру
  • ‌достаём из неё всю графику
  • воссоздаём игру на Construct 3

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

Начать я решил с пошаговой стратегии Ancient Empires. Будет целый цикл небольших уроков, по итогу которых получится создать полный клон этой легендарной игры. Уроки рассчитаны на разработчиков с опытом, которые имеют базовые знания по Construct 3. А потому, я не буду подробно останавливаться на том, как работают функции, циклы или массивы.

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

СОДЕРЖАНИЕ
Перемещение юнитов

Сражение юнитов

Искусственный интеллект

(...)
Если вам интересна данная тема и вы будете ждать новые уроки — ставьте лайки! Так у меня будет больше мотивации работать над продолжением ?

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

Урок 1.1 Сетка для пошагового перемещения юнита
giphy.gif

Начнём с добавления объектов:

  • ‌Тайлмап с графикой для игрового поля
  • Тайлмап "TilePath" для сетки ходов
  • Спрайт "Unit"

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

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

Добавляем спрайту "Unit" переменную "MP", которая содержит числовое значение очков движения. Например, MP = 3 означает, что юнит за свой ход может пройти 3 тайла. При этом, каждый тайл должен иметь разную стоимость прохода. Например, тайл земли для прохода требует 1 очко, тайл леса 2 очка, а тайл гор 3. Таким образом, за ход юнит может пройти 3 тайла земли или 1 тайл земли и 1 тайл леса или 1 тайл гор.

Добавляем массив "PathCost", который считывает текстовые значения массива Terra и устанавливает числовые значения стоимости прохода для каждого тайла на всей карте.

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

IMG_20231103_172210.jpg
Генерация области движения

Добавляем функцию "TILEMAP > Generate Path", которая вызывается когда игрок нажимает на юнита.

Как работает функция:

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

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

Turn-Based Movement (with grid).c3p

Изменено пользователем ViGaCi
  • Like 1
  • класс! 1
  • супер! 1
Ссылка на комментарий

Урок 1.2 Две команды юнитов и система передачи хода
giphy.gif

Теперь нужно скопировать наш спрайт Unit и поместить копии на соседние клетки. Для того, чтобы у нас получились две разные команды юнитов, необходимо чтобы у каждой из команд был свой цвет. Но есть небольшая проблемка. В ресурсах игры я нашёл таблицу спрайтов только для синего игрока.
1_pak-0000000123.png

Мобильные игры начала 2000х распространялись по очень медленному тогда мобильному интернету. Разработчики старались сократить размер игры насколько это возможно. Вместо того, чтобы дублировать спрайты для каждой из команд (синий игрок, красный и т.д.), игра просто заменяла один цвет конкретных пикселей на другой. Чтобы не перерисовывать спрайты в графическом редакторе я решил пойти по тому же пути и использовал эффект "ReplaceSolidColor" для замены цветов.
Знімок екрана (104).png
Теперь, чтобы юниты друг от друга отличались не только визуально, но и программно, добавляем спрайту Unit переменную Team. То есть, если Team = 0, то перед нами юнит из синей команды, а если Team = 1, то юнит из красной команды. Далее добавляем глобальную переменную Team, которая будет соответствовать команде юнитов, которая ходит в данный момент. То есть, если Team = 0, то ходит синий игрок, а если Team = 1, то ходит красный игрок.

Наконец, добавляем спрайт TurnEndButton, который представляет собой кнопку завершения хода. По нажатию на этот спрайт глобальная переменная переключается между 0 и 1, проигрывается небольшая анимация кнопки и показывается всплывающая текстовая подсказка, какой игрок получает возможность ходить.
Знімок екрана (105).png
Кстати, данное действие я решил сделать через "custom actions" (пользовательское действие). Это очень удобное нововведение, которое было добавлено в Construct 3 относительно недавно. Custom actions позволяет реализовать всё то же самое, что вы могли бы сделать через функцию, с той лишь разницей, что пользовательское действие можно привязать к конкретному объекту. Это очень сильно упрощает работу с листом событий, когда у вас большой проект и вам нужно связать между собой много разных механик. Возможно, по этой теме можно даже отдельный урок сделать, пишите если вам это интересно.

В общем-то, на сегодня всё. Добавил ещё по мелочи анимацию тайлмапа (тайлы воды), создал контейнер для спрайта Unit и текстового индикатора с буквой "E", который отмечает, что конкретный юнит сделал свой ход. А ещё семью Units, которая нужна для одного единственного спрайта Unit и перенёс в эту семью все переменные. Для чего будет использоваться семья, об этом в следующем уроке.

Ancient Empires v.0.2.c3p

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

Урок 2.1 Механика боя
giphy.gif
Очень много работал над исходником, добавил ряд небольших механик для боевой системы.

Добавил для юнитов новые переменные:

  • HP (очки здоровья)
  • ATK (урон)
  • DEF (защита)
  • Range (дистанция атаки)

Также добавил снесколько пользовательских действий (custom actions) объекту Unit.
Знімок екрана (106).png

1. Check Target
Знімок екрана (107).png
С помощью этого действия происходит проверка, есть в в зоне досягаемости выбранного юнита подходящие цели. Подходящие, означает, что Team цели не должна быть равна Team выбранного юнита. То есть, цель и юнит должны находится в разных командах. Переменная "n" считает количество противников в зоне досягаемости. Если их количество > 0, то происходит вызов пользовательского действия "Create Menu".

2. Create Menu

Знімок екрана (109).png
Знімок екрана (108).png

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

3. Create AttackRange

Знімок екрана (110).png

Здесь всё просто. У каждого юнита есть переменная "Range", которая отвечает за дистанцию атаки юнита. Переменная текстовая, значение имеет формат "2-3", что означает зону атаки со 2 по 3 клетки (включительно). Так, например выглядит зона атаки катапульты.

Знімок екрана (111).png

Формула урона

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

Знімок екрана (110).png

Формула урона следующая: Здоровье (атакующего) x [Атака (атакующего) - Защита (цели)]. Проще говоря, чем больше здоровья у атакующего юнита - тем выше урон он наносит. Кроме того, в формуле урона используется функция tileStat, которая возвращает бонус к защите от местности, на которой находится юнит. Так, например, находясь на тайле гор юнит получает +3 к Защите, тайл леса даёт +2 к защите и т.д.

Знімок екрана (112).png

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

Ancient Empires v.0.3.c3p

Ссылка на комментарий

Урок 3.1 Закладываем фундамент для ИИ

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

(P.S. извиняюсь за постоянную тавтологию, но здесь крайне важна точность формулировок)

Этапы создания ИИ

  • создание генератора возможных ходов
  • создание оценочной функции
  • визуализация хода

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

giphy.gif

Напомню, что область перемещения генерируется за счёт волнового алгоритма, реализованого на массиве. Кратко опишу как работает волновой алгоритм.

Возьмите тетрадный лист в клеточку и нарисуйте квадрат размером 10х10 клеток. Далее внутри квадрата в случайном месте напишите цифру "0". Далее, на соседних с "0" четырёх клетках напишите цифру "1". Далее, на каждой соседней с "1" клетке напишите цифру "2". И так далее. Вот вам и весь волновой алгоритм.

В событиях, в которых воспроизводится волновой алгоритм я добавил вызов функции "ScoreCount"

Знімок екрана (119).png

Функция "ScoreCount" - это заготовка для будущей оценочной функции. Она добавляет варианты хода в отдельный массив "ScoreArray".

Знімок екрана (120).png

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

Знімок екрана (121).png

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

Ancient Empires (AI, v1).c3p

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

Урок 3.2 Расширяем возможности оценочной функции (часть 1)

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

В игре Ancient Empires некоторые тайлы дают бонусы к защите юнита. Например, тайл горы даёт +3 к защите, тайлы леса +2, тайлы земли +1, а тайлы дорог и мостов вообще не дают никаких бонусов. Если мы хотим сделать идеальный ИИ, то бот, наверное, должен избегать тайлов дорог и перемещаться только от одной горе к другой. В таком случае, бот будет иметь больше шансов на победу, но играть против него будет смертельно скучно.

А что, если мы заставим нашего бота вместо выбора наилучшего хода из возможных делать взвешеный выбор. Например, чтобы вероятность перемещения на тайл горы (+3 к защите) была выше, чем на тайл леса (+2 к защите), и выше, чем на тайлы дорог. То есть, каждый вариант хода будет иметь свой "вес". И чем "тяжелее" ход - тем выше вероятность, что бот выберет именно его.

Итак, вот у нас есть функция "tileStat", которая возвращает число бонуса к защите от указанного тайла. Так пусть значение бонуса от каждого тайла будет соответствовать "весу" этого тайла для бота при "принятии решения".

Знімок екрана (133).png

giphy.gif

Заметили аномалию? Бот совсем не хочет занимать тайл дороги. А всё потому, что тайл дороги имеет 0 очков бонуса к защите, и, соответственно, имеет нулевой вес и нулевую вероятность быть выбранным. Добавим в формулу +1. Теперь бот может перемещаться в том числе и на дороги.

Знімок екрана (134).png

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

Знімок екрана (138).png

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

source.gif

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

Знімок екрана (137).png

Таким образом, для атаки бот больше стремится занять тайл леса (+2 к защите), чем тайл земли (+1 к защите).

source.gif

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

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

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

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

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

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

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

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

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

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

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

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