Как сделать джойстик unity3d

Разработка игры в Unity3D под геймпад

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

Так как пожертвовать клавиатурой на управление было слишком жалко (да и не так это интересно), всё управление планировалось сделать через геймпад. О том, как прикрутить в Unity3d геймпад и пойдёт речь.

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

Немного о проекте

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

Первое, что пришло в голову про космос, так это управляемый робот. Развивая эту мысль дальше, игра стала про робота, который на Луне должен найти батарейку, чтобы зарядить лазерную станцию и спастись от приближающейся кометы. Разумеется все нужно было делать на время (до 8-ми минут).

(На удивление детям игра понравилась, в том числе за управление, но об этом ниже).

Картография

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

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

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

Управление

Контроль за руками

Так как у робота две руки, как и количество «грибков» в геймпаде, то разумно этим воспользоваться.

И вот тут начинаются сложности. Дело в том, что первый «грибок» работает (хоть и со скрипом) так же, как и «Mouse X» и «Mouse Y», но второй никак не отзывался по нажатию. Тогда, сев за гугл, прочитал о том, как Unity получает входные управляющие данные. Там и лежит ответ на вопрос, как заставить работать второй (правый) «грибок».

Заходим Edit → Project Settings → Input

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

Нажали? Тогда должен появиться InputManager в окне Inspector

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

В начале будет 18 входных параметров, но нам нужно больше. Потому у меня 22 (на ось X и ось Y для второго «грибка» геймпада и ещё два, чтобы обособить имя обращения к первому «грибку»).

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

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

lp_right.transform.Rotate (0, Input.GetAxis («Hor2_j»), 0);
yr += Input.GetAxis («Hor2_j»);

lp_right.transform.Rotate (Input.GetAxis («Vert2_j»),0, 0);
xr += Input.GetAxis («Vert2_j»);

lp_left.transform.Rotate (0, Input.GetAxis («Hor_j»), 0);
yl += Input.GetAxis («Hor_j»);

lp_left.transform.Rotate (Input.GetAxis («Vert_j»),0, 0);
xl += Input.GetAxis («Vert_j»);

Передвижение

Стоит помнить, что передвижение по координатам плохо скажется на игре, так как карта построена на Terrain. Потому было принято решение использовать физику. Это увеличивает интерес прохождения с одной стороны, а с другой решает несколько проблем сразу (неровное перемещение, скачки, вылет за ограждения).

А значит нужен Rigidbody, который нужно поместить на робота, а дальше на ваш вкус (в проекте выставлена масса 100, остальное осталось не тронутым).

В коде будут только два фокуса. Первый — GetComponent(), чтобы работать именно с Rigidbody и Addforce. Второй — математический. Нужно не только знать, куда хочет робот, но и знать, куда он смотрит. Для этого обращаемся к transform.eulerAngles.y, переводим в радианы и берем косинус и синус для координат x и z соответственно.

Как можно заметить, в действиях указаны по две кнопки. Это сделано на случай, если бампера (L1,L2,R1,R2) сломаются/залипнут при многократном использовании.

Время

Для уточнения настоящего времени в Unity можно использовать System.DateTime.Now, чтобы посчитать в секундах, сколько времени прошло от начала дня. Такой способ ограничения времени имеет недостаток — переход часов с 23:59 на 00:00, но так как игра на раз и конкурс будет проходить днем, то можно пренебречь

Ограничение по времени тогда можно считать, как разницу во времени после запуска скрипта (void Start()) и тем, что сейчас (Update)

Послесловие

Детям игра понравилась, так как робот перемещался с ускорением, чем все охотно пользовались.

Особенно было интересно поймать батарейку до того, как ты в неё врежешься, так как она тоже Rigidbody и получит направление движения. В сочетании с медленным перемещением рук, получилось очень даже неплохо.

Надеюсь, что данная статья поможет вам не сидеть до поздней ночи, прикручивая геймпад к вашему проекту!

Источник

Информационный портал по безопасности

Делаем свой джойстик для Unity3D с батчингом и спрайтами

Автор: admin от 13-02-2014, 17:40, посмотрело: 14 223

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

Чтобы не изобретать велосипед, решил поискать бесплатный джойстик в местном Asset Store. Меня очень удивило, если не сказать поразило, отсутствие бесплатных джойстиков. Из 40 найденных позиций были джойстики по 5-100 долларов, при этом, судя по рейтингам и комментариям, большинство из них работали очень криво. (Единственный бесплатный джойстик я нашел намного позже, но об этом подробнее дальше)

Я решил помочь себе и другим, сделав бесплатный джойстик без использования платных GUI библиотек вроде NGUI. Тем более у меня давно лежал пак экранных контроллеров от Kenny (изображение ниже) и нужно было срочно найти ему применение.

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

Какие спрайты и батчинг?

Unity3D версии 4.3 наделала много шума добавлением нативной поддержки разработки 2D игр. Одним из новых компонент являлся SpriteRenderer, который позволил с легкостью делать 2D игры без дополнительных библиотек. Однако основной его особенностью является то, что разные спрайты из одного атласа батчатся в 1 Draw Call независимо от относительного изменения размеров через Scale. В мобильной разработке принято экономить на Draw Call в любом месте, где это возможно и SpriteRenderer дает нам эту возможность — если упаковать все используемые контроллеры на экране в один атлас, то отрисовку всего интерфейса можно вместить в один Draw Call.

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

Основная идея

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d
Если разместить наш джойстик перед камерой на расстоянии, скажем, 0.5 юнитов, спрайты не будут «врезаться» в другие объекты сцены и все время будут на переднем плане. Вместе со SpriteRenderer пришла система Z-сортировки внутри определенных заранее слоев, но она распространяется только на сами спрайты и системы частиц (насколько я смог разобраться, поправьте если не прав).

Этот же принцип, по-моему, используется в системах вроде NGUI (я не работал с ней, не могу сказать точно). В любом случае, картина получается следующая:
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

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

Окей, с этим понятно. Теперь к самому джойстику. Если вы играли в игры типа Dungeon Hunter 4, то замечали, что джойстик подпрыгивает в точку нажатия, и управление идет относительно этой точки. Причем есть «подложка» под джойстик и собственно сам джойстик.

Я собрал простой джойстик с «рабочей зоной». При нажатии на любую точку внутри зеленого коллайдера (простой Box Collider), джойстик должен прыгнуть туда и управляться относительно этой точки.

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d
Объект состоит из трех элементов, главный компонент с Box Collider и два вложенных объекта со SpriteRenderer

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

Для превода экранных координат в координаты точки на сечении пирамиды я решил пойти простым путем — находим процентное отношение координат нажатия к размерам экрана, получаем два числа от 0 до 1, соответствующих координатам X и Y. Затем умножаем эти числа на ширину и высоту сечения пирамиды и получаем локальные координаты точки на этом сечении. После чего, если джойстик расположен не в центре, нужно вычесть из полученных координат относительный центр коллайдера. В итоге, без проверки выхода джойстика за рамки подложки, получается следующая картина. При этом мы уже можем найти относительное направление джойстика и нормировать его.
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d
Используя разницу векторов центра подложки и центра джойстика можно найти длину вектора. Для проверки этого значения нам нужно знать радиус самой подложки. На помощь нам приходит свойство Pixels to Unit при импорте спрайтов. Фактически это свойство говорит о том, сколько пикселей исходного спрайта уместится в 1 юнит расстояния. Чем больше это значение, тем меньше выглядит спрайт. К сожалению, я не нашел адекватного способа определения этого свойства во время выполнения кода, поскольку требуется класс TextureImporter и его свойства, а он обычно доступен только для расширений редактора (скорее всего его физически можно использовать из рантайма, но по-моему это не совсем адекватный вариант). Пока решением остается ручное копирование значения Pixels to Unit в паблик свойство контроллера джойстика.
Посчитав фактическую величину подложки в юнитах, мы можем проверить, выходит ли джойстик за ее рамки или нет.
Для оптимизации проверки в данном случае нам здорово поможет свойство Vector3.sqrMagnitude, определяющее квадрат модуля вектора. Если сравнивать квадрат модуля с квадратом необходимого расстояния, можно избежать операции вычисления квадратного корня, что немного ускорит выполнения кода.
Общее условие выглядит следующим образом — если квадрат модуля вектора относительного направления меньше или равен квадрату радиуса подложки, джойстик находится под положением нажатия. В противном случае нормируем вектор относительного направления, умножаем на радиус подложки и ставим джойстик в точку с получившимися координатами.
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d
Получается такая картина:
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

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

Если прикрутить получившийся на данный момент джойстик к заготовке персонажа, получится нечто такое:
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

(На самом деле он ходит, просто неоднородная текстура, на которой видно передвижение, здорово увеличивает размер GIF файла)

Я уже начал думать что работа подходит к концу, но дальше все оказалось еще интересней.

Подводные камни

Все стало очень интересно, когда я начал делать снеппинг джойстика к углам экрана.
Поскольку локальные координаты точки нажатия на сечение не соответствуют локальным координатам самого джойстика, при перемещении самого джойстика (вместе с коллайдером) в точку, отличную от левого нижнего угла экрана, приходится пересчитывать дополнительное слагаемое локальных координат. Для привязки к верхнему левому углу выглядело это примерно так:
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d
С этой проблемой я залип на очень длительное время, долго пытался понять мозгом, что и с чем нужно складывать и из чего вычитать. Оказалось, что все довольно сложно.
Прежде всего, как бы мы ни двигали BoxCollider, точка отсчета локальных координат в джойстике всегда будет в центре подложки (в обычном положении, без нажатия).
Оказалось что свойства collider,bounds считаются всегда в мировых координатах, поэтому для адекватного нахождения реальных размеров пришлось для начальных вычислений ставить объект джойстика в положение Reset, то есть в нулевую позицию с нулевым поворотом, а потом ставить обратно.
Общий вид систем отсчетов выглядел следующим образом:
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

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

Но это был не конец.

Еще одним подводным камнем оказалась поддержка мультитача.
Представим следующий сценарий:
У нас есть два джойстика и два пальца, пусть это будет Д1, Д2, П1 и П2.
Пользователь нажимает П1 на Д1, после чего нажимает П2 на Д2. Индекс П1 в массиве нажатий равен 0, индекс П2 в массиве нажатий равен 1. Если после этого пользователь отпускает П2, индекс П1 все еще остается равен 0, все хорошо. Но если вместо П2 пользователь отпустит П1, то индекс П2 станет равен 0, и Д1 будет думать, что его П1 переместился в точку П2, и получится так, что один П2 управляет двумя джойстиками.
Стоит отметить, что до этого я мало работал с мультитачами, и следующее предложение может показаться кому-то смешным и несуразным. Я сразу ринулся проверять дельту перемещений. Но это был слишком кривой костыль, он не спасал от случая, когда мы сводим два пальца вместе. Оба джойстика прилипают к одному пальцу и снова та же самая картина.
Потом у меня хватило ума посмотреть документацию и прочитать про волшебное свойство Touch.fingerId. Оно хранит индекс нажатого пальца.
Я поменял привязку джойстика к индексу в массиве касаний на индекс пальца и стал проверять, присутствует ли еще в списке присутствующих касаний нужный нам палец. Все стало работать просто отлично.
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

Итог:
Я проверил производительность джойстика по профайлеру, оказалось что он здорово превосходит стандартный по производительности (простой одновременный твикинг, без применения перемещения на цель, проверял через Unity Remote):
Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

Батчинг никуда не делся.
С подобным подходом не нужно переживать о размерах текстур относительно размера экрана, GUITexture приходилось вручную шкалировать под разные разрешения.
Но самое главное — своими руками и бесплатно. Нестоит недооценивать роль комунизма в Open-Source разработках!

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

Пока писал статью понял, как сделать джойстик без коллайдера и Physics.Raycast(..)
Я определенно буду продолжать работать над этим продуктом, планируется сделать простой тачпад и ABC кнопки.

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

Оригинальный пак экранных контроллеров можно найти ТУТ

Источник

Традиционный игровой ввод

Unity поддерживает ввод с клавиатуры, джойстика и гейпада.

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

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

Virtual Axes

Из скриптов все виртуальные оси доступны по их именам.

Каждый проект при создании содержит следующие оси ввода по умолчанию:

Добавление новых осей ввода

Как сделать джойстик unity3d. Смотреть фото Как сделать джойстик unity3d. Смотреть картинку Как сделать джойстик unity3d. Картинка про Как сделать джойстик unity3d. Фото Как сделать джойстик unity3d

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

Свойство:Функция:
NameИмя, используемое для проверки этой оси из скрипта.
Descriptive NameИмя положительного значения, отображаемое на вкладке Input диалогового окна Configuration в автономных сборках.
Descriptive Negative NameИмя отрицательного значения, отображаемое на вкладке Input диалогового окна Configuration в автономных сборках.
Negative ButtonКнопка, используемая для смещения значения оси в отрицательном направлении.
Positive ButtonКнопка, используемая для смещения значения оси в положительном направлении.
Alt Negative ButtonАльтернативная кнопка, используемая для смещения значения оси в отрицательном направлении.
Alt Positive ButtonАльтернативная кнопка, используемая для смещения значения оси в положительном направлении.
GravityСкорость в единицах в секунду, с которой ось возвращается в нейтральное положения, когда кнопки не нажаты.
DeadРазмер аналоговой мертвой зоны. Все значения аналоговых устройств, попадающие в этот диапазон, считаются нейтральными.
SensitivityСкорость в единицах в секунду, с которой ось движется к заданному значению. Только для цифровых устройств.
SnapЕсли включено, значение оси будет сбрасываться в ноль при нажатии кнопки в противоположном направлении.
InvertЕсли включено, Negative Buttons будут выдавать положительные значения, и наоборот.
TypeТип ввода, который будет управлять осью.
AxisОсь подключенного устройства, которая будет управлять этой осью.
Joy NumПодключенный джойстик, который будет управлять этой осью.

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

Использование осей ввода из скриптов

Вы можете запросить текущее состояние из скрипта так:

Это в случае ввода с джойстика и клавиатуры.

Однако изменения осей Mouse и Window Shake показывают, насколько мышь или окно сдвинулись по сравнению с последним кадром. Это значит, что они могут быть больше, чем 1 или меньше, чем –1, когда пользователь быстро двигает мышь.

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

Названия кнопок

Keys (Клавиши)

Названия кнопок следуют этому соглашению:

Названия, используемые для определения кнопок одни и те же при написании скриптов и в окне Inspector.

Ось может иметь значение от –1 до 1. На нейтральное положение указывает 0. Note also that the keys are accessible using the KeyCode enum parameter.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *