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


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



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



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


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


Картография


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



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


Управление


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


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


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


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



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



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


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



Код для управления руками

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 соответственно.


Перемещение робота
y=bot.transform.eulerAngles.y*(Mathf.PI/180);
if(Input.GetKey(KeyCode.JoystickButton4)||Input.GetKey(KeyCode.JoystickButton0))
{
    s="Go_to";
    bot.GetComponent<Rigidbody>().AddForce(new Vector3(Mathf.Cos(y),0,-Mathf.Sin(y))*15);
}
if(Input.GetKey(KeyCode.JoystickButton5)||Input.GetKey(KeyCode.JoystickButton2))
{
    s="Go_back";
    bot.GetComponent<Rigidbody>().AddForce(-new Vector3(Mathf.Cos(y),0,-Mathf.Sin(y))*15);
}
if(Input.GetKey(KeyCode.JoystickButton6)||Input.GetKey(KeyCode.JoystickButton3))
{
    s="Turn_left";
    bot.transform.Rotate(0,-0.5f,0);
}
if(Input.GetKey(KeyCode.JoystickButton7)||Input.GetKey(KeyCode.JoystickButton1))
{
    s="Turn_right";
    bot.transform.Rotate(0,0.5f,0);
}

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


Время


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


А если нельзя

Советов два


  • Считайте вместе с днем, месяцем и годом. Когда то видел такую функции в TurboC++, которая выдает количество секунд, прошедших с 1 января 1970
  • Прочитайте про таймеры и вызывающие функции в C#

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


Код
void Start () {
    time = System.DateTime.Now.Hour * 3600 + System.DateTime.Now.Minute * 60 + System.DateTime.Now.Second;
}
void Update () {
    win = PlayerPrefs.GetInt ("win");
    lose = PlayerPrefs.GetInt ("lose");
    t = System.DateTime.Now.Hour * 3600 + System.DateTime.Now.Minute * 60 + System.DateTime.Now.Second;
    if((win+lose)==0) PlayerPrefs.SetInt("time",480-(t-time));
    if((480-(t-time))==0) PlayerPrefs.SetInt ("lose",1);

Послесловие


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


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


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


P.S. Собрано, сделано и проверено для Unity3d 5.0

Поделиться с друзьями
-->

Комментарии (9)


  1. Slydex
    07.10.2016 17:15
    +1

    Не джойстик а геймпад…


    1. Gr13
      07.10.2016 17:16

      Исправил


      1. Heinhain
        07.10.2016 22:34

        «грибки» называются «аналаговыми стиками»…


  1. Terras
    07.10.2016 17:42

    Сколько по времени у вас ушло на всю разработку?


    1. Gr13
      07.10.2016 17:48
      +1

      В сумме где то до 10 часов, где 4 из них выяснения отношений с геймпадом


      1. Terras
        07.10.2016 18:00

        Неплохо. Нужно будет обязательно попробовать движок. Что-то люди с ним чудо делать за короткий период -)


  1. inborn_killer
    07.10.2016 20:28

    if(Input.GetKey(KeyCode.JoystickButton5)||Input.GetKey(KeyCode.JoystickButton2))

    Мне кажется, так всё же не стоит писать. Лучше всё так же в InputManager настроить необходимые кнопки и использовать их алиасы в коде. Тогда даже не придётся через «или» перечислять все варианты.


  1. Leopotam
    08.10.2016 11:18
    +1

    Судя по всему целевой платформой является исключительно Windows, потому что под другими платформами начинается адский ад при использовании разных контроллеров. Самые большие проблемы вызвал xbox360 контроллер, который выдавал безумные результаты под osx (где еще нужно постараться его завести через левые драйвера от коммунити) и под андроид: где-то триггеры выдавали значение вкл-выкл (0,1, без плавной интерполяции по силе нажатия), где-то левый триггер выдавал диапазон [-1,0], а правый [0,+1] по одной оси! Те можно было ткнуть оба и полуить одновременно -1 и +1. Те же проблемы с D-pad-ом, где-то детектится как 2 оси, где-то — как 4 независимые кнопки. Аналогично — правый стик. После всех опытов было выяснено, что единообразно работает только левый стик на всех контроллерах, все остальное — абсолютно в разнобой, причем одни и те же контролы на одном и том же контроллере могут мапиться абсолютно на разные номера кнопок / осей на разных платформах. Единственным исключением стал ps3 / ps4 контроллер — он работал всегда и везде единообразно. Собственно, из-за этого адского ада существуют фреймворки, пытающися по имени вендора контроллера перемапить внутри себя всю эту мешанину. Вывод: или избегайте контроллеры по-максимуму, или будете иметь максимальную боль на разных платформах.


  1. shushu
    10.10.2016 08:16

    C удовольствием бы еще прочитал про аналогичную разработку, но под blend4web