- •Предисловие
- •Введение
- •Благодарности
- •О книге
- •Перспективы
- •Условные обозначения, требования и доступные для скачивания данные
- •Автор в Интернете
- •Об авторе
- •Глава 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. Назначение материала
10.4. Фоновая музыка 261
и выберите в меню подходящую функцию. На этот раз нам предоставят текстовое поле для ввода числа, так как метод OnPlayMusic() принимает в качестве параметра число. Введите 1 для Intro Music, 2 для Level Music и произвольное число для No Music (у меня это был ноль). Инструкция switch в методе OnMusic() воспроизводит клип intro или level в зависимости от числа или останавливает воспроизведение, если число не равно ни 1, ни 2.
Щелкая на кнопках в процессе игры, вы сможете включать музыку. Великолепно! Код загружает аудиоклипы из папки Resources. Производительность воспроизведения оптимизирована. Осталось доработать две вещи: сделать отдельные элементы управления громкостью и обеспечить плавный переход при переключении музыки.
10.4.2. Отдельная регулировка громкости
В игре уже есть элемент управления громкостью, который сейчас влияет в числе прочего и на фоновую музыку. Но в большинстве игр громкость звуковых эффектов и музыки контролируется по отдельности. Давайте посмотрим, как этого достичь.
Первым делом нужно сделать так, чтобы компоненты AudioSources музыки игнорировали настройки компонента AudioListener. Мы хотим, чтобы регулятор громкости и кнопка отключения звука, связанные с глобальным компонентом AudioListener, продолжали влиять на все звуковые эффекты, но не затрагивали бы фоновую музыку. Листинг 10.11 содержит код, заставляющий источник музыки игнорировать громкость, задаваемую компонентом AudioListener. Заодно этот код создает регулятор громкости и возможность выключения музыки. Добавьте его к диспетчеру аудио.
Листинг 10.11. Раздельное управление громкостью музыки в диспетчере управления звуком
...
private float _musicVolume; ¬ Непосредственный доступ к закрытой переменной невозможен, только через функцию задания свойства.
public float musicVolume { get {
return _musicVolume;
}
set {
_musicVolume = value;
if (music1Source != null) { ¬ Непосредственно регулируем громкость источника звука. music1Source.volume = _musicVolume;
}
}
}
...
public bool musicMute { get {
if (music1Source != null) { return music1Source.mute;
}
return false; ¬ Значение предлагается по умолчанию, если AudioSource отсутствует.
}
set {
262 Глава 10. Звуковые эффекты и музыка
if (music1Source != null) { music1Source.mute = value;
}
}
}
public void Startup(NetworkService service) { Debug.Log("Audio manager starting...");
_network = service;
music1Source.ignoreListenerVolume = true; │ music1Source.ignoreListenerPause = true; │
soundVolume = 1f; musicVolume = 1f;
status = ManagerStatus.Started;
}
...
¬Выделенный курсивом код уже был в сценарии, тут он приведен для справки.
Эти свойства заставляют компонент AudioSource игнорировать громкость компонента AudioListener.
Ключевой в этом коде является возможность непосредственной регулировки громкости в компоненте AudioSource с одновременным игнорированием источником глобальных параметров громкости, заданных в компоненте AudioListener. Существуют свойства для управления громкостью и включения/выключения звука отдельного источника музыки.
Метод Startup() инициализирует источник музыки со свойствами ignoreListener Volume и ignoreListenerPause, имеющими значение true. Как следует из их названий, они заставляют источник звука игнорировать глобальные настройки громкости в компоненте AudioListener.
Вы можете щелкнуть на кнопке Play и удостовериться, что существующий элемент регулировки громкости на громкость музыки больше не влияет. Значит, нам нужен в UI еще один элемент управления, который будет отвечать за громкость музыки; отредактируйте сценарий SettingsPopup в соответствии со следующим листингом.
Листинг 10.12. Элементы управления громкостью в сценарии SettingPopup
... |
|
public void OnMusicToggle() { |
Снова воспроизводим элемент управления |
Managers.Audio.musicMute = !Managers.Audio.musicMute; ¬ включением звука, но на этот раз используя |
|
Managers.Audio.PlaySound(sound); |
musicMute. |
} |
|
public void OnMusicValue(float volume) { |
Снова воспроизводим элемент |
Managers.Audio.musicVolume = volume; ¬ управления громкостью звука, |
|
} |
но на этот раз используя musicVolume. |
...
Особых пояснений этот код не требует — по большей части он повторяет элементы управления громкостью звука. Бросается в глаза замена свойств объекта AudioManager
с soundMute/soundVolume на musicMute/musicVolume.
10.4. Фоновая музыка 263
В редакторе создайте кнопку и ползунок. Вот последовательность ваших действий:
1.Измените высоту всплывающего окна на 225 (чтобы появилось место для дополнительных элементов управления).
2.Создайте UI-кнопку.
3.Сделайте ее потомком по отношению к всплывающему окну.
4.Поместите кнопку в точку с координатами 0, –60.
5.Раскройте иерархию кнопки и выделите текстовую метку.
6.Измените ее текст на Toggle Music.
7.Создайте ползунок (командой того же самого меню UI).
8.Сделайте ползунок потомком всплывающего окна и поместите его в точку с координатами 0, –85.
Свяжите эти UI-элементы с кодом в сценарии SettingsPopup. Найдите список OnClick/OnValueChanged в настройках UI-элементов, щелкните на кнопке со знаком + (плюс) для добавления новой записи и перетащите всплывающее окно на ячейку для объекта, после чего выберите в меню функцию. В первом случае это будет вариант OnMusicToggle(), во втором — OnMusicValue(). Обе функции находятся в разделе Dynamic Float.
Теперь запустите код и убедитесь, что на звуковые эффекты и фоновую музыку влияют разные элементы управления. Но на самом деле, это еще не все. Остался последний штрих — плавное микширование музыкальных треков.
10.4.3. Переход между песнями
В качестве финального штриха давайте заставим диспетчер управления звуком постепенно увеличивать и уменьшать громкость звука при переходе от одной мелодии к другой. Сейчас в процессе переключения мелодия просто обрывается, и начинается новый трек, что несколько режет ухо. Мы можем сгладить этот переход, сделав так, чтобы громкость предыдущего трека быстро затухала, в то время как громкость нового увеличивалась от нуля. Это простой, но хорошо продуманный код, объединяющий изученные вами методы регулировки громкости с сопрограммой, постепенно меняющей громкость.
Листинг 10.13 содержит код сценария AudioManager. Смысл происходящего сводится к простой концепции: теперь, когда у нас есть два отдельных источника звука, мы пользуемся ими для воспроизведения отдельных музыкальных треков и пошагово увеличиваем громкость одного источника, одновременно пошагово уменьшая громкость другого (как обычно, выделенный курсивом код уже присутствует в сценарии и показан для справки).
Листинг 10.13. Плавный переход между треками в сценарии AudioManager
...
[SerializeField] private AudioSource private AudioSource _activeMusic; ¬ private AudioSource _inactiveMusic;
Второй компонент AudioSource music2Source; ¬ (первый тоже сохраняем).
Следим за тем, какой из источников активен, а какой нет.
264 Глава 10. Звуковые эффекты и музыка
public float crossFadeRate = 1.5f;
private bool _crossFading; ¬ Переключатель, позволяющий избежать ошибок в процессе перехода.
...
public float musicVolume {
...
set {
_musicVolume = value;
if (music1Source != null && !_crossFading) { music1Source.volume = _musicVolume;
music2Source.volume = _musicVolume; ¬ Регулировка громкости обоих источников музыки.
}
}
}
...
public bool musicMute {
...
set {
if (music1Source != null) { music1Source.mute = value; music2Source.mute = value;
}
}
}
public void Startup(NetworkService service) { Debug.Log("Audio manager starting...");
_network = service;
music1Source.ignoreListenerVolume = true; music2Source.ignoreListenerVolume = true; music1Source.ignoreListenerPause = true; music2Source.ignoreListenerPause = true;
soundVolume = 1f; musicVolume = 1f;
_activeMusic = music1Source; ¬ Инициализируем один из источников как активный.
_inactiveMusic = music2Source;
status = ManagerStatus.Started;
}
...
private void PlayMusic(AudioClip clip) { if (_crossFading) {return;}
StartCoroutine(CrossFadeMusic(clip)); ¬ При изменении музыкальной композиции вызываем сопрограмму.
}
private IEnumerator CrossFadeMusic(AudioClip clip) { _crossFading = true;
_inactiveMusic.clip = clip; _inactiveMusic.volume = 0; _inactiveMusic.Play();
float scaledRate = crossFadeRate * _musicVolume;
10.4. Фоновая музыка 265
while (_activeMusic.volume > 0) {
_activeMusic.volume -= scaledRate * Time.deltaTime; _inactiveMusic.volume += scaledRate * Time.deltaTime;
yield return null; ¬ Эта инструкция yield останавливает операции на один кадр.
}
AudioSource temp = _activeMusic; ¬ Временная переменная, используемая, когда мы меняем местами переменные _active и _inactive.
_activeMusic = _inactiveMusic; _activeMusic.volume = _musicVolume;
_inactiveMusic = temp; _inactiveMusic.Stop();
_crossFading = false;
}
public void StopMusic() { _activeMusic.Stop(); _inactiveMusic.Stop();
}
...
Первым дополнением стала переменная для второго источника музыки. Вам нужно сохранить первый объект AudioSource, но создать его копию (убедитесь, что настройки остались теми же — установите флажок Loop), а затем перетащить его на ячейку панели Inspector. При этом код задает переменные для активного и неактивного состояний источника звука, но это закрытые переменные, которые не появляются на панели Inspector. Именно они определяют, музыка из какого источника воспроизводится в конкретный момент времени.
Теперь в процессе воспроизведения музыки код вызывает сопрограмму. Она заставляет второй объект AudioSource начать воспроизведение нового музыкального трека, в то время как старый воспроизводится на втором источнике звука. После этого сопрограмма пошагово увеличивает громкость новой музыки, одновременно уменьшая громкость старой. После завершения перехода (то есть в момент, когда уровни громкости поменялись местами) сопрограмма меняет местами «активный» и «неактивный» источники.
Потрясающе! Мы добавили фоновую музыку в аудиосистему игры.
FMOD: ЗВУКОВОЙ ИНСТРУМЕНТ ДЛЯ ИГР
Аудиосистема в Unity приводится в действие популярной программной аудиобиблиотекой FMOD. Ее можно скачать с сайта www.fmod.org, но в Unity она уже встроена, хотя и без наиболее нетривиальных функциональных возможностей (о них вы можете узнать на сайте библиотеки).
Эти нетривиальные функциональные возможности предлагает подключаемый к Unity модуль FMOD Studio, но для выполнения упражнений этой главы предоставленного по умолчанию набора функциональных возможностей более чем достаточно. В этот набор входят самые необходимые для создания аудиосистемы в играх компоненты. Они удовлетворяют нуждам большинства разработчиков, дополнительный же модуль требуется только для добавления в игры сложных звуковых эффектов.