Статьи

Разработайте игру в стиле Monkey Ball с Unity

Конечный продукт
Что вы будете создавать

В этом уроке вы узнаете, как создать мобильную 3D-игру с использованием C # и Unity. Цель игры — использовать акселерометр для перемещения мяча и достижения портала.

Из этого руководства вы узнаете о следующих аспектах разработки игр Unity:

  • 3D Примитивы
  • акселерометр управления
  • движение камеры
  • физика
  • GUI текстуры

Откройте Unity и выберите « Новый проект» в меню « Файл», чтобы открыть диалоговое окно нового проекта. Сообщите Unity, где вы хотите сохранить проект, и установите   Установите значения по умолчанию для: меню в 3D .


На следующем шаге вам будет представлен пользовательский интерфейс Unity. Настройте проект для мобильной разработки, выбрав « Настройки сборки» в меню « Файл» и выбрав нужную платформу.


Первое, что нам нужно сделать после выбора целевой платформы, это выбрать размер рисунка, который мы будем использовать в игре. Это поможет нам выбрать правильный размер для 3D текстур и 2D GUI, не делая размытые изображения или использовать текстуры, которые слишком велики для целевого устройства. Например, изображение должно иметь более высокое разрешение, если вы ориентируетесь на iPad с дисплеем Retina, чем на Lumia 520.

  • iPad без сетчатки: 1024 x 768 пикселей
  • iPad с сетчаткой : 2048px x 1536px
  • 3,5 «iPhone / iPod Touch без сетчатки: 320px x 480px
  • 3,5 «iPhone / iPod с сетчаткой : 960px x 640px
  • 4 «iPhone / iPod Touch: 1136 пикселей x 640 пикселей

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

  • Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
  • Motorola Droid X: 854 x 480 пикселей, 228 ppi
  • Samsung Galaxy SIII: 720px x 1280px, 306 ppi
  • Blackberry Z10 : 720px x 1280px, 355 ppi
  • Nokia Lumia 520 : 400 пикселей на 800 пикселей, 233 пикселей на дюйм
  • Nokia Lumia 1520 : 1080px x 1920px, 367 ppi

Обратите внимание, что код, который мы напишем в этом руководстве, можно использовать для работы с любой из платформ.


В зависимости от целевых устройств вам может потребоваться преобразовать иллюстрацию в рекомендуемый размер и плотность пикселей. Вы можете сделать это в вашем любимом графическом редакторе. Я использовал функцию « Настроить размер …» в меню « Инструменты» в приложении предварительного просмотра OS X.


Вы можете изменить разрешение, отображаемое на панели « Игра» .


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


Вы можете использовать один из трех языков программирования при использовании Unity, C # , UnityScript , разновидности JavaScript и Boo . У каждого языка программирования есть свои плюсы и минусы, и вам решать, какой из них вы предпочитаете. Мои личные предпочтения относятся к языку программирования C #, поэтому я буду использовать этот язык в этом руководстве.

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


Я буду использовать несколько звуков, чтобы улучшить слуховой опыт игры. Звуковые эффекты, используемые в этом руководстве, были получены от playonloop.com и Freesound .


Для создания нашей игры нам сначала нужно получить наши 3D модели. Я рекомендую 3docean для высококачественных моделей, текстур и многого другого, но если вы тестируете или изучаете, то несколько хороших моделей также хороши. Модели в этом руководстве были загружены из SketchUp 3D Warehouse, где вы можете найти множество разнообразных моделей.

Теперь, когда Unity не распознает формат файла SketchUp, нам нужно преобразовать его во что-то, что Unity может импортировать. Сначала нам нужно скачать бесплатную версию SketchUp, которая называется SketchUp Make .

Откройте 3D-модель в SketchUp Make, выберите « Экспорт»> «3D-модель» в меню « Файл» и выберите Collada (* .dae) .

Выберите имя и местоположение и нажмите кнопку «Сохранить». Это создаст файл и папку для 3D-модели. Файл содержит данные для трехмерного объекта, в то время как папка содержит текстуры модели. Затем вы можете импортировать модель в Unity, как описано в следующем шаге.


Прежде чем мы начнем кодировать, нам нужно добавить наши активы в проект Unity. Вы можете сделать это одним из нескольких способов:

  • выберите Импортировать новый актив в меню Активы
  • добавить элементы в папку активов в вашем проекте
  • перетащите активы в окно проекта

После выполнения этого шага вы должны увидеть активы в папке « Ресурсы » вашего проекта на панели « Проект» .


Мы готовы создать сцену нашей игры, перетаскивая объекты на панель Иерархия или Сцена . Мы также будем использовать нативные трехмерные примитивные объекты Unity для создания уровня, как показано на следующих шагах.

Давайте сначала расположим нашу основную камеру немного выше, чтобы получить желаемый вид. Выберите его на панели « Иерархия» и настройте значения « Преобразование» в Инспекторе, чтобы они соответствовали значениям, показанным ниже.

Не волнуйтесь, если вы не видите никаких изменений. Мы еще ничего не создали для камеры, чтобы увидеть. Затем с помощью Инспектора установите для цвета фона значение RGB: 0, 139, 252 .

Уровень нашей платформы будет плавать над фоном, который будет изображением моря. Он будет создан с использованием примитивов Unity, простой плоскости с наложенной на нее текстурой.

Хотя Unity может работать с трехмерными объектами любого типа, созданными другими программами, иногда проще и / или более удобно использовать примитивы для прототипов.

Например, чтобы создать море, выберите « Создать другой»> «Плоскость» в меню GameObject и отрегулируйте значения « Преобразование» в Инспекторе, чтобы они соответствовали значениям, показанным ниже.

Вы должны квадрат в панели Scene . Мы будем использовать его, чтобы определить, когда игрок падает с платформы и заканчивает игру.

Стоит отметить, что к этим примитивным объектам уже прикреплен Mesh Collider , что означает, что они будут автоматически обнаруживать столкновения или инициировать события, когда они вступают в контакт с RigidBody .

Чтобы наложить текстуру на морской самолет, нам нужно создать материал . Материал используется для определения того, как выглядит GameObject, и важно добавить текстуру в GameObject .

Выберите « Создать»> «Материал» в меню « Активы», чтобы создать его, найдите его на панели « Активы» и с помощью инспектора выберите текстуру, которую хотите использовать в качестве моря. Вот настройки, которые я использовал:

В разделе материалов вы увидите сообщение о том, что рекомендуется использовать Mobile / Diffuse в качестве шейдера, потому что белый цвет по умолчанию ничего не делает. Изменение его на Mobile / Diffuse также поможет с производительностью.


Возможно, вы заметили, что море немного темнее, чем должно быть. Чтобы это исправить, нам нужно добавить Light в нашу сцену. Выберите « Создать другое» в меню GameObject и выберите « Направленный свет» . Это создаст объект, который производит луч света. Измените значения Transform, как показано на следующем снимке экрана, чтобы он освещал море.

Это выглядит намного лучше.

Платформы являются частью нашего уровня и используются игроком для перемещения мяча к порталу на другой стороне моря.

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

Теперь мы можем использовать инструменты перемещения и вращения Unity для создания других платформ. Все они имеют одинаковый размер, поэтому мы можем использовать их по вертикали или горизонтали, дублируя их с помощью Command + D в OS X и Control + D в Windows.


Создайте новый материал, как мы делали на шаге 14, и примените к нему текстуру. Моя выглядит так:

Отрегулируйте тайлы x и y, пока вы не будете довольны результатом.


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

Выберите « Создать другой»> «Цилиндр» в меню GameObject и настройте значения « Преобразование» в Инспекторе, как показано ниже.

Это добавит небольшую границу к краю первой платформы. Создайте новый Материал и измените его цвет в Инспекторе на RGB: 255, 69, 0 .

Результат должен выглядеть так:

Используйте Command + D ( Control + D в Windows)   дублировать границу и масштабировать инструмент, чтобы изменить его размер. Разместите дубликаты по краям платформ, используя инструменты Unity.


Портал — это линия ворот игры. Игрок будет использовать акселерометр для управления мячом и доводить его до этой точки, подбирая предметы и избегая падения с платформы. Портал представляет собой 3D-модель, которую мы импортировали на шаге 10 .

Перетащите его на панель « Сцена» или « Иерархия» и измените его значения преобразования на следующие:

Это будет позиционировать его в конце платформы.


Поскольку импортированные 3D-модели по умолчанию не имеют коллайдера, мы должны прикрепить его. Поскольку нам нужно только проверить, попадает ли шарик в синюю область портала, мы прикрепим к нему коллайдер.

Взгляните на модель портала в представлении Hierarchy, и вы увидите небольшой треугольник слева от его имени. Нажмите на треугольник, чтобы развернуть группу портала и выбрать первый элемент. Я добавил суффикс -Collider для пояснения.

Нажмите кнопку « Добавить компонент» в Инспекторе и выберите « Физика»> «Сетка-коллайдер» . Это добавит коллайдер, используя форму выбранной области модели.


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

Выберите его на панели « Иерархия» , нажмите кнопку « Добавить компонент» на панели « Инспектор» и выберите « Источник звука» в разделе « Аудио ».

Снимите флажок Play on Awake и нажмите маленькую точку справа под значком шестеренки, чтобы выбрать звук, который вы хотите воспроизвести.

Острова — не более чем декоративные элементы, делающие уровень менее пустым. Я использовал импортированную 3D модель и цилиндр, чтобы сделать их. Я не буду вдаваться в детали создания островов, так как они не важны для игры. С тем, что вы узнали, вы сможете создавать их самостоятельно.


Как и в Monkey Ball, игрок сможет собирать бананы во время игры. Начните с перетаскивания модели с панели « Ресурсы» на сцену . Пока не беспокойтесь о его расположении, потому что позже мы конвертируем его в Prefab, так как будем многократно использовать его несколько раз.

Как я упоминал ранее, в импортированных моделях по умолчанию коллайдер отсутствует, поэтому нам нужно прикрепить его к банану. Нажмите кнопку « Добавить компонент» в Инспекторе и выберите « Физика»> «Сетка-коллайдер» . Это добавит коллайдер, используя форму модели. Обязательно установите флажок Trigger , потому что мы хотим обнаруживать столкновения, но не хотим, чтобы шар реагировал с бананом.


Пришло время создать нашего игрового персонажа, который будет простым примитивом Sphere . Выберите Create Other> Sphere из меню GameObject, чтобы создать примитив и изменить значения Transform в Inspector, как показано ниже.

Это создаст сферу и поместит ее в начале нашего уровня.

Чтобы сфера стала полупрозрачной, нам нужно изменить ее параметры шейдера . Откройте Инспектор и измените шейдер на Прозрачный / Диффузный .


Чтобы обнаружить столкновение с игроком, нам нужно прикрепить к нему RigidBody . Чтобы добавить его, выберите « Добавить компонент» на панели « Инспектор» , а затем « Физика» > « RigidBody» . Вы можете оставить настройки по умолчанию.


Для отображения пользовательского интерфейса игры мы будем использовать текстуру графического интерфейса Unity. Документация Unity дает четкое объяснение текстур GUI:

Текстуры GUI отображаются в виде плоских изображений в 2D. Они сделаны специально для элементов пользовательского интерфейса, кнопок или украшений. Их позиционирование и масштабирование выполняются только по осям x и y, и они измеряются в координатах экрана, а не в мировых координатах.

По умолчанию изображения, импортированные в папку « Ресурсы », преобразуются в текстуры, которые можно применять к трехмерным объектам. Нам нужно изменить это на GUI Texture для изображений, которые мы хотим использовать в пользовательском интерфейсе игры.

Выберите изображения, которые вы хотите преобразовать, на панели « Ресурсы» и откройте Инспектор , нажмите на раскрывающееся меню « Тип текстуры» и выберите GUI .

Теперь вы можете перетащить изображения в сцену . Изображения всегда будут появляться перед каждым объектом на сцене и будут рассматриваться как 2D-элементы.

Внутри каждого элемента GUI мы будем отображать число, указывающее количество бананов, которые игрок забрал, и время, которое игрок оставил.

Выберите « Создать другой»> «Текст GUI» в меню GameObject, чтобы создать текстовый объект, поместите его в центр элемента GUI и измените текст на панели « Иерархия» на 0 . Сделайте то же самое для времени справа. Я установил время по умолчанию на 30 секунд.

Вы можете использовать собственный шрифт для текста, добавив шрифт в папку « Ресурсы », а затем изменив свойство « Шрифт» текста в Инспекторе .

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


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

Выберите этап, нажмите кнопку « Добавить компонент» на панели « Инспектор» и выберите « Новый сценарий» . Назовите скрипт MoveScene и не забудьте сменить язык на C #. Откройте только что созданный файл и добавьте следующий фрагмент кода.

01
02
03
04
05
06
07
08
09
10
using UnityEngine;
using System.Collections;
 
public class MoveScene : MonoBehaviour
{
    void Update()
    {
        transform.rotation *= Quaternion.Euler(Input.acceleration.y/6, -Input.acceleration.x/3, 0);
    }
}

Мы используем метод Update для запроса данных от акселерометра в каждом кадре, используя свойство Input.acceleration , которое измеряет движение устройства в трехмерном пространстве. Это позволяет нам получить значения x , y и z и использовать их для управления положением игрока.

Затем мы применяем полученные значения к свойству transform.rotation уровня, вызывая Quaternion.Euler , который возвращает значения вращения. Обратите внимание, что мы делим значения акселерометра, чтобы избежать слишком быстрого движения игрока, что усложняет игровой процесс.

Мы изменяем только значения x и y уровня , потому что он нужен нам только для наклона, а не для перемещения ближе или дальше от камеры.

Следующий скрипт прикреплен к основной камере . Он вычисляет пространство между камерой и игроком и поддерживает его, пока мяч движется.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using System.Collections;
 
public class FollowPlayer : MonoBehaviour
{
    public GameObject player;
    private Vector3 playerOffset;
 
    // Use this for initialization
    void Start()
    {
        playerOffset = transform.position — player.transform.position;
    }
     
    // Update is called once per frame
    void Update()
    {
        transform.LookAt(player.transform);
        transform.position = player.transform.position + playerOffset;
    }
}

Скрипт использует две переменные, которые стоит объяснить:

  • player : это ссылка на игрока в сцене . Вы можете установить это в Инспекторе .
  • playerOffset : это расстояние между камерой и плеером. Поскольку мы поддерживаем одинаковое расстояние между камерой и игроком, камера следует за игроком, когда он движется. Смещение рассчитывается в методе Start .

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
using UnityEngine;
using System.Collections;
 
public class PickBanana : MonoBehaviour
{
    public AudioClip bananaSound;
    public GUIText bananaText;
 
    void OnTriggerEnter(Collider other)
    {
        AudioSource.PlayClipAtPoint(bananaSound, transform.position);
        int score = int.Parse (bananaText.text) + 1;
        bananaText.text = score.ToString();
        Destroy(gameObject);
    }
}

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

Чтобы изменить счетчик, мы создаем переменную, используя значение текста GUI, и используем метод int.Parse чтобы преобразовать строку в число и int.Parse число на 1 . Затем мы устанавливаем значение в текст GUI , сначала преобразовывая число в строку, вызывая метод toString . Наконец, мы вызываем Destroy для удаления объекта игры банан.

Следующий класс используется для определения, когда игрок падает с платформы в море. Прикрепите скрипт к морскому игровому объекту.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
using UnityEngine;
using System.Collections;
 
public class Lose : MonoBehaviour
{
    void OnCollisionEnter()
    {
        audio.Play();
        Invoke(«Reload», 1.59f);
    }
 
    void Reload()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

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

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

Следующий класс, Timer , прикреплен к графическому интерфейсу времени в правом верхнем углу. Сокращает время и заканчивает игру, когда счетчик достигает 0 .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using UnityEngine;
using System.Collections;
 
public class Timer : MonoBehaviour
{
    public GUIText timeText;
 
    void Start()
    {
        InvokeRepeating(«ReduceTime», 1, 1);
    }
 
    void ReduceTime()
    {
        int currentTime = int.Parse(timeText.text) — 1;
        timeText.text = currentTime.ToString();
 
        if (currentTime == 0)
        {
            audio.Play();
            Invoke(«Reload», 1.59f);//waits until sound is played to reload
            Destroy(timeText);
        }
    }
 
    void Reload()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

Мы сохраняем ссылку на текст в переменной timeText чтобы упростить изменение пользовательского интерфейса. В методе Start мы вызываем метод InvokeRepeating , который многократно вызывает метод ReduceTime .

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

Когда счетчик достигает 0 , воспроизводится соответствующий звук, и мы уничтожаем текст счетчика. Мы вызываем метод Reload с задержкой, чтобы перезапустить игру, когда закончится воспроизведение звука.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using System.Collections;
 
public class EndLevel : MonoBehaviour
{
    public GameObject complete;
    public GameObject player;
 
    void OnTriggerEnter(Collider other)
    {
        audio.Play();
        Invoke(«Restart», 2);
        GameObject alert = Instantiate(complete, new Vector3(0.5f, 0.5f, 0), transform.rotation) as GameObject;
        Destroy(player.rigidbody);
    }
 
    void Restart()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

Метод Instantiate используется для создания экземпляра сообщения, которое отображается игроку. Это позволяет нам использовать элемент GUI из ресурсов проекта вместо того, чтобы размещать его на сцене. Наконец, мы перезапускаем игру с задержкой в ​​две секунды.

Пришло время протестировать игру. Нажмите Ctrl + P, чтобы играть в игру в Unity. Если все работает, как ожидалось, тогда вы готовы к последним шагам.


Когда вы довольны своей игрой, пора выбрать « Настройки сборки» в меню « Файл» и нажать кнопку « Настройки игрока» . Это должно вызвать настройки проигрывателя на панели инспектора, где вы можете установить параметры для вашего приложения.

Эти настройки представляют собой специфические данные приложения, которые включают создателя или компанию, разрешение приложения и режим отображения, режим рендеринга (CPU, GPU), совместимость с ОС устройства и т. Д. Настройте параметры в соответствии с целевыми устройствами и магазином или рынком, где Вы планируете опубликовать приложение.


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

Как только ваш проект будет правильно настроен, пришло время вернуться к настройкам сборки и нажать кнопку « Сборка» . Это все, что нужно для создания вашей игры для тестирования и / или распространения.

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