Добавить в корзинуПозвонить
Найти в Дзене
Catrep Studio Dev Code

День 3. Как моя Unity-арена начала превращаться в настоящий рогалик

Все мои соцсети здесь: taplink.cc/catrepdev К третьему этапу у меня уже была рабочая база: движение, враги, атака, здоровье, волны. То есть игра уже перестала быть просто технодемкой. Но я очень быстро понял одну вещь - просто бегать по арене и отбиваться от волн недостаточно. Да, это уже похоже на игру, но это еще не тот рогалик, который хочется запускать снова и снова. Для этого нужна прогрессия, выбор, новые ситуации и ощущение, что каждый забег развивается по-своему. Именно этим я и занялся дальше. Первым большим шагом стали апгрейды между волнами. И вот это был реально важный момент. До этого каждая волна была просто следующим боем. А когда между ними появляется выбор улучшения, бой начинает работать уже не сам по себе, а как часть более большого цикла. Ты не просто выжил - ты получил шанс стать сильнее и изменить стиль следующего боя. Для этого у меня появились PlayerStats, обновлённые скрипты здоровья и интерфейса, а также UpgradePanel и UpgradeUI. С точки зрения программирова

Все мои соцсети здесь: taplink.cc/catrepdev

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

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

Для этого у меня появились PlayerStats, обновлённые скрипты здоровья и интерфейса, а также UpgradePanel и UpgradeUI. С точки зрения программирования это очень полезный шаг, потому что я начал работать уже не только с объектами на сцене, но и с системой выбора. То есть игра должна была не просто показать панель, а приостановить процесс, дать игроку варианты, дождаться решения, применить эффект и вернуть бой обратно. Это уже более сложная логика, чем просто "если нажал кнопку - ударил".

Здесь особенно важной стала работа с UI. Теперь интерфейс был нужен не только для отображения здоровья, но и для взаимодействия с игроком. Панель улучшений фактически стала отдельным игровым экраном внутри основного процесса. И это очень показательный момент: чем дальше двигаешься в геймдеве, тем больше понимаешь, что интерфейс - это не украшение, а часть механики. Через него игрок принимает решения, а значит он напрямую влияет на игровой цикл.

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

На уровне кода тут появились enum UpgradeType, класс данных UpgradeData, список всех возможных улучшений и логика выбора нескольких случайных вариантов. Это был очень полезный шаг в понимании программирования, потому что я начал работать уже не просто с отдельными переменными, а с типами данных и структурой контента.
То есть я не хардкодил каждое улучшение отдельно в стиле "если кнопка 1, то плюс 10 к здоровью", а начал мыслить системно:
есть
тип улучшения,
есть
данные улучшения,
есть
список возможных вариантов,
есть
метод применения эффекта.

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

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

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

С точки зрения Unity это был очень важный шаг в использовании prefab-подхода. У меня уже были разные заготовки врагов, и спавнер начал работать не с одним объектом, а с массивом GameObject[] enemyPrefabs. Это очень полезная идея: система спавна остается одной и той же, а контент внутри нее может меняться. То есть код становится более универсальным, а игра - богаче по содержанию.

-2

Когда появился дальний враг, в проекте пошли еще и снаряды. Это уже новый уровень механик, потому что в игре добавляется не просто "объект идёт к игроку", а отдельная сущность, которая появляется, летит, сталкивается и наносит эффект. По сути, пуля или магический снаряд - это тоже самостоятельная игровая система. Для этого использовались отдельные скрипты вроде EnemyBullet и EnemyShooter. И для меня это был важный сдвиг: я начал видеть, как одна механика рождает другую. Появляется дальний враг - значит появляется выстрел. Появляется выстрел - значит нужна логика попадания. Появляется логика попадания - значит надо учитывать дистанцию, ритм боя и реакцию игрока.

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

В коде dash был интересен тем, что здесь уже появилась работа с состояниями. Были переменные вроде isDashing, dashTimer, dashCooldown, а также методы вроде StartDash() и отдельная логика движения во время рывка. Для новичка это важный шаг, потому что ты начинаешь понимать: поведение персонажа - это не всегда один непрерывный режим. Иногда у него есть отдельные состояния, и в каждом из них игра должна вести себя по-разному. Обычное движение - одно состояние. Рывок - другое. Ожидание отката - третье.

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

Здесь в дело пошёл обновленный PlayerHealth с флагом isInvulnerable и методом SetInvulnerable(). Это хороший пример того, как одна система начинает взаимодействовать с другой. Логика dash находится в одном скрипте, а логика получения урона - в другом. Но во время рывка один скрипт временно сообщает другому: "сейчас урон применять нельзя". И вот именно такие связи между системами делают игру глубже.

Враги, дальники, ближник, быстрый моб. Сам игрок и хп бар
Враги, дальники, ближник, быстрый моб. Сам игрок и хп бар

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

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

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

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

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

Для этого в ExitPortal использовался массив строк с возможными сценами, например string[] possibleNextScenes, а затем случайный выбор одной из них. Это простой, но очень полезный пример того, как даже через базовые структуры данных можно добавить в игру ощущение разнообразия. Иногда не нужны сложные генераторы, чтобы проект стал интереснее - достаточно правильно использовать уже имеющиеся инструменты.

Портал и игрок. Вывод напдиси комната очищена
Портал и игрок. Вывод напдиси комната очищена

И вишенкой на этом этапе стали разные типы комнат. Когда я добавил RoomType, RoomDefinition и разделение на Combat, Reward, Rest и Elite, проект окончательно начал отходить от формата "одна и та же арена раз за разом". Появилась структура, где каждая следующая комната может нести разный смысл: где-то бой, где-то награда, где-то передышка, где-то сложный вызов. А это уже одна из самых вкусных частей рогалика - не просто сражаться, а двигаться по системе решений и состояний.

С точки зрения программирования это тоже был очень сильный этап. Я на практике потрогал enum для описания типов комнат и апгрейдов, serializable data-классы для хранения данных, списки и массивы для выбора контента, switch для применения разных эффектов, состояния персонажа вроде dash и неуязвимости, межсценовую логику через DontDestroyOnLoad, случайный выбор следующего шага и менеджеры, которые управляют не одной механикой, а целым этапом игры.

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

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