Unity

Разработка вашей первой игры с помощью Unity и C#. Часть 2

Адам Тьюлипер

Исходный код можно скачать по ссылке

Продукты и технологии:

Unity, C#, Microsoft .NET Framework

В статье рассматриваются:

  • работа с двухмерной графикой в Unity;
  • спрайты;
  • распространенная функциональность, в том числе коллайдеры, учет попаданий (очков) и анимация;
  • создание заготовок (prefabs) для повторного использования.

В первой статье я рассказал о некоторых основах и об архитектуре Unity. В этой статье я намерен исследовать работу с двухмерной графикой в Unity, которая опирается на поддержку двухмерной графики (далее для краткости 2D) в Unity, добавленную в версии 4.3. Вы могли работать с такой графикой и в Unity до версии 4.3, но этот процесс был весьма тяжелый без стороннего инструментария. Я хочу просто перетаскивать изображения в свою сцену, после чего она должна появляться в ней и работать, как ожидалось. Это как раз часть того, что предлагается в Unity 4.3, и в этой статье я рассмотрю другие возможности, разрабатывая базовую двухмерную игру-аркаду, что позволит вам освоить некоторые значимые концепции Unity.

2D в Unity

Чтобы получить поддержку 2D в Unity при создании нового проекта, выберите 2D из раскрывающегося списка в диалоге создания нового проекта. После этого все свойства проекта по умолчанию подстраиваются под 2D (можно увидеть в Edit | Project Settings | Editor), и любые изображения, импортируемые в ваш проект, становятся спрайтами, а не просто текстурами. (Об этом я расскажу подробнее в следующем разделе.) Кроме того, представление сцены переключается по умолчанию в режим 2D. На самом деле в этом режиме просто предоставляется вспомогательная кнопка, которая фиксирует две оси при разработке сцены, но никак не влияет на саму игру. Вы можете щелкнуть ее в любой момент, чтобы войти в режим 2D или выйти из него. 2D-игра в Unity реально остается 3D-средой — просто ваша работа ограничивается осями X и Y. На рис. 1 и 2 показаны варианты с выбранным режимом 2D и без него. Я выделил камеру, чтобы вы видели контуры области просмотра камеры, но она смотрит в пространство как фигура прямоугольной формы.

Режим 2D выбран — камера имеет фокус
Рис. 1. Режим 2D выбран — камера имеет фокус

Режим 2D не выбран — камера имеет фокус
Рис. 2. Режим 2D не выбран — камера имеет фокус

2D-игра в Unity реально остается 3D-средой — просто ваша работа ограничивается осями X и Y. 

Выделенная камера настроена как прямоугольная (orthographic camera) — это один из двух режимов камеры в Unity. Этот тип камеры, широко применяемый в 2D, не масштабирует объекты, отстоящие дальше от ваших глаз, т. е. нет глубины от позиции камеры. Другой тип камеры — перспектива (perspective), которая показывает объекты так, как их видят ваши глаза, с глубиной. Причин использовать каждый из типов камеры много, но, как правило, следует выбирать перспективу, когда требуется визуальная глубина, если только вы не хотите соответственно масштабировать свои объекты. Вы можете сменить тип камеры, просто выбрав камеру и изменив тип проекции. Советую опробовать это и посмотреть, как изменяется область просмотра вашей камеры, когда вы начинаете смещать объекты дальше от глаз по оси Z. Режим по умолчанию можно сменить в любой момент, что повлияет только на изображения, которые будут потом импортироваться в ваш проект.

Когда по умолчанию выбран режим 3D, изображения распознаются как тип Texture.

Если у вас есть существующий проект в Unity или если вы не уверены, выбран ли режим 2D в диалоге проекта, то можете задать свойствам проекта значения по умолчанию для 2D через Edit | Project Settings | Editor; иначе вам придется вручную задавать тип каждого импортируемого вами 2D-изображения, что несколько утомительно при большом количестве изображений.

Все дело в спрайте

Когда по умолчанию выбран режим 3D, изображения распознаются как тип Texture. Перетащить текстуру в сцену нельзя; текстура должна быть применена к какому-то объекту. Создавать 2D-игры таким путем вовсе не забавно. Я хочу просто перетаскивать изображения, чтобы они появлялись в моей сцене. Однако, если режим по умолчанию — 2D, все становится проще. Теперь, когда я перетаскиваю изображение в Unity, оно распознается как тип Sprite.

Это позволяет перетаскивать в Unity все изображения, образующие графику игры, а затем из Unity в сцену. Если какие-то изображения выглядят мелкими, то вместо их масштабирования везде, где они встречаются, вы можете просто уменьшить значение Pixels To Units. Это очень распространенная операция в Unity как для 2D, так и для 3D и обычно более производительная, чем масштабирование объектов через свойство scale преобразования.

Отпуская объекты, вы наверняка заметите, что один объект оказывается поверх другого. Unity на внутреннем уровне создает серию вершин, даже для 2D-изображений, поэтому порядок рисования может различаться в разных частях изображений. Всегда лучше явно указывать z-порядок своих изображений. Это делается одним из трех методов, перечисленных в порядке, в котором Unity рисует ваши спрайты.

  1. Вы задаете свойство Sorting Layer в Sprite Renderer.
  2. Вы задаете свойство Order in layer в Sprite Renderer.
  3. Вы задаете значение позиции по оси Z в Transform.

Уровень сортировки имеет высший приоритет, за ним следует порядок в уровне, а затем z-значение в преобразовании.

Уровни сортировки рисуются в порядке определения. Когда вы добавляете другие уровни (в Edit | Project Settings | Tags and Layers), Unity сначала рисует любой объект, который обнаруживается в уровне Default (затем учитывается Order in Layer, потом — значение позиции по оси Z в Transform), далее Background, Platforms и т. д. Поэтому вы можете легко поправить перекрытие объектов, присвоив их уровню Platforms, а объекту, который должен быть поверх, указав Order in Layer со значением 1; тогда он будет нарисован после всего, что имеет Order in Layer, равный 0.

Распространенная функциональность

На рис. 3 показан уровень, содержащий некоторые изображения платформ и фона, которые были созданы перетаскиванием и заданием уровней сортировки (sorting layers).

Игровой уровень
Рис. 3. Игровой уровень

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

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

void Update()
{
  // Returns -1 to 1
  var horizontal = Input.GetAxis("Horizontal");
  // Возвращает true или false. Событие щелчка левой кнопки
  // мыши или касания на мобильном устройстве вызывает
  // срабатывание этого.
  var firing = Input.GetButtonDown("Fire1");
}

Если вы проверите Edit | Project Settings | Input, то увидите варианты ввода по умолчанию (Unity предоставляет целый набор таких вариантов в каждом новом проекте) и сможете задать новые. На рис. 4 показаны умолчания для считывания перемещения по горизонтали. Параметры left и right представляют клавиши-стрелки «влево» и «вправо», но заметьте, что для перемещения по горизонтали используются «a» и «d». Их можно сопоставить со вводом от джойстика. Вы можете добавить новые значения или изменить умолчания. Поле Sensitivity контролирует, насколько быстро Unity будет проходить от 0 до 1 или –1. При нажатии стрелки вправо первый кадр может получить значение .01, а затем возможно довольно быстрое ускорение до 1, хотя скорость можно подстроить так, чтобы игровой персонаж мгновенно получал горизонтальную скорость. Вскоре я покажу код для применения этих значений к вашим игровым объектам. Для чтения этих значений необходимость в компоненте GameObject на самом деле нет; вы просто используете ключевое слово Input в своем коде для доступа к функциональности, обеспечивающей чтение ввода. Как общее правило, ввод следует считывать в функции Update в противоположность FixedUpdate, чтобы избежать потери событий ввода.

Значения по умолчанию для ввода перемещений по горизонтали
Рис. 4. Значения по умолчанию для ввода перемещений по горизонтали

Линейное перемещение Вещи нужно иметь возможность перемещать. Если это игра, где экран прокручивается сверху вниз (top-down game), то гравитация обычно не играет важной роли. Если же это аркада (platformer), гравитация, наоборот, крайне важна. В любом случае обнаружение коллизии объектов весьма критично. Вот базовые правила. Компонент Rigidbody2D или RigidBody (используется для 3D), добавленный к игровому объекту, автоматически придаст ему массу, сделает его поддерживающим гравитацию и способным реагировать на прикладываемые к нему силы. Согласно Википедии: «В физике абсолютно твердое тело (rigid body) является идеализацией твердого тела (solid body), в котором пренебрегается деформацией. Другими словами, расстояние между любыми двумя данными точками абсолютно твердого тела остается постоянным во времени независимо от действующих на него внешних сил». Тот же принцип применяется в играх. Добавление абсолютно твердого тела позволяет вам делает вызовы наподобие показанных на рис. 5.

Рис. 5. Добавление перемещения и скорости

void FixedUpdate()
{
  // Значение от -1 до 1 для перемещения по горизонтали
  float moveHorizontal = Input.GetAxis("Horizontal");
  // Vector просто дает вам значение x,y,z, например 1,0,0
  // для макс. смещения вправо, 0,1,0 для макс. смещения вверх.
  // Сохраняйте текущее Y-значение, которое увеличивается
  // для каждого интервала из-за гравитации.
  var movement = new Vector3(moveHorizontal * 
   _moveSpeed, rigidbody.velocity.y, 0);
  rigidbody.velocity = movement;
  if (Input.GetButtonDown("Fire1"))
  {
    rigidbody.AddForce(0, _jumpForce, 0);
  }
}

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

Обнаружение коллизий Объект получает массу от своего компонента RigidBody, но, кроме того, вы должны сообщить Unity, как обрабатывать коллизии с этим объектом. Здесь размер и форма ваших изображений или моделей не имеют значения, хотя масштабирование все же влияет на физику самого объекта. Важны размер и форма компонента коллайдера (collider component), который представляет собой просто определенную область вокруг или внутри объекта, для которого нужно, чтобы Unity обнаруживала соприкосновение с другим объектом. Это обеспечивает поддержку таких ситуаций, когда вы входите в область неактивного зомби или когда при приближении к горе на вас скатывается валун.

Коллайдеры бывают самых разнообразных форм. Коллайдер для 2D может быть окружностью, границей (гранью), многоугольником или прямоугольником. Прямоугольные коллайдеры хороши для объектов с формой наподобие квадратов или прямоугольников, или когда вы просто хотите обнаруживать коллизии в квадратной области. Подумайте о платформе, на которой вы стоите, — это хороший пример прямоугольного коллайдера. Простое добавление этого компонента к вашему игровому объекту позволяет задействовать преимущества физических столкновений. На рис. 6 я добавил персонажу коллайдер в виде окружности и абсолютно твердое тело, а к платформе — прямоугольный коллайдер. Когда я запускаю игру в Editor, игрок немедленно падает на платформу и останавливается. Никакого кода не требуется.

Добавление коллайдеров
Рис. 6. Добавление коллайдеров

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

Объект получает массу от своего компонента RigidBody, но, кроме того, вы должны сообщить Unity, как обрабатывать коллизии с этим объектом. 

Если я хочу, чтобы Unity вызывала мой код, когда впервые происходит этот случай коллизии, то просто добавляю следующий код в игровой объект через компонент скрипта (о нем мы говорили в предыдущей статье):

void OnCollisionEnter2D(Collision2D collision)
{
  // Если вы хотите проверять, с кем вы столкнулись,
  // то, как правило, должны использовать теги, а не имена
  if (collision.gameObject.tag == "Platform")
  {
    // Отыгрываем звуки шагов или приземления
  }
}

Триггеры Иногда нужно обнаруживать коллизию, но безо всякой физики. Возьмите такую ситуацию, когда вы подбираете в игре какой-то ценный предмет. Вы же не хотите, чтобы монеты разлетелись перед игроком, когда он подойдет к ним; вам нужно, чтобы монеты были собраны и никак не мешали перемещению игрока. В этом случае используется коллайдер, который называется триггером. Это не более чем коллайдер с помеченным флажком IsTrigger в его свойствах. Тем самым физика отключается, и Unity будет лишь вызывать ваш код, когда объект A (содержащий коллайдер) попадет в область объекта B (тоже содержащего коллайдер). В данном случае в коде применяется метод OnTriggerEnter2D вместо OnCollisionEnter2D:

void OnTriggerEnter2D(Collider2D collider)
{
  // Если игрок попадает на триггер
  if (collider.gameObject.tag == "Player")
  {
    // О контроллере игры расскажу чуть позже
    GameController.Score++;
    // Не вызывайте Destroy(this); поскольку this - это
    // компонент скрипта в игровом объекте, вы используете
    // this.gameObject или просто gameObject, чтобы
    // уничтожить объект
    Destroy(gameObject);
  }
}

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

Одна вещь, о которую часто спотыкаются разработчики-новички, — поведение абсолютно жестких тел при добавлении к ним коллайдеров. Если в моем объекте есть коллайдер, имеющий форму окружности, и я помещаю этот объект на наклонную плоскость (как указывается формой ее коллайдера), он начинает катиться (рис. 7). Это моделирует то, что вы видите в физическом мире, когда колесо попадает на склон. Я не использую прямоугольный коллайдер для своего персонажа из-за того, что у этого коллайдера есть границы, которые могут задевать границы других коллайдеров, что будет приводить к перемещению с рывками. Коллайдер с формой окружности обеспечивает более плавное перемещение. Однако, когда плавное вращение неприемлемо, вы можете использовать параметр Fixed Angle в компоненте Rigidbody.

Применение коллайдера с формой окружности для плавного перемещения
Рис. 7. Применение коллайдера с формой окружности для плавного перемещения

Звук Чтобы слышать звук, нужен компонент Audio Listener, который по умолчанию существует в любой камере. Для проигрывания звука просто добавьте компонент Audio Source к игровому объекту и укажите аудиоклип. Unity поддерживает большинство основных форматов звука и будет кодировать более длинные клипы в MP3. Если у вас множество источников звука с клипами, назначенными в Unity Editor, учитывайте, что все они будут загружены в период выполнения. Вместо этого вы можете загружать звук через код, размещенный в специальной папке ресурсов и уничтожать его, когда он больше не нужен.

Импортировав звук в свой проект, я сохранил его как WAV-файл, который представляет собой несжатое аудио. Unity перекодирует более длинный звук для оптимизации, поэтому всегда используйте звук максимального качества, которым вы располагаете. Это особенно верно для коротких файлов вроде звуковых эффектов, которые Unity не станет кодировать. Я также добавил компонент Audio Source к своей главной камере, хотя мог бы добавить его к любому игровому объекту. Затем я назначил аудиоклип Adventure этому компоненту Audio Source и сбросил флажок Loop, поэтому он постоянно проигрывается как петля. Три простых шага, и теперь в игре есть фоновая музыка.

GUI/элементы HUD (Heads-Up Display) Система GUI может охватывать многие вещи в игре. Она может включать систему меню, индикатор здоровья, текущий счет, арсенал оружия и др. Как правило, систему GUI вы постоянно видите на экране независимо от того, куда смотрит камера (хотя это не обязательно). GUI-функционал в Unity в настоящее время полностью перерабатывается, и в Unity 4.6 появится новая система uGUI. Поскольку эта версия еще не вышла, мы рассмотрим здесь лишь некоторую базовую функциональность, но, если вас интересуют подробности о новой системе GUI, загляните в мой блог на channel9 по ссылке channel9.msdn.com/Blogs/AdamTuliper.

Чтобы вывести на экран простой текстовый дисплей (например, score: 0), я открыл Game Object | Create Other | GUI Text. Этой команды в Unity 4.6 больше нет, поэтому советую посмотреть видеоролик по uGUI, о котором я упоминал. В версии 4.6 по-прежнему можно добавить компонент GUI Text к игровому объекту, щелкнув кнопку Add Component; он просто убран из меню Editor. В существующей (устаревшей) системе GUI в Unity вы не можете увидеть свои GUI-объекты в представлении сцены — только в представлении Game, что превращает создание разметки в несколько странное занятие. Если хотите, используйте чисто программный подход к настройке своего GUI, и для этого есть класс GUILayout, позволяющий автоматически отслеживать виджеты. Но я предпочитаю систему GUI, где можно легко работать, используя мышь; вот почему я нахожу гораздо совершеннее систему uGUI. (До uGUI лидером в этой области был довольно основательный сторонний продукт — NGUI, который и задействовали как исходную кодовую базу для uGUI.)

Самый простой способ обновлять текстовый дисплей — найти и назначить в Editor ссылку на игровой объект с этим GUIText и обрабатывать его подобно метке в .NET, обновляя его свойство text:

void UpdateScore()
{
  var score = GameObject.Find("Score").GetComponent<GUIText>();
  score.text = "Score: 0";
}

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

Отслеживание счета Это несложная задача. У вас просто есть класс, предоставляющий открытый метод или свойство, с помощью которого задается счет. В играх обычно есть объект Game Controller, действующий как организатор игры. Game Controller может отвечать за инициацию сохранений игры, загрузку, учет текущего счета и др. В этом примере у меня есть класс, предоставляющий переменную score, как показано на рис. 8. Я назначаю этот компонент пустому игровому объекту, чтобы он был доступен при загрузке сцены. Когда счет обновляется, происходит обновление и GUI. Переменная _scoreText назначена в Unity Editor. Просто перетащите любой игровой объект с GUIText на это поле или используйте виджет поиска, где данный компонент скриптов предоставляет переменную Score Text в редакторе.

Рис. 8. Создание переменной _scoreText

public class GameController : MonoBehaviour
{
  private int _score;
  // Перетащите игровой объект GuiText на это предоставляемое
  // в Editor поле или ищите его при запуске, как на рис. 12
  [SerializeField]
  private GUIText _scoreText;
  void Start()
  {
    if (_scoreText == null)
    {
      Debug.LogError("Missing the GuiText reference. ");
    }
  }
  public int Score
  {
    get { return _score; }
    set
    {
      _score = value;
        // Обновляем счет на экране
      _scoreText.text = string.Format("Score: {0}", _score);
    }
  }
}

После этого я могу просто обновить (в данном примере) код триггера гриба для увеличения счета при каждом подборе ценного предмета:

void OnTriggerEnter2D(Collider2D collider)
{
  if (collider.gameObject.tag == "Player")
  {
    GameController.Score++;
    Destroy(gameObject);
  }
}

Анимации Как и в XAML, анимации создаются выполнением различных действий в ключевых кадрах. Я мог бы легко посвятить целую статью одним только анимациям в Unity, но буду краток из-за нехватки места. В Unity есть две системы анимации: устаревшая и более новая — Mecanim. В устаревшей системе используются файлы анимации (.ani), а в Mecanim — состояния, управляющие тем, какой файл анимации воспроизводится.

В двухмерной графике по умолчанию применяется Mecanim. Самый простой способ создать анимацию — перетащить изображения в сцену и разрешить Unity создать анимацию за вас. Для начала я перетащил некоторые отдельные спрайты в Unity, а та в свою очередь создала за меня несколько вещей. Прежде всего она создала игровой объект с компонентом рендера спрайтов (sprite renderer component) для рисования спрайтов. Затем — файл анимации. Вы можете увидеть это, перейдя в Window | Animator и выделив свой игровой объект. Аниматор показывает назначенный файл анимации, который в моем случае содержит шесть ключевых кадров, поскольку я перетащил в сцену шесть изображений. Каждый ключевой кадр контролирует один или более параметров в каком-либо компоненте; здесь изменяется свойство Sprite компонента Sprite Renderer. Анимации — это не более чем отдельные изображения, показываемые с некоей частотой, воспринимаемой глазом как движущиеся картинки.

Далее Unity создала компонент Animator в игровом объекте, как показано на рис. 9.

Компонент Animator, указывающий на контроллер
Рис. 9. Компонент Animator, указывающий на контроллер

Этот компонент указывает на простой конечный автомат, называемый контроллером анимации. Это файл, создаваемый Unity, который просто показывает состояние по умолчанию; иначе говоря, он всегда находится в состоянии «idle» («простаивает»), так как это единственное доступное состояние. Это состояние простоя ничего не делает, а просто указывает на мой файл анимации. На рис. 10 представлены реальные данные ключевых кадров на временном графике.

{Рисунок: здесь нужно перевести надпись Each keyframe changes the image — Каждый ключевой кадр выполняет смену изображения}


Рис. 10. Анимационные данные в простое

Может показаться, что для подготовки анимации требуется много усилий. Однако мощь конечных автоматов в том, что вы можете управлять ими, задавая простые переменные. Вспомните: состояние не делает ничего — только указывает на файл анимации (хотя в 3D можно изощряться и делать такие вещи, как смешивание анимаций).

Затем я взял больше изображений, что создать анимацию run (run animation) и перетащил их на свой игровой объект Yeti. Так как у меня уже есть компонент аниматора в этом объекте, Unity просто создает новый файл анимации и добавляет новое состояние «run» («выполняется»). Я могу просто щелкнуть правой кнопкой мыши состояние idle и создать переход к run. При этом появляется стрелка между состояниями idle и run. Далее можно добавить новую переменную Running, использовать которую очень легко: вы просто щелкаете стрелку между состояниями и изменяете условие использования этой переменной, как показано на рис. 11.

Смена состояний из idle в run
Рис. 11. Смена состояний из idle в run

Когда Running становится равной true, анимация idle сменяется анимацией run, что означает лишь воспроизведение файла анимации с состоянием run. Вы можете легко контролировать эти переменные в коде. Если вы хотите запустить свою анимацию run инициацией состояния run при щелчке кнопки мыши, то можете добавить код, приведенный на рис. 12.

Рис. 12. Смена состояния программным способом

private Animator _animator;
void Awake()
{
    // Кешируем ссылку на компонент Animator
    // из этого игрового объекта
    _animator = GetComponent<Animator>();
}
void Update()
{
  if (Input.GetButtonDown("Fire1"))
  {
    // Это заставит контроллер анимации перейти
    // из состояния idle в состояние run
    _animator.SetBool("Running", true);
  }
}

В моем примере я использовал отдельные спрайты для создания анимации. Однако довольно часто используют ленту спрайтов (sprite sheet) — один файл более чем с одним изображением в нем. Unity поддерживает ленты спрайтов, так что достаточно сообщить Unity, как разделить на части ваш спрайт, а затем включить эти части в вашу сцену. В этом случае от вас потребуется выполнить ряд операций: сменить в свойствах спрайта Sprite Mode с Single на Multiple и открыть Sprite Editor, который потом сможет автоматически поделить спрайт и применить изменения, как показано на рис. 13. Наконец, вы раскрываете спрайт (в режиме просмотра проекта на значке спрайта есть небольшая стрелка), выделяете полученные спрайты и перетаскиваете их в свою сцену, как обычно.

Создание ленты спрайтов
Рис. 13. Создание ленты спрайтов

Анимация может быть делом сложным, пока вы не поймете систему. Подробности см. в моем блоге на channel9 или один из многих превосходных ресурсов на сайте обучения Unity.

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

void OnTriggerEnter2D(Collider2D collider)
{
  // Если игрок попадает на триггер
  if (collider.gameObject.tag == "Player")
  {
    // Перезагружаем текущий уровень
    Application.LoadLevel(Application.loadedLevel);
   // Вместо этого можно было бы
    // передать имя сцены для загрузки:
    // Application.LoadLevel("Level2");
  }
}

Игровой объект и его соответствующие свойства показаны на рис. 14. Заметьте, что высота коллайдера достаточно велика, чтобы игрок не мог перепрыгнуть через него, и, кроме того, этот коллайдер настроен как триггер.

Игровой объект и его свойства
Рис. 14. Игровой объект и его свойства

Ход игры (game play) В просто 2D-игре вроде этой поток управления довольно прямолинеен. Игрок начинает игру. Гравитация абсолютно твердого тела заставляет персонаж в игре упасть. У персонажа и платформы есть по коллайдеру, поэтому персонаж останавливается. Считывается сенсорный ввод, от клавиатуры и мыши, что приводит к перемещению игрового персонажа. Игрок перепрыгивает между платформами с помощью rigidbody.AddForce, который заставляет персонаж прыгнуть, и перемещается влево и вправо за счет считывания Input.GetAxis("Horizontal") и его применения к rigidbody.velocity. Игрок собирает грибы, которые являются коллайдерами, настроенными как триггеры. Когда игрок касается их, они увеличивают счет и разрушаются. Как только игрок доходит до финала уровня, срабатывает триггер, перезагружающий текущий уровень. Здесь следовало бы добавить большой коллайдер под землей, чтобы обнаруживать, когда игрок сваливается с платформы, и просто перезагружать уровень.

Заготовки (prefabs) Повторное использование важно как в кодировании, так и в дизайне. Назначив своим игровым объектам несколько компонентов и настроив их, вы будете часто использовать их снова и снова в рамках одной сцены или даже нескольких сцен либо игр. Вы можете создать другой экземпляр игрового объекта в сцене, но также можете создать экземпляр заготовки, которой пока нет в вашей сцене. Возьмем, к примеру, платформы и их коллайдеры. Если вы хотите повторно использовать их в других сценах, то, увы, на данный момент это невозможно. Но, создав заготовки, вы получаете нужную возможность. Просто перетащите любой игровой объект из иерархии обратно в папку проекта, и будет создан новый файл с расширением .prefab, содержащий любые дочерние иерархии. Теперь вы можете перетаскивать этот файл в другие сцены и повторно использовать его. Исходный игровой объект теперь оказывается соединенным с заготовкой. Обновление файла .prefab обновляет все экземпляры в ваших сценах; кроме того, вы можете оправлять изменения из модифицированной заготовки сцены обратно в файл .prefab.

Щелкнув заготовку, вы увидите содержащиеся в нем игровые объекты, как показано на рис. 15. Если вы внесете здесь изменения, все экземпляры в вашей сцене будут обновлены.

Просмотр содержимого заготовки
Рис. 15. Просмотр содержимого заготовки

Заключение

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

Дополнительные материалы для изучения


Адам Тьюлипер (Adam Tuliper)старший идеолог по технологиям в Microsoft; живет в солнечной Южной Калифорнии. Разработчик инди-игр, один из администраторов Orange County Unity Meetup и автор на pluralsight.com. Скоро в его семье появится третий ребенок, так что связывайтесь с ним, пока у него еще есть свободные минуты, по адресу adamt@microsoft.com или через twitter.com/AdamTuliper.

{Для верстки: в последней фамилии (литовской) есть диакритический знак, не потеряйте}

Выражаю благодарность за рецензирование статьи экспертам Мэтту Ньюмену (Matt Newman) из Subscience Studios и Тоутвидасу Цилису (Tautvydas Žilys) из Unity.