Pull to refresh
0

Разработка игр с помощью Unity и 3D-камеры Intel RealSense

Reading time 11 min
Views 15K
Original author: Gregor Biswanger

Процесс создания компьютерных игр включает набор стандартных задач, с которыми постоянно приходится сталкиваться разработчикам. Это, к примеру, учет физических законов, столкновение объектов, запуск событий (звуковые сигналы, подсчет очков и т. п.) и ответ на действия игроков, использующих джойстик, мышь и клавиатуру. Реализация этих функций для каждой целевой платформы в отдельности может отнять очень много времени. Чтобы этого избежать, разработчики используют игровой движок с поддержкой стандартной функциональности. Это позволяет уделять больше внимания сложным задачам.
Unity 3D — отличное кроссплатформенное решение от Unity Technologies. Оно предназначено для разработки игр для компьютеров, игровых консолей, мобильных устройств и веб-браузеров. В Unity 3D предусмотрена поддержка различных языков программирования, например C++, C#, Unity Script (похож на JavaScript) и Boo.
Эта статья предназначена как для начинающих специалистов, так и для экспертов. Чтобы помочь тем, кто никогда раньше не работал с Unity, мы начнем с небольшого примера применения этого продукта. Затем я расскажу, как использовать Intel RealSense SDK и 3D-камеру Intel RealSense для отслеживания жестов и как создать простую игру на C#.

Для работы вам потребуется Visual Studio, Unity, Intel RealSense SDK и 3D-камера Intel RealSense.

Загрузка, установка и настройка Visual Studio


Загрузите бесплатную версию Unity. Она работает под ОС Microsoft Windows* и Apple Mac* OS X*. Чтобы завершить установку, пройдите бесплатную регистрацию.
Программа, приведенная в этой статье для примера, написана на языке C#. В качестве кроссплатформенной интегрированной среды разработки в Unity по умолчанию используется MonoDevelop. Unity также можно использовать с Microsoft Visual Studio, что особенно удобно для разработчиков .NET. Для начала нужно подключить Visual Studio к Unity. В раскрывающемся меню выберите Edit -> Preferences…. На экране появится окно настроек. Выберите External Tools на панели с левой стороны (рис. 1). Нажмите MonoDevelop рядом с полем External Script Editor и выберите файл .exe Visual Studio, нажав кнопку Browse…. Установите Visual Studio, используя настройки по умолчанию. Путь к файлу запуска программы должен быть следующим.
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe.
Это все, что требуется для подключения.


Рисунок 1. Выбор Visual Studio* в Unity*

Среда


Перейдем к настройкам среды Unity. Главный экран состоит из нескольких окон. Вы можете разместить их вручную или выбрать стандартное расположение. Мы выбрали ориентацию Tall в раскрывающемся меню Layout в правом верхнем углу экрана.


Рисунок 2. Выбор положения окна

Окно построения сцены и окно игры


Первое большое окно (рис. 3) предназначено для построения сцены, то есть для размещения объектов игры. Обычно для него используется 3D-формат. Чтобы изменить положение объекта сцены, достаточно его перетащить. Сразу над главным экраном расположена вкладка игры. На ней показано готовое изображение, каким его увидит пользователь.


Рисунок 3. Окно построения сцены


Рисунок 4. Окно игры

Окно иерархии


В окне иерархии (рис. 5) представлен список используемых объектов, например предметы из самой игры, камеры, средства освещения сцены, элементы интерфейса и аудиозаписи. Чтобы создать новые объекты, используйте меню GameObject или окно Create.


Рисунок 5. Окно иерархии

Окно свойств


При выборе объекта в окне иерархии на экране появится окно его свойств (рис. 6). Их набор можно расширить, добавив в него дополнительные элементы. Для этого нужно нажать кнопку Add Component. Например, объекту можно назначить свойства твердого тела, чтобы в игре на него действовала гравитация.


Рисунок 6. Окно свойств

Окно проекта


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


Рисунок 7. Окно проекта

Создание простой игры


В начале 70-х Нолан Бушнелл, основатель Atari, выпустил игру, которая впоследствии стала очень популярной. Она называлась Pong и представляла собой простейший симулятор настольного тенниса. Игра заключалась в следующем. По экрану движется мячик. Каждый игрок управляет ракеткой, перемещая ее по вертикали. Если кому-то не удается отбить мяч, его соперник получает одно очко. Давайте разберемся, как реализовать эту игру с помощью Unity.
Чтобы создать новый проект, нажмите File -> New Project. Назовите его PingPongUnity.


Рисунок 8. Создание нового проекта

Ракетки


Для начала создадим ракетки. В окне иерархии нажмите Create -> 3D Object -> Cube. Чтобы изменить форму и расположение ракеток, выберите созданный куб и укажите нужные параметры в окне настроек. В нашем примере мы назвали объект Paddle1 и изменили его форму (см. графу Transform). Укажите следующие значения в графе scale X: 0.5, Y:3, Z:1. Укажите следующие координаты в графе Position X: -9, Y: 1, Z: 0. Таким образом мы создали первую ракетку. В окне иерархии нажмите правой кнопкой мыши на ракетку и в контекстном меню выберите Duplicate. На экране появится копия созданной ракетки. Осталось только переименовать ее в Paddle2 и изменить значение X в графе Position на 9.
Чтобы ракетки двигались согласно физическим законам, нам придется добавить компонент RigidBody, нажав кнопку Add Components для каждой из них. Так мы сможем управлять движением ракеток и их столкновением с мячом. Пока что наш мячик просто пролетает сквозь ракетку, а не отскакивает от нее. Это не совсем то, что требуется. Чтобы избежать этого, следует установить определенные ограничения на свойства объектов. Те объекты, которые будут удовлетворять указанным ограничениям, назовем RigidBody. Ракетки могут двигаться только вверх и вниз, так что в графе Freeze Rotation нужно выбрать x, y и z, а в графе Freeze Position — только x.


Рисунок 9. Ракетки

Стенки


Для этой игры также нужно создать две стенки (верхнюю и нижнюю), чтобы мячик отскакивал от них и не улетал за границы поля. Для этого нам снова понадобятся кубические объекты. В окне иерархии еще раз нажмите Create -> 3D Object -> Cube. Назовите созданный объект WallBelow. Он будет чуть длиннее ракеток, поэтому в графе scale укажите следующие значения X: 23, Y: 1, Z: 1. В графе Position укажите следующее X: 0, Y: -5, Z: 0.
Чтобы создать вторую стенку, достаточно скопировать первую и переименовать ее в WallAbove. Теперь просто измените значение Y-Position на 7.


Рисунок 10. Стенки

Мячик


Осталось создать последний, самый важный объект игры — мячик. В наборе стандартных форм, представленном в Unity, уже есть нужная. В окне иерархии нажмите Create -> 3D Object -> Sphere. Измените название на Ball, в графе Position укажите следующие значения X: 0, Y: 1, Z: 0. Чтобы мячик двигался нужным образом, необходимо включить ограничения RigidBody, нажав на кнопку Add Components, и снять галочку Use gravity.


Рисунок 11. Мячик

Изменение угла обзора и освещение сцены


Пока что ракурс выбран неудачно. Чтобы это исправить, нужно изменить настройки камеры. В окне иерархии выберите стандартную камеру Main Camera. Переключите формат обзора с 3D на 2D. Это можно сделать в разделе Projection. Вместо Perspective (3D) выберите Orthographic (2D). Теперь на экране представлена вертикальная проекция сцены. Измените значение параметра Size на 10.
Если требуется повернуть камеру, нажмите значок осей координат.


Рисунок 12. Поворот камеры можно включить, нажав на значок осей координат

Мы установили все необходимые настройки камеры. Однако сцена остается слишком темной. Чтобы добавить освещение, откройте окно иерархии и нажмите Create -> Light -> Directional Light. Все изменения отображены в окне игры.


Рисунок 13. Окно игры

Давайте запустим мячик!


Поле готово, но все объекты пока замерли на месте. Если сейчас начать игру, мячик свалится вниз и этим все закончится. Чтобы это исправить, достаточно добавить в игру несколько строк кода на C#. Нажмите кнопку Create в окне проекта и создайте новый файл сценария под названием Ball для программы на языке C#. Перетащите его на мячик в окне иерархии или в окне отображения сцены, чтобы связать с объектом игры. Теперь при выборе мячика в окне свойств появится информация о файле сценария.
По двойному щелчку файла C# откроется выбранная среда разработки (MonoDevelop или Microsoft Visual Studio). Каждый вновь созданный файл содержит автоматически реализованный стандартный класс. Он называется MonoBehavior и является интерфейсом для Unity API. Метод Start выполняет инициализацию и подготовку к началу игры. Игровая среда, как телевизор, обрабатывает несколько изображений в секунду. Одно изображение называется кадром. Метод Update запускается каждый раз перед показом кадра. Таким образом реализуется то, что мы называем циклом игры. То есть игровые объекты могут действовать независимо от действий игрока.
В нашем случае требуется установить направление движения мячика в начале игры. Это можно сделать в методе Start. См. фрагмент программы ниже.

using UnityEngine;
public class Ball : MonoBehaviour
{
    private float _x;
    private float _y;
    // Инициализация
    void Start ()
    {
       _x = GetRandomPositionValue();
       _y = GetRandomPositionValue();
        GetComponent<Rigidbody>().velocity = new Vector3(Random.Range(5,10) * _x, Random.Range(5,10) * _y, 0);
        Debug.Log("x: " + _x);
        Debug.Log("y: " + _y);
    }
    private float GetRandomPositionValue()
    {
        if (Random.Range(0, 2) == 0)
        {
            return -1;
        }
        return 1;
    }
    // Обновление вызывается один раз за кадр
    void Update () 
    {
    }
}

Фрагмент кода 1. Выбор направления движения мячика. Реализация на языке C#

Раздел компонентов — самая содержательная часть реализации. Для каждой игровой логики предусмотрен свой компонент. В приведенном фрагменте кода для доступа к компоненту Rigidbody текущего объекта игры используется метод GetComponent. Rigidbody отвечает за действие на объект сил гравитации. В программе мы создаем новый вектор Vector3 и присваиваем его velocity (скорость, свойство Rigidbody). Координаты вектора задаются случайным образом.
Запуская игру еще раз, мы видим, что мячик теперь падает в произвольном направлении. Сталкиваясь со стенкой, он начинает двигаться вбок, а нам нужно, чтобы он отскакивал.
Давайте воспользуемся разделом Physic Material и выберем для мячика необходимые физические свойства. В окне проекта нажмите кнопку Create. Укажите имя Bouncy. Осталось только изменить некоторые свойства, чтобы добиться нужной прыгучести мячика. В окне свойств установите значение 0 для параметров Dynamic Friction и Static Friction. Для Bounciness укажите 1. Значение Friction Combine должно быть минимально, а Bounce Combine — максимально.


Рисунок 14. Настройка физических свойств материала

Чтобы применить выбранные настройки к объектам игры, нужно сделать следующее. Нажмите Edit -> Project Settings -> Physics. Перетащите набор свойств под названием Bouncy в набор стандартных свойств Default material. Для параметра Bounce Threshold установите значение 0.1. Теперь мячик будет прыгать как резиновый.


Рисунок 15. Настройка свойств Bouncy в окне PhysicsManager

Управление ракетками при помощи жестов


Игра почти готова. Все объекты находятся на своих местах, и мячик движется, как мы и хотели. Осталось только научиться управлять ракетками. Для этого лучше всего использовать 3D-камеру — новейшее устройство ввода, которое уже широко используют с Microsoft Xbox* и Kinect*, а также встраивают в некоторые новые модели Ultrabook. 3D-камера не так дорого стоит, так что не упустите возможность ее приобрести. Для программной реализации вам потребуется Intel RealSense SDK. Этот комплект можно загрузить бесплатно. Примеры работы с Unity находятся в Intel RealSense SDK. Посмотрите их после завершения установки.


Рисунок 16. Примеры из Intel RealSense SDK

В Unity 3D предусмотрена поддержка подключаемых модулей сторонних производителей, а также Intel RealSense SDK. Чтобы подключить Intel RealSense SDK, добавьте в проект файлы SDK DLL. В окне Unity нажмите Assets -> Import package -> custom package.... Затем выберите файл RSUnityToolkit.unitypackage, расположенный по адресу C:\Program files (x 86) \Intel\RSSDK\framework\Unity. На экране появится диалоговое окно (см. рис. 17). По умолчанию выбраны все файлы. Чтобы снять выбор, нажмите None. Затем выберите только папку подключаемых модулей. При работе с 64-разрядными системами импортированные файлы DLL также нужно будет заменить вручную. Они находятся в папке C:\Program Files (x86)\Intel\RSSDK\bin\x64.


Рисунок 17. Подключение Intel RealSense SDK к Unity* с помощью функции импорта пакета

После подключения можно перейти к реализации управления ракетками. Создадим еще один файл C#. Для этого нажмите кнопку Create в окне проекта. Назовите файл Paddle. Для управления обеими ракетками достаточно одного общего экземпляра. Это существенный момент, поскольку 3D-камера Intel RealSense не поддерживает подключение к нескольким экземплярам. Поэтому, чтобы подключить новый файл, достаточно перетащить его на объект main camera в окне иерархии.
После этого дважды нажмите файл Paddles.cs. Хотя он подключен к главной камере, для работы нам понадобятся объекты игры, соответствующие ракеткам. В Unity подключение нескольких объектов игры определяется в их свойствах. В C# пришлось бы определять дополнительные свойства с помощью get и set, что в Unity делать совсем не обязательно. Нужно только создать для каждой ракетки переменную типа GameObject с модификатором доступа public, как показано в примере ниже. Теперь, чтобы подключить объекты игры, достаточно перетащить их в свойства созданных ракеток.

public class Paddles : MonoBehaviour
{
    public GameObject Paddle1;
    public GameObject Paddle2;
..

Фрагмент 2. Автоматически определяемые свойства

Для подключения камеры в Intel RealSense SDK реализован класс PXCMSenseManager. Функция Start будет вызвана только один раз, так что в ней лучше всего выполнять все подготовительные действия. Именно поэтому мы выбрали функцию Start для инициализации класса PXCMSenseManager. Распознавание жестов реализовано в модуле QueryHand, к которому мы обращаемся в программе. Для распознавания лица и голоса требуется отдельный модуль. Объявление экземпляра модуля (переменная _pxcmSenseManager) вынесено за пределы функции Start. См. фрагмент программы ниже.
public class Paddles : MonoBehaviour
{
    public GameObject Paddle1;
    public GameObject Paddle2;

    private PXCMSenseManager _pxcmSenseManager;
    private PXCMHandModule _pxcmHandModule;

    // Инициализация
    private void Start()
    {
        _pxcmSenseManager = PXCMSenseManager.CreateInstance();

        if (_pxcmSenseManager == null)
        {
            Debug.LogError("SenseManager Initialization Failed");
        }
        else
        {
            pxcmStatus pxcmResult = _pxcmSenseManager.EnableHand();
            if (pxcmResult != pxcmStatus.PXCM_STATUS_NO_ERROR)
            {
                Debug.LogError("EnableHand: " + pxcmResult);
            }
            else
            {
                _pxcmHandModule = _pxcmSenseManager.QueryHand();
                _pxcmSenseManager.Init();

                PXCMHandConfiguration configuration = _pxcmHandModule.CreateActiveConfiguration();
                configuration.EnableAllGestures();
                configuration.ApplyChanges();
                configuration.Dispose();
            }
        }
    }
...


Фрагмент кода 3. Подключение 3D-камеры Intel RealSense

Обработка очереди данных, поступающих с камеры, выполняется в функции Update (на каждом шаге цикла игры), так что мы можем определить, распознает камера руку или нет. В нашей реализации левая рука управляет левой ракеткой, правая — правой. Обработка действий для обеих рук полностью совпадает, поэтому мы создадим отдельную функцию MoveBall и будем передавать ей доступ к данным о левой или правой руке в качестве параметра.
Если игрок завершает игру или начинает заново, требуется отключить связанный с камерой экземпляр. Для этого будем использовать функцию OnDisable, к которой автоматически обратится Unity.
   // Обновление вызывается один раз за кадр
    private void Update()
    {
        if (_pxcmSenseManager == null)
        {
            return;
        }

        _pxcmSenseManager.AcquireFrame(false, 0);

        _pxcmHandModule = _pxcmSenseManager.QueryHand();
        PXCMHandData handData = _pxcmHandModule.CreateOutput();
        handData.Update();

        MoveBall(handData, PXCMHandData.AccessOrderType.ACCESS_ORDER_LEFT_HANDS, Paddle1);
        MoveBall(handData, PXCMHandData.AccessOrderType.ACCESS_ORDER_RIGHT_HANDS, Paddle2);

        _pxcmSenseManager.ReleaseFrame();
    }

    private void MoveBall(PXCMHandData handData, PXCMHandData.AccessOrderType accessOrderType, GameObject gameObject)
    {
        PXCMHandData.IHand pxcmHandData;
        if (handData.QueryHandData(accessOrderType, 0, out pxcmHandData) == 
            pxcmStatus.PXCM_STATUS_NO_ERROR)
        {
            PXCMHandData.JointData jointData;
            if (pxcmHandData.QueryTrackedJoint(PXCMHandData.JointType.JOINT_CENTER, out jointData) ==
                pxcmStatus.PXCM_STATUS_NO_ERROR)
            {
                gameObject.GetComponent<Rigidbody>().velocity = new Vector3(-9, jointData.positionWorld.y*100f, 0);
            }
        }
    }

    private void OnDisable()
    {
        _pxcmHandModule.Dispose();
        _pxcmSenseManager.Dispose();
    }
}


Фрагмент кода 4. Управление ракетками при помощи жестов

Перезапуск игры


Мы создали объекты, написали программу, теперь настало время поиграть. Ракетка начнет перемещаться, если движение руки удалось распознать в пределах 1–5 метров от камеры. Ударившись о ракетку, мячик отскочит и будет двигаться в обратном направлении. Если мячик не коснется ракетки и вылетит за пределы поля, вернуть его уже не удастся. В этом случае логично было бы запускать игру заново.
Для этого достаточно дописать всего несколько строчек кода в наш файл Ball.cs. Добавим проверку наличия мячика на поле в функцию Update. Если мячик пропадет из вида, функция Application.LoadLevel перезапустит игру, как показано в программе ниже.

private bool _loaded;
// Обновление вызывается один раз за кадр
void Update () 
{
    if (GetComponent<Renderer>().isVisible)
    {
        _loaded = true;
    }

    if (!GetComponent<Renderer>().isVisible && _loaded)
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

Фрагмент кода 5. Ball.cs: запуск новой игры, когда мячик пропадает из вида

Публикация игры


Мы не зря старались и создали первую версию игры. Поделиться ей с другими очень просто. Нажмите File | Build Settings (Ctrg + Shift + B). На экране появится диалоговое окно сборки. В нем предложен огромный выбор самых разных платформ. Мы будем использовать ОС Windows (архитектура x86_64). Чтобы запустить компилятор и создать файл *.exe для Windows, достаточно нажать Build. После этого, чтобы начать игру, потребуется 3D-камера Intel RealSense с установленным драйвером.


Рисунок 18. Компиляция игры и создание файла *.exe

Теперь ваша очередь


Мы научились создавать простейшую игру с помощью Unity, но есть еще столько способов ее улучшить! Попробуйте доработать ее, добавьте подсчет очков, звуки и спецэффекты. Загрузите видео на YouTube* и напишите мне по электронной почте, чтобы похвастаться своими успехами. Я уверен, у вас получится отличная игра. На этом все, настало время поиграть!


Рисунок 19. Игра


Рисунок 20. Интерфейс игры
Tags:
Hubs:
+8
Comments 2
Comments Comments 2

Articles

Information

Website
www.intel.ru
Registered
Founded
Employees
5,001–10,000 employees
Location
США
Representative
Анастасия Казантаева