Как я игрульку создал: ч. 1 Предыстория и идея, ч. 2 Игрок и сборщик уровней
Часть 1. Предыстория и идея
Здравствуй, Хабр!
Я хочу поделиться опытом в создании одной гиперказуалки. Сам я, правда, ещё совсем зелен и юн на этой тернистой тропе игроделания, но может кому-то станет интересно и он прочтёт цикл этих статей. Самого кода здесь не будет, а если и будет, то в очень мизерных количествах, в связи с чем вряд-ли эти статьи будут интересны людям, которые хотят применить главную основу программирования «Ctrl+C/Ctrl+V» да и так как я сам новичок то заядлым «про» тут тоже будет скучновато, а плюсом на них может наложиться дебафф «BloodFromTheEyes» от порой наинеумнейших решений наиглупейших проблем. Но всё же опыт есть опыт, так что расскажу что есть.
Пожалуй, начну с рассказа как я до такого докатился.
Предыстория
В детстве у меня не было собственного компьютера, так что приходилось довольствоваться часом игры в вк-игры. Смартфон у меня тоже появился относительно поздно, но мне хватало и тех игр что были в кнопочном телефоне. Как таковым геймером я не был, а скоротать время на перемене вполне можно.
Позже, когда мне всё же купили ноутбук, меня всецело поглотил Minecraft года на 4. Наверно это была единственная игра которая мне так понравилась (и я всё ещё считаю её 1-й из лучших), так как там можно буквально всё.
Потом мне потихоньку надоело безвылазно сидеть в кубическом мире и я отдалился от него. Как раз в то время в школе началась информатика. Не то чтобы учительница была хорошо сведущая (перепутать блок питания и видеокарту это сильно), но основы Паскаля она заложить смогла. Это показало мне, что оказывается я могу довольно легко писать программы и игры в том числе, если выучу язык программирования, ведь это быстро и просто! (как же я ошибался…)
Так я захотел создать игру и немного почитав начал выбирать движок. Естественно мой взор пал на Unity. Могу выделить в нем такие плюсы как:
-
Простота, ведь и само меню и основной язык C# являются довольно лёгкими в обучении
-
Огромное количество статей, тем на форумах и видеоуроков по практически любой проблеме. (К примеру у UE видеоуроков на русском заметно меньше)
-
Я есть школота. Школота есть сила. Сила есть единство. Единство есть Unity!
Так, спустя немного времени, я получал 5 несколько четвертей подряд за созданную наспех игру. Сама игра было максимально простой. В игре были небольшие квадратные комнаты и коридоры, соединявшие этим комнаты. Игровое поле представляло собой массив этих комнат, соединённых коридорами (размер поля 16*16 комнат). В некоторых комнатах были монстры. Монстры были разные. Некоторые маленькие и слабые, но буквально прижимали к стенке количеством и затыкивали до смерти. Некоторые сносили почти всю полосу здоровья 1-м ударом, но были медленными и не могли покинуть свою комнату. Цель этой игры — собрать 5 ключей для открытия нужной комнаты и загнать туда 1-го монстра, который движется быстрее игрока и наносит 99 урона (максимальное здоровье — 100). Игрок мог умирать сколько хочет. Возрождался он в 1-й из 4х комнат, куда не могут зайти монстры в разных углах локации. Сама игра не была оснащена даже кнопкой выхода или настройками, но для школьных учителей информатики и этого хватало.
Кому интересно как «Это» выглядело, то вот:
Как я придумал идею
Так, я окончил школу и поступил в вуз. За это время я начинал по меньшей мере ещё 3 проекта и строил грандиозные планы по ААА проектам, которые взорвут сеть. Однако я всё же звёзд с неба не хватаю и принял решение выпустить игру на подобии прошлых гигантов, таких как Crossy Road и Geometry Dash. У первого я взял идею простоты, а у второго идею графики со светящимися в темноте цветами. Правда, по ходу создания друг подметил что больше всего игра напоминает другую классику — Doodle Jump.

Для создания этой игры я решил освободить максимум времени и отложил другие проекты. Теперь я почувствовал, что начал нечто, что должен закончить. Всё же неправильно интересоваться созданием игр и не выпустить ни одной.
Суть игры, как писалось выше, максимально простая. Нужно допрыгать так высоко вверх, как только возможно, но по мере увеличения высоты будут появляться новые виды и комбинации платформ. Чтобы игроку было не скучно, можно будет менять образы (Стандартный — «Ниндзя воды». Его можно заметить на изображении) и темы самой карты. Новые образы и темы можно будет получить с помощью «Рандомайзера», заплатив 100 монет, которые вы собрали на карте или получили, выполняя миссии.
Сами образы делятся на:
-
Стандартные. Их больше всего и шанс их выпадения около 74%
-
Редкие. Их поменьше. Шанс получить такой будет не больше 20%
-
Эпические. Красивые образы, шанс получить которые будет 5%
-
Легендарные. Название само говорит за себя. Шанс выпадения такого равен 1%.
-
Особые. Это образы событий или тематические. Шанс получить такой в рандомайзере всего 0,01%.
Подробнее об каждом компоненте и их реализации я расскажу в следующих статьях, а сейчас искренне благодарствую каждому за то, что уделили этой статье свои пару минут. Надеюсь, я смог заложить в вас хоть чуточку интереса и впредь буду рад делиться опытом создания этой игры!
Часть 2. Игрок и сборщик уровней

В прошлой части я рассказал как придумал идею и что из себя представляет эта игрулька. В этой же речь пойдёт о системе передвижения персонажа и сборщике уровней.
Дисклеймер: данная статья не является гайдом и не рекомендуется к прочтению профи из-за опасность улететь на своём кресле в стратосферу.
Игрок

Для начала разберёмся, что мы вообще хотим от игрока:
-
Должен прыгать и падать
-
Должен плавно перемещаться по горизонтальным поверхностям
Для простой реализации физики в Unity представлены компоненты Rigidbody и Character Controller. Первый представляет собой объект физического движка, а второй это скрипт, управляющий объектом. Изначально я начал делать персонажа с помощью Rigidbody, но уже на начальных этапах столкнулся с проблемой, когда персонаж сам по себе входил с стены, липнул ко всему подряд и в некоторых случаях перемещался рывками, поэтому было принято решение избавится от Rigidbody в пользу Character Controller.
Реализовывал гравитацию и передвижение я в двух методах:
В GamingGravity() я присваивал переменной gravityForse значение -50f, если персонаж не касается земли и -1f, если касается. Этого хватило, чтобы обеспечить довольно быстрое падение и не дать объекту самому оторваться от земли. Для проверки соприкосновения с землёй была использована одна из функций самого Caracter Controller: [chController].isGrounded возвращает true, если объект касается земли и false, если нет. Данные значения были умножены на Time.deltatime.
В методе CharacterMove() было реализовано всё остальное передвижение персонажа. В самом начале метода переменная типа Vector3 обнулялась [moveVector] = Vector3.zero, чтобы не переносить значения из прошлой работы метода.
Далее персонажу даётся возможность прыгать, если игрок касается земли и зажата левая кнопка мыши (На android работает как нажатие). Для самого прыжка присваиваем gravityForse значение 20f.
Следующим шагом даём игроку возможность перемещаться влево и право:
Если позиция мыши по оси х меньше начальной позиции, то переменной типа float присваиваем значение: [move] = ((startMausPos — Input.mousePosition.x) / 30f) * sensitivity, где sensitivity это переменная чувствительности, а 30f было подобрано испытательным методом, чтобы при sensitivity = 1 игрок перемещался с нужной скоростью. Далее нужно сделать проверку на максимальную скорость: Если наша скорость меньше максимальной, то присваиваем её отрицательное значение переменной [moveVector].x, в обратном случае присваиваем отрицательное значение максимальной скорости.
Если же позиция мыши по оси х меньше начальной позиции, то при присвоении значения переменной [move] вычитаем из текущей позиции начальную, а переменной [moveVector].x присваиваем не отрицательные, а исходные значения [move] и максимальной скорости.
Финальным этапом присваиваем [moveVector].y значение gravityForse.
Оба метода (GamingGravity() и CharacterMove()) вызываем в Update и радуемся передвижению нашего персонажа.
Генерация уровней

Все префабы уровней я подготовил заранее, так что в итоге у меня вышел этакий сборщик префабов. Из плюсов можно отметить гибкость в сборке: есть возможность выбирать какие уровни нельзя создать после текущего, выбрать тип уровня и его сложность. Из минусов нагромождение в коде от которого больно глазам, душе. пятой точке и соответственно креслу.
На сцене я создал объект Spawner и повесил на него скрипт, который и отвечает за саму сборку.
В начале скрипта располагается структура Lvls, которая содержит:
public GameObject thisLvl; — сам префаб уровня,
public GameObject[] impossibleLvl; — все префабы, которые нельзя поместить после этого уровня,
public GameObject posseblelvl; — префаб, который точно можно поместить. Он нужен для подстраховки.
Чтобы уровни были более разнообразными, я разделил их на 2 типа и 2 сложности: Y5 (его высота равняется 5) и Y10 (его высота равняется 10) и 1 и 2 сложность. Для каждого типа каждой сложности я создал массивы структуры Lvls. Так же добавил переменную сложности difficultyFactor с изначальным значением 0.
Чтобы генерировать не бесконечное количество уровней, а лишь на несколько шагов вперёд, я дал сборщику возможность передвигаться: если игрок ниже сборщика менее чем на 20 единиц, то сборщик запускает метод генерации уровня, а сам перемещается вверх на высоту этого уровня.
Теперь о самом процессе подбора уровня.
Когда игрок подобрался к сборщику менее чем на 20 единиц, то скрипт начинает определять какой уровень создать. Так как уровней типа Y5 меньше и они добавляют сложности игре, шанс их появления 30%, а остальные 70% остаются для Y10. С помощью рандома создаётся переменная и случайным образом выбирается 1 из типов. после выбора переменной отвечающей за сложность (у меня это difficultyFactor) прибавляется значение 1. Предположим выбран тип Y10.
Переносимся в метод SpawningY10(), где тут же отфутболиваемся в другой метод передав ему параметр 10 (высота уровня в Y10) для определения какой именно уровень выбрать. Этот дополнительный метод вызывается во всех методах спавна и принимает на вход нужную высоту. Он нужен для удобства чтения скрипта и даёт возможность выбирать к примеру из различных образов карты. Внутри этого метода выбираем какой сложности сгенерировать уровень. Если рандомная переменная (от 0 до 100) больше difficultyFactor, то сложность 1, если меньше, то 2. Выбранный префаб возвращается в метод SpawningY10(), После чего идёт проверка, есть ли этот новый уровень в массиве impossibleLvl от текущего. Если есть, то повторяем вызов метода для выбора уровня. Если же скрипт совершил более 50 повторений и всё ещё выбирает невозможные уровни, то генерируем объект для подстраховки, posseblelvl.
С помощью такого сборщика можно гибко настраивать сборку уровней по типу, сложности и даже менять образы карты.
Послесловие
Чтобы не затягивать статью в огромную ленту, пока остановлюсь на этом. В следующей части расскажу как я делал платформы с ловушками, на какие камни наступал и что в итоге вышло.
Всех благодарю за то, что уделили пару минут своего времени этой статье. До скорого!
Resident Evil Requiem стала игрой года на Golden Joystick Awards 2026, GTA VI не участвовала в премии
Прибыль Square Enix за первое полугодие 2026 финансового года выросла почти в три раза
Sony намерена сделать аниме одним из ключевых направлений бизнеса
Соавтор Path of Exile объяснил, почему Diablo V может разочаровать фанатов
GTA VI получила первые оценки — все игроки поставили игре высший балл
Евросоюз занялся микротранзакциями — игроки смогут отключать навязчивые покупки
State of Decay 3 меняется после ухода от Xbox — разработчики прислушались к игрокам
Weta Workshop начала принимать предзаказы на статую Короля-чародея Ангмара из «Властелина колец»