2 февраля 2023 2.02.23 13 3125

Как я делал свою первую игру

+25

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

Почему Unity?

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

Вы можете спросить меня: «А как же C#?» А он разве сложный? Весь код, который будет использоваться на начальном этапе есть в интернете. Тут главное понимать, что он делает.

«Но есть же Unreal» — может возразить юный хейтер, но где ты видел инди разработчика, который в одиночку создает игры? И не нужно приводить в пример корейца, который заканчивает очередную игру, пока ты спишь.

Как по мне, Unity будет намного проще на начальном этапе, так как с самого начала на нем учат делать 2D-игры.

Мотивация

Конечно же Деньги! Я зашел на Head Hunter и посмотрел вакансии. А чем я хуже? Вообще хорошей мотивацией могут стать различные ролики по Game Jam. Их на ютюбе навалом, можно смотреть не переставая.

Обучение

Итак, ролики я посмотрел. Что дальше? А дальше — просмотр обучающий роликов! Подойдут любого качества, главное чтобы тебе было понятно, правда от местного кода может стать плохо.

Я начал с курса от loftblog. Мало того, что в коде не было нормальной читаемой структуры, так он еще оператор if-else не перенес на след строчку!

Меня хватило на пять уроков, поэтому я решил создать новый проект и сделать все по-нормальному.

Концепция

У меня нет опыта в Unity, поэтому нужно сделать игру, которая будет простая, но с одной интересной механикой. Поразмыслив, я решил, что у меня будет персонаж, который движется вперед и прыгает через препятствия. Но затем, я сменил препятствия на специальные «шарики», при поедании которых персонаж увеличивается и уменьшается.

Выглядит довольно просто, теперь осталось нарисовать графику, анимации, меню и прочее. Звучит довольно просто.

Графика

Для рисования пиксель арта я использовал Aseprite. Программа несложная, правда я хотел использовать фотошоп. К сожалению, программа лагает при включении пиксельной сетки.

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

В итоге у меня получился вот такой набор:

Настройки для пиксельных картинок. Учите, что Pixels Per Unit — это размер вашей картинки. У меня 16×16.

Префабы

В Unity есть возможность рисовать префабами через Grid. Я перекинул объекты в Prefab и создал там палитру в новом гриде. Теперь открываем новую палитру в редакторе и перекидываем спрайты с префаба в редактор.

Чтобы ровно расположить объекты нужно использовать Box Collider 2D. Затем для рисования используйте GameObjectBrush. Вот подробное видео.

Для грида использую следующие настройки:

Прыжок

Прыжок реализован довольно просто, но с учетом гравитации. Более подробно можно прочитать здесь.

[SerializeField] private int jumpx;
[SerializeField] private int jumpy;
[SerializeField] public float fallingGravityScale;
[SerializeField] private float gravityScale;

if (Input.GetKeyDown(KeyCode.Space)
{
 rb.velocity = new Vector2(jumpx, jumpy);
 if (rb.velocity.y >= 0)
{
 rb.gravityScale = gravityScale;
}
 else if (rb.velocity.y < 0)
{
 rb.gravityScale = fallingGravityScale;
}

Звуки

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

Постпроцессинг

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

Для Post-proccess Layer нужно создать новый слой.

Канвас

В проекте у меня несколько канвасов. Для создания функции OnClick нужно перемещать сам конвас на кнопку, чтобы появились методы, которые вы накодили.

«Паралакс» сделал с учетом позиции камеры и скоростью игрока.

public class position : MonoBehaviour
{
    private Transform cameraTransform;
    public float speed;

    // Start is called before the first frame update
    void Start()
    {
        cameraTransform = Camera.main.transform;
    }

    // Update is called once per frame
    void Update()
    {
        if (cameraTransform.position.x >= 0)
        {
            transform.Translate(Vector2.right * speed * Time.deltaTime);   
        }

    if (player.speed == 0)
        {
            speed = 0;
        }
}

Камера

В игре используется плагин Cinemachine, поэтому нужно указать метод обновления камеры. В моем случае Last Update.

Сборка

Когда три уровня было готово, я начал собирать проект. Здесь я столкнулся с одной проблемой — у меня лагала игра. Я не мог понять в чем проблема, но потом выяснил, что в Project Settings — Physics 2D стоит Fixed Update, а у меня все вызовы перемещения через Update, поэтому игра лагала, но не только.

Еще был включен VSync, хотя после переключения в Physics 2D игра стала работать нормально, но я все равно его отключил.

Очень важно при сборке установить минимальное разрешение и режим работы приложения — В Окне. Иначе игра будет запускаться на полный экран т это неудобно. Минимальное разрешение в котором запускался проект — это 1280×720

Иконка

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

Сборка под Linux

Всегда хотел делать игры для линукс, поэтому собрал сборку без труда. Затем установил Ubuntu 22.10 на виртуальную машину (Virtual Box).

В настройках задал общую папку.

Для открытия папки без root потребуется вести команду, потом перезагрузи систему:

sudo adduser game vboxsf

Для запуска игры открой папку через терминал и запустите (файл должен быть исполняемым.)

chmod +x ./файл-игры — делает файл исполняемым.

./файл-игры — запуск игры.

Производительность так себе, учитывая объем памяти, но запуск проверить можно.

Игра

Rumle — это платформер раннер, состоящий из 5 гонок. Прыгай и собирай монетки. Игра полностью бесплатна.

Скачать игру.


Лучшие комментарии

Немного подушню.

В проекте у меня несколько канвасов. Для создания функции OnClick нужно перемещать сам конвас на кнопку, чтобы появились методы, которые вы накодили.

Эммммм… что? OnClick у Button'a позволяет вызвать публичные методы скормленного ему Object'a. Это необязательно должен быть именно Canvas. Да и вообще в идеале нужно подписываться и отписываться непосредственно в коде. Тогда если в игре что-нибудь отвалится можно будет быстро найти место возникновения бага, т.к. подписки и отписки будут находится в одном месте, а не будут разбросаны по кнопкам.

Здесь я столкнулся с одной проблемой — у меня лагала игра. Я не мог понять в чем проблема, но потом выяснил, что в Project Settings — Physics 2D стоит Fixed Update, а у меня все вызовы перемещения через Update, поэтому игра лагала, но не только.

Довольно странно, что из-за этого игра лагала. Но менять из-за этого FixedUpdate на Update в Physics2D… Вообще все просчёты физики, перемещения в том числе, выполняют именно в FixedUpdate для того, чтобы симуляция не зависела от FPS. FixedUpdate, в отличие от Update, вызывается фиксированное количество раз в секунду и из-за этого физика рассчитывается адекватно. Перемещения в Update не должны вызывать просадок FPS, вероятно дело в чём-то другом. Если бы я посмотрел весь код, то мог бы предположить почему игра лагала.

void Update()
{
if (cameraTransform.position.x >= 0)
{
transform.Translate(Vector2.right * speed * Time.deltaTime);
}

if (player.speed == 0)
{
speed = 0;
}
}

То есть слой «параллакса» будет перемещаться только если изначальная позиция камеры по «x» больше 0 и скорость игрока != 0? В игру не играл, но как понял — игра раннер, где персонаж бежит автоматически. Можно включать «слежение» параллакса за игроком в начале уровня и отключать в конце, либо при проигрыше. Если уровни маленькие, то можно тупо переключить режим отображения спрайта задника на «Tiled» и растянуть на всю длину уровня. Тогда следить вообще не надо будет.

Немного по стилистике кода. Названия классов, публичные поля, коих в идеале быть не должно, свойства, методы и прочее следует называть с заглавной буквы. Приватные же члены должны начинаться с "_" (например "_movementSpeed").

Ну и в конце субъективная вкусовщина. Прыжок. Лично мне кажется странным трогать гравитацию при расчётах прыжка. Гораздо удобнее вручную рассчитывать velocity у RigidBody. Например вот так:

private async UniTask UpdateAsync(CancellationToken token = default)
{
while (token.IsCancellationRequested == false)
{
if (_rigidbody.velocity.y < 0)
{
_rigidbody.velocity -= _gravityVector * Constants.FALL_MULTIPLIER * Time.fixedDeltaTime;
}
else if (_rigidbody.velocity.y > 0)
{
_rigidbody.velocity *= Constants.LINEAR_VELOCITY_SLOWDOWN_SPEED;
}

await UniTask.WaitForFixedUpdate();
}
}

И что по итогу? По итогу поздравляю с первым законченным проектом. Слайм выглядит мило, большинство популярных видосов по Unity стоит смотреть со скепсисом, не переставай пробовать и учиться и в скором времени у тебя начнут получаться потрясающие проекты. Удачи)

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

2) нужно разрешить нажимать кнопки и мышкой и клавиатурой, а то у тебя запуск игры

3) на эскейп надо нажать минимум 3-4 раза чтобы выйти)

4) слишком большой коллайдер на гг, монеты исчезают еще до его касания

5) мог бы и дать побольше жизней, типо пока они есть — рестарт с начала текущего лвл, когда кончились — рестарт с самого первого

6) монеты по факту не нужны, хоть бы стакал прогресс сбора за все уровни и в конце выдавал бы результат — Круто, ты собрал *число* монеток

7) зря отключил вертикалку, у меня твоё качающееся лого чуток рвалось

8) в игре на полный экран видно, что спрайты хреново апскейлятся и всё выглядит мутновато, ну или ты настроил не минимальное разрешение игры, а закрепил его в 720р, судя по мыльному лого Юнити

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

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

Совсем не то. Мало того что страшный «Ынтерпрайз.» это завод по производству пограмистов одной строчки и прочих ультра-узких специалистов, так ещё и рабочих мест то не особо много.

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

А вообще, в геймдеве деньги есть. Как профессиональный разработчик игр с 10-лентним стажем говорю.

Красавец. Положено начало хорошему хобби.

Спасибо за блог! Очень классно получилось. Сам пытаюсь изучать # и делать проекты в юньке. Желаю удачи в дальнейшем.

Выглядит симпатично. Но ещё много работы впереди. =) Я бы ещё предложил выкладывать веб-версию на страницу, так больше игроков её запустят. Не все захотят скачивать, распаковывать, запускать (просто лень будет или кто-то скажет «а вдруг вирусы?», и т.п.). Удачи! =)

Почему не GODOT? Он лучше как по мне подходит для 2д игр

В проекте у меня несколько канвасов. Для создания функции OnClick нужно перемещать сам конвас на кнопку, чтобы появились методы, которые вы накодили.

Канвас должен быть на окне, а не на конпке. На кнопку подписываться лучше в Awake монобеха.

Я зашел на Head Hanter и посмотрел вакансии. А чем я хуже?

Ну… как бы тебе сказать? :) Для начала тем что не знаешь как пишется слово «hunter».

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

Читай также