- •Предисловие
- •Введение
- •Благодарности
- •О книге
- •Перспективы
- •Условные обозначения, требования и доступные для скачивания данные
- •Автор в Интернете
- •Об авторе
- •Глава 1. Знакомство с Unity
- •1.1. Достоинства Unity
- •1.1.1. Сильные стороны и преимущества Unity
- •1.1.2. Недостатки, о которых нужно знать
- •1.1.3. Примеры игр на основе Unity
- •1.2. Как работать с Unity
- •1.2.1. Вкладка Scene, вкладка Game и панель инструментов
- •1.2.2. Работа с мышью и клавиатурой
- •1.2.3. Вкладка Hierarchy и панель Inspector
- •1.2.4. Вкладки Project и Console
- •1.3. Готовимся программировать в Unity
- •1.3.1. Запуск кода в Unity: компоненты сценария
- •1.3.2. Программа MonoDevelop — межплатформенная среда разработки
- •1.4. Заключение
- •Глава 2. Создание 3D-ролика
- •2.1. Подготовка…
- •2.1.1. Планирование проекта
- •2.1.2. Трехмерное координатное пространство
- •2.2. Начало проекта: размещение объектов
- •2.2.1. Декорации: пол, внешние и внутренние стены
- •2.2.2. Источники света и камеры
- •2.2.3. Коллайдер и точка наблюдения игрока
- •2.3. Двигаем объекты: сценарий, активирующий преобразования
- •2.3.1. Схема программирования движения
- •2.3.2. Написание кода
- •2.3.3. Локальные и глобальные координаты
- •2.4. Компонент сценария для осмотра сцены: MouseLook
- •2.4.1. Горизонтальное вращение, следящее за указателем мыши
- •2.4.2. Поворот по вертикали с ограничениями
- •2.4.3. Одновременные горизонтальное и вертикальное вращения
- •2.5. Компонент для клавиатурного ввода
- •2.5.1. Реакция на нажатие клавиш
- •2.5.2. Независимая от скорости работы компьютера скорость перемещений
- •2.5.4. Ходить, а не летать
- •2.6. Заключение
- •3.1. Стрельба путем бросания лучей
- •3.1.1. Что такое бросание лучей?
- •3.1.2. Имитация стрельбы командой ScreenPointToRay
- •3.1.3. Добавление визуальных индикаторов для прицеливания и попаданий
- •3.2. Создаем активные цели
- •3.2.1. Определяем точку попадания
- •3.2.2. Уведомляем цель о попадании
- •3.3. Базовый искусственный интеллект для перемещения по сцене
- •3.3.1. Диаграмма работы базового искусственного интеллекта
- •3.3.2. «Поиск» препятствий методом бросания лучей
- •3.3.3. Слежение за состоянием персонажа
- •3.4.1. Что такое шаблон экземпляров?
- •3.4.2. Создание шаблона врага
- •3.4.3. Экземпляры невидимого компонента SceneController
- •3.5. Стрельба путем создания экземпляров
- •3.5.1. Шаблон снаряда
- •3.5.2. Стрельба и столкновение с целью
- •3.5.3. Повреждение игрока
- •3.6. Заключение
- •Глава 4. Работа с графикой
- •4.1. Основные сведения о графических ресурсах
- •4.2. Создание геометрической модели сцены
- •4.2.1. Назначение геометрической модели
- •4.2.2. Рисуем план уровня
- •4.2.3. Расставляем примитивы в соответствии с планом
- •4.3. Наложение текстур
- •4.3.1. Выбор формата файла
- •4.3.2. Импорт файла изображения
- •4.3.3. Назначение текстуры
- •4.4. Создание неба с помощью текстур
- •4.4.1. Что такое скайбокс?
- •4.4.2. Создание нового материала для скайбокса
- •4.5. Собственные трехмерные модели
- •4.5.1. Выбор формата файла
- •4.5.2. Экспорт и импорт модели
- •4.6. Системы частиц
- •4.6.1. Редактирование параметров эффекта
- •4.6.2. Новая текстура для пламени
- •4.6.3. Присоединение эффектов частиц к трехмерным объектам
- •4.7. Заключение
- •5.1. Подготовка к работе с двухмерной графикой
- •5.1.1. Подготовка проекта
- •5.1.2. Отображение двухмерных изображений (спрайтов)
- •5.1.3. Переключение камеры в режим 2D
- •5.2. Создание карт и превращение их в интерактивные объекты
- •5.2.1. Создание объекта из спрайтов
- •5.2.2. Код ввода с помощью мыши
- •5.2.3. Открытие карты по щелчку
- •5.3. Отображение различных карт
- •5.3.1. Программная загрузка изображений
- •5.3.3. Создание экземпляров карт
- •5.3.4. Тасуем карты
- •5.4. Совпадения и подсчет очков
- •5.4.1. Сохранение и сравнение открытых карт
- •5.4.2. Скрытие несовпадающих карт
- •5.4.3. Текстовое отображение счета
- •5.5. Кнопка Restart
- •5.5.1. Добавление к компоненту UIButton метода SendMessage
- •5.5.2. Вызов метода LoadLevel в сценарии SceneController
- •5.6. Заключение
- •Глава 6. Двухмерный GUI для трехмерной игры
- •6.1. Перед тем как писать код…
- •6.1.1. IMGUI или усовершенствованный 2D-интерфейс?
- •6.1.2. Выбор компоновки
- •6.1.3. Импорт изображений UI
- •6.2. Настройка GUI
- •6.2.1. Холст для интерфейса
- •6.2.2. Кнопки, изображения и текстовые подписи
- •6.2.3. Управление положением элементов UI
- •6.3. Программирование интерактивного UI
- •6.3.1. Программирование невидимого объекта UIController
- •6.3.2. Создание всплывающего окна
- •6.3.3. Задание значений с помощью ползунка и поля ввода
- •6.4. Обновление игры в ответ на события
- •6.4.1. Интегрирование системы сообщений
- •6.4.2. Рассылка и слушание сообщений сцены
- •6.4.3. Рассылка и слушание сообщений проекционного дисплея
- •6.5. Заключение
- •7.1. Корректировка положения камеры
- •7.1.1. Импорт персонажа
- •7.1.2. Добавление в сцену теней
- •7.1.3. Облет камеры вокруг персонажа
- •7.2. Элементы управления движением, связанные с камерой
- •7.2.1. Поворот персонажа лицом в направлении движения
- •7.2.2. Движение вперед в выбранном направлении
- •7.3. Выполнение прыжков
- •7.3.1. Добавление вертикальной скорости и ускорения
- •7.3.2. Распознавание поверхности с учетом краев и склонов
- •7.4. Анимация персонажа
- •7.4.1. Создание анимационных клипов для импортированной модели
- •7.4.2. Создание контроллера для анимационных клипов
- •7.4.3. Код, управляющий контроллером-аниматором
- •7.5. Заключение
- •8.1. Создание дверей и других устройств
- •8.1.1. Открывание и закрывание дверей
- •8.1.2. Проверка расстояния и направления перед открытием двери
- •8.1.3. Управление меняющим цвет монитором
- •8.2. Взаимодействие с объектами путем столкновений
- •8.2.1. Столкновение с препятствиями, обладающими физическими свойствами
- •8.2.2. Управление дверью с помощью триггера
- •8.2.3. Сбор разбросанных по игровому уровню элементов
- •8.3. Управление инвентаризационными данными и состоянием игры
- •8.3.1. Настраиваем диспетчеры игрока и инвентаря
- •8.3.2. Программирование диспетчеров
- •8.3.3. Сохранение инвентаря в виде коллекции: списки и словари
- •8.4. Интерфейс для использования и подготовки элементов
- •8.4.1. Отображение элементов инвентаря в UI
- •8.4.2. Подготовка ключа для открытия двери
- •8.4.3. Восстановление здоровья персонажа
- •8.5. Заключение
- •9.1. Создание натурной сцены
- •9.1.1. Генерирование неба с помощью скайбокса
- •9.1.2. Настройка управляемой кодом атмосферы
- •9.2. Скачивание сводки погоды из Интернета
- •9.2.1. Запрос веб-данных через сопрограмму
- •9.2.2. Парсинг текста в формате XML
- •9.2.3. Парсинг текста в формате JSON
- •9.2.4. Изменение вида сцены на базе данных о погоде
- •9.3. Добавление рекламного щита
- •9.3.1. Загрузка изображений из Интернета
- •9.3.2. Вывод изображения на щите
- •9.3.3. Кэширование скачанного изображения
- •9.4. Отправка данных на веб-сервер
- •9.4.1. Слежение за погодой: отправка запросов POST
- •9.4.2. Серверный код в PHP-сценарии
- •9.5. Заключение
- •Глава 10. Звуковые эффекты и музыка
- •10.1. Импорт звуковых эффектов
- •10.1.1. Поддерживаемые форматы файлов
- •10.1.2. Импорт аудиофайлов
- •10.2. Воспроизведение звуковых эффектов
- •10.2.1. Система воспроизведения: клипы, источник, подписчик
- •10.2.2. Присваивание зацикленного звука
- •10.2.3. Активация звуковых эффектов из кода
- •10.3. Интерфейс управления звуком
- •10.3.1. Настройка центрального диспетчера управления звуком
- •10.3.2. UI для управления громкостью
- •10.3.3. Воспроизведение звуков UI
- •10.4. Фоновая музыка
- •10.4.1. Воспроизведение музыкальных циклов
- •10.4.2. Отдельная регулировка громкости
- •10.4.3. Переход между песнями
- •10.5. Заключение
- •Глава 11. Объединение фрагментов в готовую игру
- •11.1. Построение ролевого боевика изменением назначения проектов
- •11.1.1. Сборка ресурсов и кода из разных проектов
- •11.1.2. Элементы наведения и щелчка
- •11.1.3. Замена старого GUI новым
- •11.2. Разработка общей игровой структуры
- •11.2.1. Управление ходом миссии и набором уровней
- •11.2.2. Завершение уровня
- •11.2.3. Проигрыш уровня
- •11.3. Обработка хода игры
- •11.3.1. Сохранение и загрузка достижений игрока
- •11.3.2. Победа в игре при прохождении всех уровней
- •11.4. Заключение
- •Глава 12. Развертывание игр на устройствах игроков
- •12.1. Создание приложений для настольных компьютеров: Windows, Mac и Linux
- •12.1.1. Построение приложения
- •12.1.2. Настройки проигрывателя: имя и значок приложения
- •12.1.3. Компиляция в зависимости от платформы
- •12.2. Создание игр для Интернета
- •12.2.1. Проигрыватель Unity и HTML5/WebGL
- •12.2.2. Создание файла Unity и тестовой веб-страницы
- •12.2.3. Обмен данными с JavaScript в браузере
- •12.3. Сборки для мобильных устройств: iOS и Android
- •12.3.1. Настройка инструментов сборки
- •12.3.2. Сжатие текстур
- •12.3.3. Разработка подключаемых модулей
- •12.4. Заключение
- •Приложение А. Перемещение по сцене и клавиатурные комбинации
- •А.1. Навигация с помощью мыши
- •А.2. Распространенные клавиатурные комбинации
- •Б.1. Инструменты программирования
- •Б.1.1. Visual Studio
- •Б.1.2. Xcode
- •Б.1.3. Android SDK
- •Б.1.4. SVN, Git или Mercurial
- •Б.2. Приложения для работы с трехмерной графикой
- •Б.2.1. Maya
- •Б.2.3. Blender
- •Б.3. Редакторы двухмерной графики
- •Б.3.1. Photoshop
- •Б.3.2. GIMP
- •Б.3.3. TexturePacker
- •Б.4. Звуковое программное обеспечение
- •Б.4.1. Pro Tools
- •Б.4.2. Audacity
- •Приложение В. Моделирование скамейки в программе Blender
- •В.1. Создание сеточной геометрии
- •В.2. Назначение материала
82 Глава 3. Добавляем в игру врагов и снаряды
Поэтому в Unity существует метод Destroy(), заставляющий игровой движок удалять объект из графа сцены. Как часть этой фоновой функциональности в Unity также перегружается оператор == и начинает возвращать значение true при проверке на наличие значения null. Технически объект все еще находится в памяти, но при этом он может больше не существовать, поэтому Unity показывает его равенство значению null. Это можно проверить, вызвав для уничтоженного объекта метод GetInstanceID().
Впрочем, разработчики Unity обдумывают замену этого поведения более стандартным вариантом управления памятью. Если подобное произойдет, придется поменять и код порождения врагов, указав вместо проверки (_enemy==null) новый параметр, например (_enemy.isDestroyed). Следите за новостями в социальной сети Facebook по адресу https://www.facebook.com/unity3d/ posts/10152271098591773.
(Если большая часть данного примечания осталась вам непонятной, просто не обращайте на него внимания; это было лирическое отступление для пользователей, заинтересованных в непонятных деталях.)
3.5. Стрельба путем создания экземпляров
Хорошо, добавим врагам еще немного способностей. Пойдем по тому же пути, что и при работе над игроком. Первым делом мы научили врагов двигаться, теперь дадим им возможность стрелять! Как я упоминал, знакомя вас с приемом испускания луча, этот прием является всего лишь одним из подходов к реализации стрельбы. Другой вариант реализации — создание экземпляров из шаблона. Воспользуемся им, чтобы заставить врагов отстреливаться. Результат, который нужно получить, показан на рис. 3.9.
Рис. 3.9. Враг бросает в игрока «огненный шар»
3.5.1. Шаблон снаряда
Если раньше мы стреляли без применения реальных снарядов, то теперь они нам понадобятся. Стрельба приемом испускания лучей, по сути, мгновенна, и попадание регистрируется в момент щелчка кнопкой мыши, враги же будут бросать «огненные шары», летающие по воздуху. Разумеется, хотя они двигаются довольно быстро, у игрока будет возможность уклониться. Фиксировать попадания мы будем не методом испускания лучей, а методом распознавания столкновений (это уже знакомый вам метод, не дающий игроку проходить сквозь стены).
3.5. Стрельба путем создания экземпляров 83
Код будет порождать огненные шары тем же способом, которым порождаются враги, — созданием экземпляров из шаблона. Как вы знаете из предыдущего раздела, первым шагом в подобных случаях является создание объекта, который послужит основой для шаблона. Так как нам требуется огненный шар, выберите в меню GameObject команду 3D Object и в дополнительном меню команду Sphere. Присвойте появившейся сфере имя Fireball. Теперь создайте новый сценарий с таким же именем и присоедините его к объекту. Чуть позже мы напишем для него код, а пока оставьте вариант, предлагаемый по умолчанию, так как первым делом мы завершим работу над снарядом. Чтобы он напоминал огненный шар, ему нужно присвоить ярко-оранжевый цвет. Такие свойства поверхностей, как цвет, контролируются при помощи материалов.
ОПРЕДЕЛЕНИЕ Материалом (material) называется пакет информации, определяющий свойства поверхности любого трехмерного объекта, к которому этот пакет присоединен. К свойствам поверхности относятся цвет, блеск и даже небольшая шероховатость.
Выберите в меню Assets команду Create и в дополнительном меню команду Material. Присвойте новому материалу имя Flame. Выберите его на вкладке Project, чтобы увидеть его свойства на панели Inspector. Как показано на рис. 3.10, щелкните на цветовой ячейке с именем Albedo (это технический термин, означающий основной цвет поверхности). В отдельном окне откроется палитра цветов; переместите расположенный справа ползунок и точку в основной области таким образом, чтобы выбрать оранжевый цвет.
Щ а |
В |
|
, |
||
а а а а |
||
а |
||
а |
||
|
Рис. 3.10. Выбор цвета материала
Еще мы увеличим яркость материала, чтобы придать ему большее сходство с пламенем. Отредактируйте параметр Emission (он тоже находится в списке атрибутов панели Inspector). По умолчанию он равен 0, присвойте ему значение 0.3, чтобы сделать материал более ярким.
Теперь можно превратить наш огненный шар в шаблон, перетащив его со вкладки Hierarchy на вкладку Project, как мы делали, создавая шаблон врага. Теперь у нас есть основа для наших снарядов! Осталось написать код стрельбы.
84 Глава 3. Добавляем в игру врагов и снаряды
3.5.2. Стрельба и столкновение с целью
Отредактируем шаблон врага, наделив его способностью кидать огненные шары. Чтобы код распознавал игрока, потребуется новый сценарий (аналогично тому, как сценарий ReactiveTarget требовался для распознавания мишеней), поэтому создадим сценарий с именем PlayerCharacter и присоединим его к игроку.
А теперь откроем сценарий WanderingAI и введем в него код следующего листинга.
Листинг 3.11. Сценарий WanderingAI с возможностью кидать огненные шары
... |
|
Эти два поля добавляются перед любыми |
|
[SerializeField] private GameObject fireballPrefab; ¬ |
|||
private GameObject _fireball; |
|
методами, как и в сценарии SceneController. |
|
|
|
||
... |
|
|
|
if (Physics.SphereCast(ray, 0.75f, out hit)) { |
|
||
GameObject hitObject = hit.transform.gameObject; |
Игрок распознается тем же способом, |
||
if (hitObject.GetComponent<PlayerCharacter>()) { ¬ |
|||
что и мишень в сценарии RayShooter. |
|||
if (_fireball == null) { ¬ Та же самая логика с пустым игровым объектом, что и в сценарии SceneController. |
|||
_fireball = Instantiate(fireballPrefab) as GameObject; ¬ Метод Instantiate() работает так же, |
|||
|
|
как и в сценарии SceneController. |
|
_fireball.transform.position = ¬ |
Поместим огненный шар перед врагом |
||
|
и нацелим в направлении его движения. |
transform.TransformPoint(Vector3.forward * 1.5f); _fireball.transform.rotation = transform.rotation;
}
}
else if (hit.distance < obstacleRange) { float angle = Random.Range(-110, 110); transform.Rotate(0, angle, 0);
}
}
...
Думаю, вы заметили, что все примечания к этому листингу ссылаются на сходные (или аналогичные) фрагменты предыдущих сценариев. Фактически, в предыдущих листингах вы уже видели весь код, необходимый для бросания огненных шаров; мы просто смешали эти фрагменты друг с другом в соответствии с новым контекстом.
Как и в листинге SceneController, в верхнюю часть сценария нужно добавить два поля GameObject: сериализованную переменную, с которой будет связываться шаб лон, и закрытую переменную для слежения за созданным кодом экземпляром этого шаблона. После испускания луча идет проверка попадания в объект PlayerCharacter; это работает аналогично тому, как код стрельбы проверял наличие у пораженного объекта компонента ReactiveTarget. Код, создающий экземпляр огненного шара при отсутствии таких шаров в сцене, работает как код создания экземпляров врага. Отличаются только размещение и ориентация объектов; на этот раз мы помещаем экземпляр, полученный из шаблона, перед врагом и нацеливаем в направлении его движения.
Как только новый код окажется на своем месте, на панели Inspector появится новое поле Fireball Prefab, точно так же, как в свое время для компонента SceneController появилось поле Enemy Prefab. Щелкните на шаблоне врага на вкладке Project, и на панели Inspector появятся компоненты этого объекта, как если бы вы выделили его в сцене.
3.5. Стрельба путем создания экземпляров 85
Хотя упомянутое ранее неудобство интерфейса часто проявляется при редактировании шаблонов, именно интерфейс дает нам возможность легко редактировать компоненты объекта, чем мы сейчас и воспользуемся. Перетащите шаблон огненного шара со вкладки Project на поле Fireball Prefab панели Inspector, как показано на рис. 3.11.
П а а а а а Project а а Inspector
Рис. 3.11. Соединение огненного шара со сценарием
Теперь, как только игрок окажется непосредственно перед врагом, в него полетит огненный шар… Попробуйте выполнить воспроизведение — перед врагом появится огненная сфера, но никуда не полетит, потому что мы пока не написали соответствующий сценарий. Давайте сделаем это сейчас. Код сценария Fireball приведен в следующем листинге.
Листинг 3.12. Сценарий Fireball, реагирующий на столкновения
using UnityEngine;
using System.Collections;
public class Fireball : MonoBehaviour { public float speed = 10.0f;
public int damage = 1;
void Update() {
transform.Translate(0, 0, speed * Time.deltaTime);
}
Эта функция вызывается, когда с триггером void OnTriggerEnter(Collider other) { ¬ сталкивается другой объект.
PlayerCharacter player = other.GetComponent<PlayerCharacter>();
if (player != null) { ¬ Проверяем, является ли этот другой объект объектом PlayerCharacter.
Debug.Log("Player hit");
}
Destroy(this.gameObject);
}
}
Существенным новшеством в этом коде является метод OnTriggerEnter(). Он автоматически вызывается при столкновении объекта, например, со стеной или с игроком. Пока что наш код работает не совсем корректно; после его запуска огненный шар