На втором этапе у меня уже была база: персонаж двигался, камера работала, и проект перестал быть просто пустой сценой. Дальше началось самое интересное - я стал добавлять то, без чего рогалик вообще не ощущается как игра: врагов, урон, атаку, интерфейс и волны.
Первым делом я сделал самого простого врага, который просто идёт к игроку. И даже такая простая механика очень сильно меняет ощущение от проекта. Пока ты просто бегаешь по сцене - это скорее технический прототип. Но когда появляется объект, который целенаправленно тебя преследует, сцена сразу начинает восприниматься как игровая ситуация. Появляется давление, появляется задача, появляется напряжение.
Для этого я использовал отдельный скрипт EnemyChase. И здесь для меня был важный момент в плане программирования: каждая новая механика начала оформляться в отдельный класс.
Есть PlayerMovement для движения игрока.
Есть CameraFollow для камеры.
Есть EnemyChase для поведения врага.
Это очень полезный подход, потому что логика не сваливается в один огромный скрипт, а делится по ролям. Так проект становится понятнее и его легче развивать дальше.
Внутри врага использовались уже знакомые мне вещи: Transform, Rigidbody, Vector3 и FixedUpdate(). Враг получал ссылку на игрока через target, а потом вычислял направление до него:
Vector3 direction = target.position - rb.position;
Здесь хорошо видно, как в Unity работает движение через математику.
Позиция игрока - позиция врага = направление до цели.
Дальше это направление можно нормализовать через .normalized, чтобы получить именно направление без влияния расстояния. Это одна из базовых вещей в геймдеве: движение объекта - это не магия, а обычная работа с координатами и векторами.
Еще одна важная штука - direction.magnitude. Это свойство возвращает длину вектора, то есть расстояние до игрока. Благодаря этому я мог сделать stopDistance и остановить врага на нужной дистанции. То есть враг уже не просто ехал вперед, а вел себя более осмысленно.
Следующим большим шагом стали здоровье и урон. Вот тут игра начала ощущаться реально живой. Потому что появились последствия: игрок может получать урон, враг может наносить этот урон, а значит бой уже имеет смысл. Это уже не просто перемещение по сцене, а система, где можно проиграть.
Для этого я добавил PlayerHealth и EnemyDamage. И здесь мне уже стало понятнее, как строятся игровые системы. Логика здоровья была вынесена в отдельный скрипт, а значит здоровье стало самостоятельной системой, а не случайной переменной где-то в коде. Обычно в таких скриптах есть метод вроде TakeDamage(), который отвечает за уменьшение текущего здоровья. Это хороший принцип: не менять данные хаотично, а делать для этого отдельный понятный метод.
В уроне от врага использовался метод OnCollisionStay. Для меня это тоже был важный шаг, потому что я начал понимать, что Unity работает не только через Update() и FixedUpdate(), но и через событийные методы. То есть движок сам вызывает нужную функцию, когда происходит конкретное событие - например, столкновение. Это уже совсем другой уровень понимания системы.
Потом я сделал атаку игрока. И вот здесь проект стал ощущаться уже по-настоящему игровым. Теперь я не просто убегал от врагов, а мог отвечать. Как только у игрока появляется возможность атаковать, всё меняется: появляется цикл враг идёт к тебе -> ты выбираешь момент -> атакуешь -> враг погибает. И это уже минимальная, но настоящая боёвка.
Для атаки использовались EnemyHealth и PlayerAttack. Тут мне особенно понравилось, что в дело пошёл метод Physics.OverlapSphere(). Он проверяет объекты в определённом радиусе и позволяет делать удар по области. Ты задаёшь центр атаки и радиус, а Unity возвращает все коллайдеры, попавшие внутрь. Это очень удобный способ реализовать ближний бой.
Дальше в такой логике обычно используется массив целей и цикл foreach. Для меня это был уже важный шаг в понимании программирования:
foreach (Collider hit in hits)
{
// работа с каждым врагом
}
foreach позволяет пройтись по всем найденным объектам без ручной работы с индексами. И это очень полезный момент, потому что на этом этапе ты уже начинаешь работать не с одним объектом, а сразу с группой игровых сущностей.
Еще одна важная механика - attackCooldown. Без неё атаку можно было бы нажимать бесконечно каждый кадр. А с кулдауном у боя появляется ритм. С точки зрения кода это просто ограничение по времени, но с точки зрения игры это делает атаку осмысленным действием, а не бесконтрольным спамом.
После этого я добавил UI здоровья. И это оказался очень важный шаг. Пока здоровье существует только внутри переменной, это чисто техническая часть игры. Но как только оно выводится на экран, игра начинает общаться с игроком напрямую. Теперь уже видно, сколько у тебя жизней, насколько опасна ситуация и что вообще происходит во время боя.
Для этого я использовал Canvas, TextMeshPro и отдельный скрипт HealthUI. Здесь тоже проявился хороший принцип разработки:
один скрипт отвечает за логику здоровья,
другой - за отображение этого здоровья.
То есть данные и интерфейс лучше разделять, а не смешивать всё в одном месте. Это делает код чище и понятнее.
Когда один враг уже работал, следующим шагом стало добавить нескольких врагов. И вот это очень сильно меняет игру. Один враг - это проверка механики. Несколько врагов - это уже настоящее давление на игрока. Ты должен следить сразу за несколькими целями, двигаться аккуратнее и думать, кого атаковать первым.
Чтобы это работало удобно, я перешёл к Prefab и EnemySpawner.
Prefab в Unity - это шаблон объекта, который можно создавать много раз.
EnemySpawner - система, которая решает, где и когда эти враги будут появляться.
Это уже очень важный шаг, потому что проект начинает строиться не из отдельных объектов, а из систем, которые взаимодействуют друг с другом.
Дальше у меня появились точки спавна, ссылка на игрока как на target, а также связь со скриптом комнаты. И вот здесь проект уже начал ощущаться не как набор упражнений, а как цельная структура.
Спавнер создает врагов.
Враги знают, за кем гнаться.
Игрок умеет атаковать.
UI показывает состояние здоровья.
Комната отслеживает, закончился бой или нет.
Следующим важным шагом стала очистка комнаты. Это уже не просто механика, а элемент игрового дизайна. Появилось условие победы: убей всех врагов - и комната считается пройденной. Для этого использовался RoomManager, который следил за тем, сколько врагов ещё живо.
Здесь мне особенно понравилась идея методов RegisterEnemy() и UnregisterEnemy(). Это очень правильный подход.
Когда враг появляется - он регистрируется в системе комнаты.
Когда враг умирает - он удаляется из учёта.
Благодаря этому менеджер комнаты всегда знает актуальное состояние боя. Это уже не уровень "сделать объект", а уровень "сделать систему, которая управляет боем".
После очистки комнаты я добавил следующую волну врагов. И вот тут игра наконец начала ощущаться как арена, в которую можно реально заходить и пытаться выживать. Появились currentWave, счётчик живых врагов, запуск новой волны и увеличение количества противников. С точки зрения игрока это добавляет нарастающее напряжение, а с точки зрения разработки означает, что появился повторяющийся игровой цикл.
Здесь же использовался метод Invoke(), чтобы запускать следующую волну с задержкой. Это простая, но полезная штука: она позволяет выстраивать последовательность игровых событий без постоянных ручных проверок в Update().
Если коротко, то второй этап стал для меня переходом от "есть персонаж" к "есть игровой цикл".
Я добавил:
- врага
- здоровье
- урон
- атаку
- UI
- нескольких противников
- очистку комнаты
- волны
И именно в этот момент проект впервые стал похож не на технодемку, а на основу боевой игры.
Самое важное, что вместе с механиками росло и понимание программирования. Я на практике потрогал:
- отдельные классы
- ссылки между объектами
- событийные методы Unity
- физику
- массивы
- циклы
- prefab-подход
- менеджеры состояний
- логику игрового цикла
То есть я не просто "добавил врагов", а начал понимать, как вообще строятся игровые системы.
И вот это, наверное, главный итог второго дня. На первом этапе я оживил сцену. На втором - заставил её сопротивляться. А когда у тебя уже есть движение, враги, урон, атака и волны, ты начинаешь чувствовать, что дальше можно строить уже настоящий рогалик.