Для работы на конкурс была поставлена задача: спроектировать небольшую игру про космос, которую дети будут проходить порядка 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
Автор: Gr13