- •Предисловие
- •Введение
- •Благодарности
- •О книге
- •Перспективы
- •Условные обозначения, требования и доступные для скачивания данные
- •Автор в Интернете
- •Об авторе
- •Глава 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. Назначение материала
256 Глава 10. Звуковые эффекты и музыка
Ведь Unity требуется компонент AudioSource. В случае звуков, испускаемых объектами сцены, место его присоединения очевидно. Но звуковые эффекты UI не являются частью сцены, поэтому вам нужно настроить специальный компонент AudioSource для диспетчера AudioManager. Он будет использоваться, если в сцене отсутствуют другие источники звука.
Создайте новый пустой объект GameObject и сделайте его дочерним по отношению к основному игровому диспетчеру. Так как у этого нового объекта будет компонент AudioSource, используемый диспетчером управления звуком, присвойте ему имя Audio. Добавьте к нему компонент AudioSource (на этот раз оставьте ползунок Spatial Blend в положении 2D, так как пользовательский интерфейс не имеет определенного положения в сцене) и добавьте в сценарий AudioManager код следующего листинга.
Листинг 10.7. Воспроизведение звуковых эффектов в диспетчере AudioManager
...
[SerializeField] private AudioSource soundSource; ¬ Ячейка переменной на панели Inspector для ссылки на новый источник звука.
...
public void PlaySound(AudioClip clip) { ¬ Воспроизводим звуки, не имеющие другого источника. soundSource.PlayOneShot(clip);
}
...
На панели Inspector появится новая ячейка переменной; перетащите на нее объект Audio. Теперь добавим звуковой эффект UI к сценарию всплывающего окна.
Листинг 10.8. Добавление звуковых эффектов в сценарий SettingsPopup
...
[SerializeField] private AudioClip sound; ¬ Ячейка на панели Inspector для ссылки на звуковой клип.
...
public void OnSoundToggle() {
Managers.Audio.soundMute = !Managers.Audio.soundMute; Managers.Audio.PlaySound(sound); ¬ Воспроизводим звуковой эффект при нажатии кнопки.
}
...
Перетащите звуковой эффект UI на ячейку переменной; я использовал 2D-звук thump. В результате щелчок на кнопке UI сопровождается этим звуком (если, конечно, вы не уменьшили его громкость до нуля!). И хотя сам UI не имеет источника звука, диспетчер AudioManager воспроизводит нужный звуковой эффект через свой источник.
Замечательно, мы настроили все звуковые эффекты! Пришло время обратить внимание на музыку.
10.4. Фоновая музыка
Теперь нам нужно вставить в игру фоновую музыку, а для этого ее нужно добавить в диспетчер AudioManager. Как объяснялось во введении к данной главе, музыкальные клипы, по сути, не отличаются от звуковых эффектов. Цифровой звук функционирует посредством звуковых волн тем же самым способом, команды его воспроизведения тоже по большей части одни и те же. Основное отличие состоит в размере клипа, но именно из этого вытекает ряд последствий.
10.4. Фоновая музыка 257
Во-первых, для музыкальных треков, как правило, требуется много компьютерной памяти, и этот расход необходимо оптимизировать. Нужно отслеживать два аспекта: загрузка музыки в память до того, как она начнет использоваться, и потребление слишком большого объема памяти при загрузке.
Оптимизация в процессе загрузки выполняется методом Resources.Load(), с которым вы познакомились в главе 8. Как вы узнали, этот метод позволяет загружать ресурсы по имени — это удобный инструмент, но есть и другие причины загружать ресурсы из папки Resources. Одним из ключевых факторов является отложенная загрузка; обычно все ресурсы в Unity загружаются вместе со сценой, но это не касается ресурсов из папки Resources, ожидающих извлечения с помощью кода. В этом разделе нас интересует загрузка музыкальных клипов по требованию. В противном случае музыка займет слишком много места в памяти, причем еще до того, как ею начнут пользоваться.
ОПРЕДЕЛЕНИЕ Загрузка по требованию (lazy-loading) означает, что загрузка файла заранее не делается, а откладывается до момента, когда этот файл понадобится. Обычно данные реагируют быстрее (например, немедленно начинается воспроизведение звука), когда они загружены заранее, но загрузка по требованию экономит память в ситуациях, когда быстрая реакция не имеет особого значения.
Второй способ решения проблемы с потреблением памяти связан с потоковой передачей музыки с диска. Как объяснялось в разделе 10.1.2, потоковая передача звука позволяет компьютеру обойтись без загрузки файла целиком. Тип загрузки указывается на панели Inspector импортированного аудиоклипа.
В конечном счете процедура подготовки к воспроизведению музыки делится на несколько этапов, в том числе включающих в себя оптимизацию потребления памяти.
10.4.1. Воспроизведение музыкальных циклов
Для воспроизведения музыки потребуется уже знакомая вам последовательность шагов, которой мы придерживались при программировании звуковых эффектов пользовательского интерфейса (фоновая музыка также является 2D-звуком, то есть не имеет источника в сцене), поэтому мы просто повторим ее:
1.Импортируем аудиоклипы.
2.Настраиваем компонент AudioSource для использования диспетчером AudioManager.
3.Пишем код для воспроизведения аудиоклипа в диспетчере AudioManager.
4.Добавляем UI-элементы управления музыкой.
Каждый шаг будет слегка модифицирован, так как теперь мы работаем с музыкой, а не со звуковыми эффектами. Рассмотрим первый шаг.
Шаг 1. Импорт аудиоклипов
Скачайте или запишите музыкальные треки. В прилагаемом к книге примере проекта я скачал с сайта www.freesound.org следующие композиции:
loop от пользователя by Xythe/Ville Nousiainen;Intro Synth от пользователя noirenex.
258 Глава 10. Звуковые эффекты и музыка
Перетащите файлы в Unity и отредактируйте их настройки импорта на панели Inspector. Как уже упоминалось, настройки аудиоклипов со звуковыми эффектами и с музыкой в общем случае различаются. Прежде всего, для звука со сжатием следует выбрать формат Vorbis. Напомню, что в результате сжатия размер файлов значительно уменьшается. Одновременно слегка ухудшается качество звука, но для длинных музыкальных клипов это вполне допустимый компромисс; установите ползунок Quality на отметку 50 %.
Затем нужно выбрать параметр Load Type. Еще раз напомню, что нам нужно чтение музыки с диска, а не ее полная загрузка. Выберите в меню Load Type вариант Streaming. Установите флажок Load In Background, чтобы в процессе загрузки музыки игра не останавливалась и не замедлялась.
И даже после всех этих настроек для корректной загрузки нужно еще поместить аудиофайл в нужное место. Надеюсь, вы помните, что метод Resources.Load() загружает только содержимое папки Resources. Создайте новую папку с этим именем, а внутри нее — папку Music и перетащите туда аудиофайлы, как показано на рис. 10.5.
Рис. 10.5. Музыкальные аудиоклипы, помещенные в папку Resources
Это даст возможность выполнить шаг 1.
Шаг 2. Настройка компонента audiosource для использования диспетчером управления звуком
Теперь нам нужно создать новый компонент AudioSource для воспроизведения музыки. Создайте пустой объект GameObject, присвойте ему имя Music 1 (единица появилась потому, что позднее мы добавим объект Music 2) и сделайте его дочерним по отношению к объекту Audio.
Добавьте к объекту Music 1 компонент AudioSource и отредактируйте его параметры. Сбросьте флажок Play On Awake, но установите флажок Loop; если звуковой эффект обычно проигрывается один раз, музыка воспроизводится в цикле. Ползунок Spatial Blend оставьте в положении 2D, так как музыка не привязана к конкретной точке сцены.
Возможно, вы захотите уменьшить параметр Priority. Для звуковых эффектов мы оставили заданное по умолчанию значение 128, но для музыки имеет смысл снизить его примерно до 60. При наложении друг на друга различных звуков этот параметр указывает Unity, какие из звуков имеют больший приоритет; как ни странно, более низкие значения указывают на более высокий приоритет. При одновременном
10.4. Фоновая музыка 259
воспроизведении слишком большого количества звуков аудиосистема начинает пропускать некоторые из них; увеличив приоритет музыки, мы гарантируем, что она будет звучать, даже если одновременно запустится множество звуковых эффектов.
Шаг 3. Программирование механизма воспроизведения аудиоклипов в диспетчере управления звуком
Мы настроили источник аудио Music, поэтому нужно добавить код следующего листинга в сценарий AudioManager.
Листинг 10.9. Воспроизведение музыки в диспетчере AudioManager
...
[SerializeField] private AudioSource music1Source;
[SerializeField] private string introBGMusic; │ Эти строки указывают имена музыкальных клипов. [SerializeField] private string levelBGMusic; │
...
public void PlayIntroMusic() { ¬ Загрузка музыки intro из папки Resources.
PlayMusic(Resources.Load("Music/"+introBGMusic) as AudioClip);
}
public void PlayLevelMusic() { ¬ Загрузка основной музыки из папки Resources.
PlayMusic(Resources.Load("Music/"+levelBGMusic) as AudioClip);
}
private void PlayMusic(AudioClip clip) { ¬ Воспроизведение музыки при помощи параметра AudioSource.clip. music1Source.clip = clip;
music1Source.Play();
}
public void StopMusic() { music1Source.Stop();
}
...
Как обычно, при выборе игрового диспетчера на панели Inspector можно увидеть новые сериализованные переменные. Перетащите на ячейку для источника аудио клип Music 1. Затем введите в две строковые переменные имена музыкальных файлов: introsynth и loop.
Остальная часть нового кода вызывает команды загрузки и воспроизведения музыки (или в последнем добавленном методе — остановки музыки). Команда Resources. Load() загружает именованный ресурс из папки Resources (учитывая, что нужные файлы расположены во вложенной папке Music). Эта команда возвращает обобщенный объект, но его можно преобразовать к конкретному типу (в данном случае — к типу AudioClip), воспользовавшись ключевым словом as.
Затем загруженный аудиоклип передается в метод PlayMusic(), который настраивает клип в компоненте AudioSource и вызывает метод Play(). Как я уже объяснял, звуковые эффекты лучше воспроизводятся методом PlayOneShot(), но установка клипа в компоненте AudioSource является более надежным подходом, позволяющим кроме всего прочего на время или совсем останавливать воспроизведение музыки.
260 Глава 10. Звуковые эффекты и музыка
Шаг 4. Добавление в UI элементов управления музыкой
Чтобы новые методы воспроизведения музыки выполняли какие-либо действия, их нужно откуда-то вызвать. Добавим к нашему UI дополнительные кнопки, щелчки на которых позволят включать разную музыку. Сейчас я опять перечислю этапы этого процесса с краткими пояснениями (подробности вы сможете найти в главе 6):
1.Измените ширину всплывающего окна на 350 (чтобы на нем поместились дополнительные кнопки).
2.Создайте новую кнопку и сделайте ее дочерним объектом по отношению к всплывающему окну.
3.Ширину кнопки сделайте равной 100 и поместите ее в точку с координатами 0, –20.
4.Раскройте иерархический список кнопки, выделите текстовую метку и поменяйте текст на Level Music.
5.Повторите эту последовательность еще два раза, чтобы создать две дополнительные кнопки.
6.Одну из них поместите в точку с координатами –105, –20, вторую — в точку с координатами 105, –20 (чтобы она появилась с другой стороны).
7.Текстовую метку первой кнопки поменяйте на Intro Music, второй — на No Music.
Теперь у нас есть три кнопки для воспроизведения различной музыки. Скопируйте метод из следующего листинга в сценарий SettingsPopup, который мы свяжем с каждой из кнопок.
Листинг 10.10. Добавление элементов управления музыкой в сценарий SettingsPopup
...
public void OnPlayMusic(int selector) { ¬ Этот метод получает от кнопки численный параметр.
Managers.Audio.PlaySound(sound);
switch (selector) { ¬ Вызываем для каждой кнопки свою музыкальную функцию в диспетчере AudioManager. case 1:
Managers.Audio.PlayIntroMusic();
break; case 2:
Managers.Audio.PlayLevelMusic();
break;
default:
Managers.Audio.StopMusic();
break;
}
}
...
Обратите внимание, что на этот раз функция принимает параметр типа int; как правило, связанные с кнопками методы лишены параметров и просто срабатывают по щелчку. Но сейчас нам нужно различие между кнопками, именно поэтому каждой присваивается свой номер.
При помощи стандартной процедуры свяжем кнопку с этим кодом: добавьте элемент в список OnClick на панели Inspector, перетащите всплывающее окно на ячейку объекта