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

3.2. Создаем активные цели      71

Код внутри функции OnGUI() определяет двухмерные координаты для отображения (слегка смещенные с учетом размера метки) и затем вызывает метод GUI.Label(). Этот метод отображает текстовую метку; так как переданная ему строка состоит из символа звездочки (*), именно он появляется в центре экрана. С ним прицеливаться в нашей будущей игре станет намного проще!

Кроме того, листинг 3.3 добавляет в метод Start() настройки указателя мыши, а именно возможность управлять его видимостью и возможность блокировки. В принципе, сценарий прекрасно работает и без этих настроек, но они делают элементы управления более удобными в использовании. Указатель мыши все время будет располагаться в центре экрана, а чтобы не заслонять обзор, мы сделаем его невидимым. Он будет появляться только при нажатии клавиши Esc.

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

Итак, код, управляющий поведением игрока, готов. Фактически, мы завершили работу над взаимодействиями игрока со сценой, но у нас все еще отсутствуют цели.

3.2. Создаем активные цели

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

3.2.1. Определяем точку попадания

Первым делом нам нужен объект, который послужит мишенью. Создайте куб (выбрав в меню GameObject команду 3D Object, а затем вариант Cube) и поменяйте его размер по вертикали, введя в поле Y для преобразования Scale значение 2. В полях X и Z оставьте значение 1. Поместите новый объект в точку с координатами 0, 1, 0, чтобы он стоял на полу в центре комнаты, и присвойте ему имя Enemy. Создайте сценарий с именем ReactiveTarget и присоедините его к объекту. Скоро мы напишем для этого сценария код, но пока оставьте его как есть; мы создали этот файл, так как без него код из следующего листинга компилироваться не будет. Вернитесь к сценарию RayShooter.cs и отредактируйте код испускания луча в соответствии с показанным листингом. Запустите новый вариант кода и попробуйте выстрелить в цель — вместо сферического индикатора на консоли появится отладочное сообщение.

Листинг 3.4. Распознавание попаданий в цель

...

if (Physics.Raycast(ray, out hit)) {

GameObject hitObject = hit.transform.gameObject; ¬ Получаем объект, в который попал луч. ReactiveTarget target = hitObject.GetComponent<ReactiveTarget>();

if (target != null) { ¬ Проверяем наличие у этого объекта компонента ReactiveTarget.

Debug.Log("Target hit");

72      Глава 3. Добавляем в игру врагов и снаряды

}else { StartCoroutine(SphereIndicator(hit.point));

}

}

...

Обратите внимание, что вы получаете объект, с которым пересекся луч, совсем так же, как получали координаты для сферических индикаторов. С технической точки зрения вам возвращается вовсе не игровой объект, а попавший под удар компонент Transform. Далее вы получаете доступ к объекту gameObject как к свойству класса transform.

Затем к этому объекту применяется метод GetComponent(), проверяющий, является ли он активной целью (то есть присоединен ли к нему сценарий ReactiveTarget). Как вы уже видели раньше, этот метод возвращает компоненты определенного типа, присоединенные к объекту GameObject. Если таковые отсутствуют, не возвращается ничего. Поэтому остается проверить, было ли возвращено значение null, и написать два варианта кода, которые будут запускаться в зависимости от результата проверки.

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

3.2.2. Уведомляем цель о попадании

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

Листинг 3.5. Отправка сообщения целевому объекту

...

if (target != null) {

target.ReactToHit(); ¬ Вызов метода для мишени вместо генерации отладочного сообщения.

}else { StartCoroutine(SphereIndicator(hit.point));

}

...

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

Рис. 3.4. Целевой объект, падающий после попадания

3.2. Создаем активные цели      73

Листинг 3.6. Сценарий ReactiveTarget, реализующий смерть врага при попадании

using UnityEngine;

using System.Collections;

public class ReactiveTarget : MonoBehaviour {

public void ReactToHit() { ¬ Метод, вызванный сценарием стрельбы.

StartCoroutine(Die());

}

private IEnumerator Die() { ¬ Опрокидываем врага, ждем 1,5 секунды и уничтожаем его. this.transform.Rotate(-75, 0, 0);

yield return new WaitForSeconds(1.5f);

Destroy(this.gameObject); ¬ Объект может уничтожать сам себя точно так же, как любой другой объект.

}

}

Большая часть кода должна быть вам уже знакома по предыдущим сценариям, поэтому рассматривать его мы будем совсем кратко. Первым делом мы определяем метод ReactToHit(), так как именно он вызывается в сценарии стрельбы. Этот метод запускает сопрограмму, аналогичную коду для сферических индикаторов, но на этот раз она призвана манипулировать объектом этого же сценария, а не создавать отдельный объект. Такие выражения, как this.gameObject, относятся к объекту GameObject, к которому присоединен данный сценарий (ключевое слово this указывать не обязательно, то есть можно ссылаться просто на gameObject).

Первая строка сопрограммы заставляет мишень опрокинуться. Как обсуждалось в главе 2, преобразование вращения можно определить как угол поворота относительно каждой из трех осей, X, Y и Z. Так как объект не должен поворачиваться из стороны в сторону, оставьте координатам Y и Z значение 0, а угол поворота назначьте координате X.

ПРИМЕЧАНИЕ  Преобразование происходит мгновенно, но, возможно, вы предпочитаете видеть, как опрокидываются мишени. После более детального знакомства с методами моделирования, возможно, вы захотите воспользоваться анимацией по начальной и конечной точкам (tweening), позволяющей смоделировать плавное движение объектов.

Во второй строке метода фигурирует ключевое слово yield, останавливающее выполнение сопрограммы и возвращающее количество секунд, через которое она возобновит свою работу. В последней строке функции игровой объект уничтожается. Функция Destroy(this.gameObject) вызывается после времени ожидания точно так же, как раньше мы вызывали код Destroy(sphere).

ВНИМАНИЕ  Аргумент функции Destroy() в данном случае должен выглядеть как this.gameObject, а не просто this! Не путайте эти два случая; само по себе ключевое слово this относится к компоненту данного сценария, в то время как this.gameObject означает объект, к которому присоединен данный сценарий.

Теперь наша мишень реагирует на попадание! Но больше она ничего не делает. Давайте добавим ей дополнительные поведения, чтобы превратить ее в настоящего врага.