Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Unity_в_действии_Джозеф_Хокинг_Рус.pdf
Скачиваний:
83
Добавлен:
21.06.2022
Размер:
26.33 Mб
Скачать

8.1. Создание дверей и других устройств      189

кода в стиле MVC (Model-View-Controller — Модель-Представление-Контроллер) для управления данными о собранных предметах инвентаря. Наконец, вы запрограммируете интерфейс, позволяющий пользоваться инвентарем для игры, к примеру, открывать дверь при помощи найденного ранее ключа.

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

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

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

8.1. Создание дверей и других устройств

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

8.1.1. Открывание и закрывание дверей

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

В стенах есть несколько промежутков, в которые можно поместить новый объект, блокирующий проход. Я создал куб, в поля Position которого ввел значения 2.5, 1.5, 17, а в поля Scale — значения 5, 3, 0.5, получив показанную на рис. 8.1 дверь.

Создайте сценарий на C# с именем DoorOpenDevice и назначьте его объекту door. Его код, показанный в следующем листинге, заставит объект функционировать как дверь.

190      Глава 8. Добавление в игру интерактивных устройств и элементов

Рис. 8.1. Дверь, закрывающая проем в стене

Листинг 8.1. Сценарий, по команде закрывающий и открывающий дверь

using UnityEngine;

using System.Collections;

public class DoorOpenDevice : MonoBehaviour {

[SerializeField] private Vector3 dPos; ¬ Смещение, применяемое при открывании двери.

private bool _open; ¬ Переменная типа Boolean для слежения за открытым состоянием двери.

public void Operate() {

if (_open) { ¬ Открываем или закрываем дверь в зависимости от ее состояния.

Vector3 pos = transform.position - dPos; transform.position = pos;

}else {

Vector3 pos = transform.position + dPos; transform.position = pos;

}

_open = !_open;

}

}

Первая переменная определяет смещение, возникающее при открывании двери. Дверь сдвигается на указанное расстояние, когда ее открывают, а затем, чтобы закрыть дверь, это значение вычитается. Далее следует закрытая переменная логического типа, отслеживающая состояние двери. В методе Operate() выполняется преобразование объекта, меняющего его положение, путем добавления или вычитания величины смещения в зависимости от того, закрыта или открыта дверь; после этого состояние переменной _open меняется на противоположное.

Подобно другим сериализованным переменным, переменная dPos появляется на панели Inspector. Но так как она представляет собой структуру Vector3, вместо одного поля под одним именем переменной появятся три. Укажите относительное положение двери в открытом состоянии; я решил, что для этого она должна уходить вниз, поэтому смещение составило 0, –2.9, 0 (так как высота объекта door равна 3, смещение вниз на расстояние 2.9 оставит только небольшой порог, выступающий над полом).

Теперь нам нужен код, который должен вызывать функцию Operate(), открывающую и закрывающую дверь (обе ситуации будут обрабатываться одной и той же

8.1. Создание дверей и других устройств      191

функцией). Соответствующий сценарий для персонажа пока отсутствует; его написанием мы и займемся в следующем разделе.

ПРИМЕЧАНИЕ  Преобразование совершается мгновенно, а вы, возможно, предпочитаете видеть, как открывается дверь. В главе 3 упоминалась такая методика, как анимация по начальной и конечной точкам, позволяющая получить плавное движение объектов. Английский термин tweening в разных контекстах имеет разные значения. В программировании игр он относится к командам кода, приводящим объекты в движение. Рекомендую обратить внимание на инструмент iTween, который можно скачать с официального сайта http://itween.pixelplacement.com.

8.1.2. Проверка расстояния и направления перед открытием двери

Создайте новый сценарий с именем DeviceOperator. Код из следующего листинга добавляет управляющую клавишу, которая воздействует на расположенные поблизости устройства.

Листинг 8.2. Клавиша контроля устройства для персонажа

using UnityEngine;

using System.Collections;

public class DeviceOperator : MonoBehaviour {

public float radius = 1.5f; ¬ Расстояние, с которого персонаж может активировать устройства.

void Update() {

if (Input.GetButtonDown("Fire3")) { ¬ Реакция на кнопку ввода, заданную в настройках ввода в Unity.

Collider[] hitColliders =

 

Physics.OverlapSphere(transform.position, radius); ¬ Метод OverlapSphere() возвращает

foreach (Collider hitCollider in hitColliders) {

список ближайших объектов.

 

hitCollider.SendMessage("Operate",

Метод SendMessage() пытается вызвать

SendMessageOptions.DontRequireReceiver); ¬

именованную функцию независимо от типа

}

целевого объекта.

}

 

}

 

}

 

Основная часть этого листинга вам уже знакома, но центральную часть кода занимает важный новый метод. Первым делом задается расстояние, на котором становится возможным управление устройством. После этого в методе Update() рассматривается клавиатурный ввод; так как клавиша прыжка уже задействована в сценарии RelativeMovement, на этот раз мы воспользуемся клавишей Fire3 (в настройках ввода проекта она определена как левая клавиша Command).

Вот мы и дошли до важного нового метода OverlapSphere(). Он возвращает массив всех объектов, расположенных не более чем на определенном расстоянии от текущего местоположения. Мы передаем в него положение персонажа и переменную radius, а он распознает все расположенные рядом с персонажем объекты. С полученным списком можно поступать как угодно (например, вы можете установить бомбу и применить к объектам силу взрыва), сейчас же мы хотим попытаться вызвать для всех этих объектов метод Operate().

192      Глава 8. Добавление в игру интерактивных устройств и элементов

Для вызова этого метода вместо обычной точечной нотации используется метод SendMessage(). Этот подход вы уже встречали раньше, при работе с кнопками UI. В данном случае мы прибегаем к нему из-за отсутствия точных данных о типе целевого объекта. А метод SendMessage() работает со всеми объектами GameObjects. Правда, на этот раз мы снабдим его параметром DontRequireReceiver. Дело в том, что у большинства объектов, возвращаемых методом OverlapSphere(), метод Operate() отсутствует. Обычно, если объект не может получить сообщение, метод SendMessage() выводит сообщение об ошибке. Но сейчас это не требуется, так как мы и так знаем, что большая часть объектов проигнорирует рассылаемые сообщения.

Готовый сценарий нужно присоединить к объекту player. После этого для открытия и закрытия двери достаточно встать рядом с ней и нажать клавишу.

Осталась одна маленькая деталь. Пока что не имеет значения, как именно стоит персонаж, главное, чтобы он располагался достаточно близко к двери. Но можно сделать так, чтобы дверь открывалась только в случае, когда персонаж стоит к ней лицом. Напомню, что в главе 7 мы определяли направление движения персонажа, вычисляя скалярное произведение. Эта математическая операция с парой векторов возвращает значения в диапазоне от –1 до 1, где 1 означает одно и то же направление векторов, а –1 указывает на диаметрально противоположные направления. Следующий листинг демонстрирует код, который нужно добавить в сценарий DeviceOperator.

Листинг 8.3. Код, позволяющий открывать дверь, только стоя к ней лицом

...

foreach (Collider hitCollider in hitColliders) {

Vector3 direction = hitCollider.transform.position - transform.position;

if (Vector3.Dot(transform.forward, direction) > .5f) { ¬

Сообщение отправляется только

hitCollider.SendMessage("Operate",

при корректной ориентации персонажа.

SendMessageOptions.DontRequireReceiver);

 

}

 

}

 

...

 

Чтобы воспользоваться скалярным произведением, первым делом нужно определить направление, которое будет проверяться. Это направление от персонажа к объекту; нужный вектор создается вычитанием координат игрока из координат объекта. Затем вызывается метод Vector3.Dot(), которому передаются вычисленный вектор направления и вектор движения персонажа вперед. Если возвращенный методом результат близок к 1 (особенно при наличии в коде условия «больше чем 0.5»), значит, векторы имеют практически одно и то же направление.

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

8.1.3. Управление меняющим цвет монитором

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

8.1. Создание дверей и других устройств      193

сходным управлением; на этот раз это будет меняющий цвет монитор, прикрепленный к стене.

Создайте новый куб и расположите его таким образом, чтобы одна из граней практически соприкасалась со стеной. Например, я ввел в поля Position значения 10.9, 1.5, –5. Теперь создайте сценарий ColorChangeDevice, добавьте в него код из следующего листинга и присоедините сценарий к монитору. Запустите игру, подойдите к монитору и нажмите ту же самую клавишу, которой открывали дверь; монитор начнет менять цвет, как показано на рис. 8.2.

Рис. 8.2. Монитор, меняющий цвет

Листинг 8.4. Сценарий устройства, которое может менять цвет

using UnityEngine;

using System.Collections;

public class ColorChangeDevice : MonoBehaviour {

public void Operate() { ¬ Объявление метода с таким же именем, как в сценарии для двери.

Color random = new Color(Random.Range(0f,1f), Эти числа представляют собой RGB-значения Random.Range(0f,1f), Random.Range(0f,1f)); ¬ в диапазоне от 0 до 1.

GetComponent<Renderer>().material.color = random; ¬ Цвет задается в назначенном объекту материале.

}

}

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

ПРИМЕЧАНИЕ  Хотя в большинстве приложений для компьютерной графики цвет определяется компонентами Red, Blue и Green, параметры объекта Color в Unity лежат в диапазоне от 0 до 1, а не от 0 до 255, как это обычно бывает (в том числе и в интерфейсе выбора цвета в Unity).

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