- •Предисловие
- •Введение
- •Благодарности
- •О книге
- •Перспективы
- •Условные обозначения, требования и доступные для скачивания данные
- •Автор в Интернете
- •Об авторе
- •Глава 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. Назначение материала
232 |
Глава 9. Подключение игры к Интернету |
|
|
SetOvercast(Managers.Weather.cloudValue); ¬ Используем значение облачности |
|
} |
из сценария WeatherManager. |
private void SetOvercast(float value) { sky.SetFloat("_Blend", value);
sun.intensity = _fullIntensity - (_fullIntensity * value);
}
}
Обратите внимание, что изменения сводятся не только к дополнениям; удалены несколько фрагментов тестового кода, а именно, мы удалили локальное значение облачности, увеличивавшееся в каждом кадре; оно нам больше не требуется, так как мы будем пользоваться значением из сценария WeatherManager.
Подписчики добавляются и удаляются в методах Awake() и OnDestroy() — это методы класса MonoBehaviour, вызываемые, когда объект активируется или удаляется. Каждый такой подписчик является частью системы рассылки сообщений. При получении сообщения он вызывает метод OnWeatherUpdated(), получающий значение облачности из сценария WeatherManager и, в свою очередь, вызывающий метод SetOvercast(), использующий это значение. В результате вид сцены контролируется скачанными из Интернета метеорологическими данными.
Выполните воспроизведение сцены и убедитесь, что небо обновляется в соответствии с информацией об облачности из прогноза погоды. Скорее всего, вы увидите, что запрос погоды занимает некоторое время; в настоящей игре до завершения загрузки неба имело бы смысл спрятать сцену за экраном загрузки.
ДРУГИЕ СПОСОБЫ ПЕРЕДАЧИ ДАННЫХ ПО СЕТИ В ИГРАХ
При всей устойчивости к сбоям и надежности HTTP-запросов задержка в получении ответа для большинства игр является слишком существенным недостатком. Поэтому эти запросы хороши при относительно медленной передаче сообщений на сервер (например, значений перемещения в играх со сменой хода или данных о набранных очках), но для таких игр, как сетевой шутер от первого лица, требуется другой подход к передаче данных по сети.
Существуют различные технологии взаимодействия, а также приемы, позволяющие скомпенсировать запаздывание. К примеру, в Unity применяется сетевая библиотека RakNet в системе удаленного вызова процедур (Remote Procedure Call, RPC).
Передовые технологии для создания сетевых игр — сложная тема, рассмотрение которой выходит за рамки темы данной книги. Вы можете самостоятельно заняться ее изучением, начав со страницы http://docs.unity3d.com/ru/current/Manual/NetworkReferenceGuide.html.
Теперь, когда вы знаете, как получить из Интернета числовые и строковые данные, давайте рассмотрим способы работы с изображениями.
9.3. Добавление рекламного щита
Ответы от веб-сервиса почти всегда представляют собой текстовые строки в формате XML или JSON, но по сети передается и множество других данных. Кроме текстовой информации чаще всего запрашиваются изображения. Объект WWW в Unity применяется в числе прочего и для их скачивания.
Способ решения этой задачи вы изучите на примере создания рекламного щита, на котором отображается скачанное из Интернета изображение. Создаваемый код будет
9.3. Добавление рекламного щита 233
решать две задачи: скачивание изображения из Интернета и назначение этого изображения рекламному щиту. Третьей задачей станет редактирование кода, позволяющее сохранить изображение для его показа на нескольких рекламных щитах.
9.3.1. Загрузка изображений из Интернета
Первым делом напишем код загрузки изображения. Для тестирования мы скачаем свободно распространяемые фотографии пейзажей. Пример такой фотографии показан на рис. 9.5. Загруженного изображения на рекламном щите вы пока не увидите; сценарий отображения картинки в сцене будет представлен в следующем разделе, но до этого мы напишем код получения графического файла.
Рис. 9.5. Озеро Морейн в национальном парке Банф, Канада
Структура кода, предназначенного для скачивания данных и графики, практически одинакова. За загрузку изображений будет отвечать помещенный в отдельный модуль очередной диспетчер (он называется ImagesManager). Напомню, что за подключение к Интернету и отправку HTTP-запросов отвечает сценарий NetworkService, к которому и будет обращаться наш новый диспетчер. Первым делом отредактируем код сценария NetworkService. Следующий листинг добавляет туда возможность скачивания изображений.
Листинг 9.12. Скачивание изображений в сценарии NetworkService
...
private const string webImage = ¬ Эта константа с другими URL-адресами помещается в верхнюю часть сценария.
"http://upload.wikimedia.org/wikipedia/commons/c/c5/ Moraine_Lake_17092005.jpg";
...
public IEnumerator DownloadImage(Action<Texture2D> callback) { ¬ WWW www = new WWW(webImage);
yield return www; callback(www.texture);
}
...
234 Глава 9. Подключение игры к Интернету
Код скачивания изображений выглядит практически идентично коду скачивания данных. Основным отличием является тип метода обратного вызова; отметьте, что на этот раз обратный вызов вместо строк работает с объектами типа Texture2D. Дело в типе возвращаемого ответа: раньше скачивалась строка данных, теперь — изображение. Следующий листинг содержит код нового диспетчера. Создайте сценарий ImagesManager и скопируйте туда код.
Листинг 9.13. Диспетчер ImagesManager, запрашивающий и сохраняющий изображения
using UnityEngine;
using System.Collections;
using System.Collections.Generic; using System;
public class ImagesManager : MonoBehaviour, IGameManager { public ManagerStatus status {get; private set;}
private NetworkService _network;
private Texture2D _webImage; ¬ Переменная для сохранения скачанного изображения.
public void Startup(NetworkService service) { Debug.Log("Images manager starting...");
_network = service;
status = ManagerStatus.Started;
}
public void GetWebImage(Action<Texture2D> callback) {
if (_webImage == null) { ¬ Проверяем, нет ли уже сохраненного изображения.
StartCoroutine(_network.DownloadImage(callback));
}
else {
}
callback(_webImage); ¬ При наличии сохраненного изображения сразу активируется обратный вызов (без скачивания).
}
}
Самой интересной частью этого кода является метод GetWebImage(); все остальное в сценарии представляет собой стандартные свойства и методы, реализующие интерфейс диспетчера. Именно метод GetWebImage() возвращает (через функцию обратного вызова) скачанное из сети изображение. Первым делом мы проверяем, не содержит ли уже переменная _webImage сохраненное изображение: в случае отрицательного результата проверки активируется сетевой вызов для скачивания. Если же в переменной _webImage уже есть сохраненное изображение, метод GetWebImage() возвращает его (чтобы не скачивать заново).
ПРИМЕЧАНИЕ Пока мы еще не загрузили и не сохранили ни одного изображения, то есть переменная _webImage пуста. При этом уже есть код, указывающий, что делать при наличии сохраненного изображения, поэтому в следующих разделах вам останется только слегка его отредактировать. Процесс редактирования вынесен в отдельный раздел, так как он включает в себя несколько хитрых приемов.
9.3. Добавление рекламного щита 235
Разумеется, диспетчер ImagesManager, как и все остальные модули диспетчеров, нужно добавить в сценарий менеджеров; этот процесс демонстрируется в следующем листинге.
Листинг 9.14. Добавление нового диспетчера в сценарий Managers.cs
...
[RequireComponent(typeof(ImagesManager))]
...
public static ImagesManager Images {get; private set;}
...
void Awake() {
Weather = GetComponent<WeatherManager>(); Images = GetComponent<ImagesManager>();
_startSequence = new List<IGameManager>(); _startSequence.Add(Weather); _startSequence.Add(Images);
StartCoroutine(StartupManagers());
}
...
В отличие от настроек диспетчера WeatherManager, при начальной загрузке диспетчера ImagesManager метод GetWebImage() автоматически не вызывается. Вместо этого код ждет процесса активации, который мы запрограммируем в следующем разделе.
9.3.2. Вывод изображения на щите
Только что написанный нами диспетчер ImagesManager ничего не сделает, пока мы его не активируем. Поэтому создадим рекламный щит, который будет вызывать методы в сценарии ImagesManager. Создайте куб и поместите его в центре сцены, введя в поля Position значения 0, 1.5, –5, а в поля Scale — значения 5, 3, 0.5. Результат показан на рис. 9.6.
Р а а |
|
Р а а а а |
|
|
|
Рис. 9.6. Рекламный щит до и после вывода скачанного из Интернета изображения
Мы создадим устройство, управляющееся так же, как меняющий цвета монитор из главы 8. Скопируйте сценарий DeviceOperator и свяжите его с объектом player.