- •Предисловие
- •Введение
- •Благодарности
- •О книге
- •Перспективы
- •Условные обозначения, требования и доступные для скачивания данные
- •Автор в Интернете
- •Об авторе
- •Глава 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. Назначение материала
2.3. Двигаем объекты: сценарий, активирующий преобразования 47
выглядит как окружающая объект зеленая сетка, поэтому после удаления компонента вы обнаружите, что она исчезла.
Щ а а
а
а Remove Component
Рис. 2.10. Удаление компонента на панели Inspector
Вместо капсульного коллайдера мы назначим объекту контроллер персонажа. В нижней части панели Inspector вы найдете кнопку Add Component. Щелчок на ней открывает меню с перечнем типов доступных компонентов. В разделе Physics и находится нужная нам строка Character Controller. Как несложно догадаться, именно этот компонент позволит объекту вести себя как персонаж.
Для завершения настройки игрока осталось сделать всего один шаг — присоединить к нему камеру. Как уже упоминалось в разделе, посвященном созданию пола и стен, вы можете перетаскивать объекты и класть их друг на друга на вкладке Hierarchy. Проделайте эту операцию, перетащив камеру на капсулу, чтобы присоединить ее к игроку. Затем расположите ее таким образом, чтобы она соответствовала глазам игрока (я предлагаю указать координаты 0, 0.5, 0). При необходимости верните координатам преобразования поворота значения 0, 0, 0 (если вы вращали капсулу, они будут различаться).
Итак, в сцене присутствуют все необходимые объекты. Осталось написать код перемещения игрока.
2.3. Двигаем объекты: сценарий, активирующий преобразования
Чтобы заставить игрока перемещаться по сцене, нам потребуются сценарии движения, которые будут присоединены к игроку. Напоминаю, что компонентами называются модульные фрагменты функциональности, добавляемые к объектам, поэтому сценарии тоже можно считать своего рода компонентами. Именно они будут реагировать на клавиатурный ввод и манипуляции мышью, но для начала мы заставим игрока поворачиваться на месте. Это продемонстрирует вам, как применять преобразования в коде. Надеюсь, вы помните, что преобразования бывают трех видов — перемещение, поворот и масштабирование; вращение объекта на месте соответствует преобразованию поворота. Но вы должны знать об этой задаче еще кое-что, кроме того, что она «сводится к изменению ориентации объекта».
48 Глава 2. Создание 3D-ролика
2.3.1. Схема программирования движения
Анимация объекта (например, его вращение) сводится к смещению его в каждом кадре на небольшое расстояние и к последующему многократному воспроизведению всех кадров. Само по себе преобразование происходит мгновенно, в отличие от движения, растянутого во времени. Но последовательное применение набора преобразований вызывает визуальное перемещение объекта, совсем как набор рисунков в кинеографе. Этот принцип проиллюстрирован на рис. 2.11.
Ка 1 |
Ка 2 |
Ка 3 |
Ка 4 |
П а |
П а |
П а |
а 15 а |
а 15 а |
а 15 а |
Рис. 2.11. Возникновение движения: циклический процесс преобразования статичных изображений
Напомню вам, что компоненты сценария снабжены запускающимся в каждом кадре методом Update(). Поэтому, чтобы заставить куб вращаться вокруг своей оси, следует добавить в метод Update() код, поворачивающий его на небольшой угол. Этот код будет запускаться в каждом кадре снова и снова. Не правда ли, все очень просто?
2.3.2. Написание кода
Применим рассмотренную концепцию на практике. Создайте новый сценарий командой C# script (напоминаю, что она находится в дополнительном меню Create, доступ к которому осуществляется через меню Assets), присвойте ему имя Spin и напишите код из следующего листинга (не забудьте после ввода листинга сохранить файл!).
Листинг 2.1. Приводим объект во вращение
using UnityEngine;
using System.Collections;
public class Spin : MonoBehaviour {
public float speed = 3.0f; ¬ Объявление общедоступной переменной для скорости вращения.
void Update() {
transform.Rotate(0, speed, 0); ¬ Поместите сюда команду Rotate, чтобы она запускалась в каждом кадре.
}
}
Для добавления компонента сценария к игроку перетащите сценарий с вкладки Project на строку Player на вкладке Hierarchy. Щелкните на кнопке Play, и вы увидите, как все
2.3. Двигаем объекты: сценарий, активирующий преобразования 49
придет во вращение — вы написали код, заставляющий объект двигаться! В основном этот код состоит из шаблона нового сценария, к которому добавлены две строки. Посмотрим, что именно они делают.
Прежде всего, появилась переменная для скорости, добавленная в верхнюю часть определения класса. Превращение скорости вращения в переменную произошло по двум причинам. Первая — это соблюдение стандартного правила программирования: «никаких магических чисел». Вторая же причина связана со способом отображения общедоступных переменных в Unity. Познакомимся с ним.
СОВЕТ Общедоступные переменные появляются на панели Inspector, что позволяет редактировать значения уже добавленных к игровому объекту компонентов. Это называется «сериализацией» значения, так как Unity сохраняет модифицированное состояние переменной.
Рисунок 2.12 показывает вид компонента сценария на панели Inspector. Можно ввести новое значение, и сценарий будет использовать его вместо указанного в коде. Таким способом удобно редактировать параметры компонентов различных объектов непосредственно в визуальном редакторе вместо того, чтобы заниматься правкой кода.
Рис. 2.12. На панели Inspector
присутствует объявленная в сценарии общедоступная переменная
Вторая строка, на которую следует обратить внимание в листинге 2.1, касается метода Rotate(). Он вставлен в метод Update(), а значит, выполняется в каждом кадре. Так как метод Rotate() принадлежит классу Transform, он вызывается при помощи точечной нотации через компонент преобразования объекта (как и в большинстве объект но-ориентированных языков, если вы введете transform, это будет восприниматься как this.transform). В рассматриваемом случае преобразование сводится к повороту на speed градусов в каждом кадре, что в итоге даст нам плавное вращение. Но почему параметры метода Rotate() указаны как (0, speed, 0), а не, допустим, (speed, 0, 0)?
Вспомните, что в трехмерном пространстве есть три оси: X, Y и Z. Интуитивно понятно, каким образом они связаны с местоположением объекта и его перемещениями, но, кроме того, их применяют для описания преобразования поворота. Сходным образом описывают вращение в воздухоплавании, поэтому работающие с трехмерной графикой программисты зачастую пользуются терминами из механики полета: тангаж (pitch), рысканье (yaw) и крен (roll). Значение этих терминов иллюстрирует рис. 2.13; тангаж означает вращение вокруг оси X, рысканье — вращение вокруг оси Y, крен — вращение вокруг оси Z.
Возможность описывать вращение вокруг осей X, Y и Z означает три параметра для метода Rotate(). Так как нам требуется только вращение вокруг своей оси без наклонов вперед и назад, меняться должна только координата Y, координатам же X и Z мы просто присвоим значение 0. Надеюсь, вы уже поняли, что получится, если изменить параметры на (speed, 0, 0) и запустить воспроизведение сцены; попробуйте реализовать это на практике!
Существует еще одна тонкость, связанная с вращением и осями координат, реализованная в виде необязательного четвертого параметра метода Rotate().
50 Глава 2. Создание 3D-ролика
К
Та а
Р а
Рис. 2.13. Тангаж, рысканье и крен самолета
2.3.3. Локальные и глобальные координаты
По умолчанию метод Rotate() работает с так называемыми локальными координатами, хотя вы также можете использовать глобальную систему координат. Вы сообщаете методу, какой именно системой координат хотите воспользоваться, при помощи четвертого необязательного параметра, который может принимать два значения:
Space.Self и Space.World. Например:
Rotate(0, speed, 0, Space.World)
Вернитесь к описанию трехмерного координатного пространства и хорошенько подумайте над следующими вопросами: где находится точка (0, 0, 0)? как выбирается положительное направление оси X? может ли перемещаться сама координатная система?
Оказывается, у каждого объекта есть собственная точка начала координат и собственные положительные направления осей. И эта координатная система перемещается вместе с объектом. В таких случаях говорят о локальных координатах. При этом трехмерная сцена как целое обладает собственной точкой начала координат и собственными направлениями осей, причем такая координатная система всегда статична. Это так называемые глобальные координаты. Соответственно, указывая вариант системы координат для метода Rotate(), вы сообщаете, относительно каких осей X, Y и Z нужно выполнить преобразование поворота (рис. 2.14).
Новичкам в области трехмерной графики эта концепция может показаться сложной для понимания. Различные оси показаны на рис. 2.14 (обратите внимание, что, к примеру, понятие «лево» для самолета отличается от понятия «лево» для сцены в целом), но разницу между локальными и глобальными координатами проще всего понять на примере.