- •Предисловие
- •Введение
- •Благодарности
- •О книге
- •Перспективы
- •Условные обозначения, требования и доступные для скачивания данные
- •Автор в Интернете
- •Об авторе
- •Глава 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. Назначение материала
120 Глава 5. Игра Memory на основе новой 2D-функциональности
Впрочем, важный параметр Projection в редактировании не нуждается, чего не скажешь о прочих настройках камеры. Обратите внимание на параметр Size; он определяет размер поля зрения камеры от центра экрана до его верхнего края. Другими словами, этому параметру присваивается значение, равное половине желаемого размера экрана в пикселах. Если позднее вы укажете такое же разрешение для развертываемой игры, вы получите графику пиксел в пиксел.
ОПРЕДЕЛЕНИЕ Пиксел в пиксел (pixel-perfect) означает, что один экранный пиксел соответствует одному пикселу изображения (в противном случае видеокарта может сделать изображение слегка размытым, растянув его под размер экрана).
Предположим, что вы хотите попасть пиксел в пиксел при разрешении экрана 1024 × 768. Значит, высота камеры должна составить 384 пиксела. Поделите это число на 100 (с учетом соотношения пикселов и единиц измерения), и вы получите размер камеры, равный 3.84. То есть вычисления ведутся по формуле РАЗМЕР ЭКРАНА / 2 /100f (f указывает на значение типа float, а не типа int). Так как наше фоновое изображение имеет размер 1024 × 768 (для проверки выделите этот ресурс), очевидно, что значение 3.84 идеально подходит для нашей камеры.
Еще два параметра, которые нужно поменять на панели Inspector, — это фоновый цвет камеры и ее положение по координате Z. Как уже упоминалось при рассмотрении спрайтов, чем больше значение координаты Z, тем дальше расположен объект. Поэтому отодвинем камеру подальше в область отрицательных значений Z; например, 0, 0, –100. В качестве фонового цвета, наверное, лучше всего выбрать черный; по умолчанию фон имеет синий цвет, и если экран окажется шире фонового изображения (что вполне вероятно), синие полоски по сторонам будут выглядеть странно. Щелкните на образце цвета Background и выберите черный цвет.
Сохраните сцену под именем Scene и щелкните на кнопке Play — вы увидите игровое поле, заполненное спрайтом, изображающим поверхность стола. Думаю, вы согласитесь, что путь до этой точки был не совсем очевидным (еще раз напомню, что причиной этого является трехмерный игровой движок Unity, в который только недавно добавили возможность работы с двухмерной графикой). Итак, у нас есть пустая поверхность стола, теперь нужно выложить на нее карты.
5.2. Создание карт и превращение их в интерактивные объекты
Так как все изображения уже импортированы и готовы к использованию, давайте создадим объекты, представляющие карты, которые сформируют ядро нашей игры. В игре Memory карты выкладываются лицевой стороной вниз и переворачиваются только на время после выбора пары карт. Для реализации такой функциональности мы создадим объекты, состоящие из положенных друг на друга спрайтов. Затем мы напишем код, который заставит карты переворачиваться по щелчку мыши.
5.2.Создание карт и превращение их в интерактивные объекты 121
5.2.1.Создание объекта из спрайтов
Перетащите в сцену одну из карт. Используйте изображение лицевой стороны, так как мы добавим поверх другую карту, чтобы скрыть рисунок. С технической точки зрения положение карты пока не имеет значения, но в конечном счете она должна будет оказаться в определенной точке, поэтому присвойте полям Position значения –3, 1, 0. Затем перетащите в сцену спрайт card_back. Сделайте этот новый спрайт потомком предыдущего (напоминаю, что для этого на вкладке Hierarchy нужно перетащить дочерний объект на родительский) и установите для него положение 0, 0, –0.1. Помните, что это положение относительно предка, то есть данные координаты означают «Поместите рубашку карты в точку с теми же координатами X и Y, но ее чуть ближе по координате Z».
СОВЕТ Вместо инструментов Move, Rotate и Scale, которыми мы пользовались в режиме 3D, теперь нам доступен единый инструмент манипуляции Rect Tool. В режиме 2D этот инструмент активируется автоматически. Кроме того, вы можете нажать крайнюю правую кнопку на навигационной панели, расположенной в верхнем левом углу Unity. Когда этот инструмент активен, перетаскивание объектов приводит к выполнению всех трех операций (перемещения/поворота/масштабирования) в двух измерениях.
Поместив рубашку карты на место, как показано на рис. 5.6, вы подготовили все для создания интерактивного объекта, реагирующего на щелчок мыши.
Р а а а а а а
О а а а•а •
• а а
(П , а
)
Рис. 5.6. Иерархическое связывание и расположение спрайта с рубашкой карты
5.2.2. Код ввода с помощью мыши
Чтобы карта могла реагировать на щелчки мыши, ей требуется такой компонент, как коллайдер. У новых спрайтов он отсутствует, поэтому щелкать на них бесполезно. Мы присоединим коллайдер к корневому объекту, а не к рубашке карты, поэтому именно лицевая сторона будет восприимчива к щелчкам. Для этого выделите корневой объект на вкладке Hierarchy (не имеет смысла щелкать на карте в сцене, так как сверху находится рубашка, и именно она будет выделена), а затем щелкните на кнопке Add Component в нижней части панели Inspector. Выделите строку Physics 2D (строка Physics относится к физике трехмерных игр) и выберите вариант Box collider.
Кроме коллайдера карте нужен сценарий, который заставит ее реагировать на действия игрока, поэтому давайте напишем его код. Создайте новый сценарий с именем MemoryCard.cs и присоедините его к корневой карте (а не к рубашке). Код
122 Глава 5. Игра Memory на основе новой 2D-функциональности
в следующем листинге заставляет карту после щелчка на ней сгенерировать отладочное сообщение.
Листинг 5.1. Генерация отладочных сообщений по щелчку
using UnityEngine;
using System.Collections;
public class MemoryCard : MonoBehaviour {
public void OnMouseDown() { ¬ Эта функция вызывается после щелчка на объекте. Debug.Log("testing 1 2 3"); ¬ Пока мы только генерируем текстовое сообщение, выводимое на консоль.
}
}
СОВЕТ Если вы еще не приобрели такой привычки, приучайте себя распределять ресурсы по папкам; создайте отдельную папку для сценариев и перетащите все сценарии туда непосредственно на вкладке Project. Главное — избегать имен, на которые реагирует Unity: Resources, Plugins, Editor и Gizmos. Позднее мы поговорим о том, какую функцию выполняют эти папки, а пока просто избегайте называть свои собственные папки перечисленными именами.
Итак, теперь мы можем щелкнуть на карте! Подобно методу Update(), функция OnMouseDown() также происходит от класса MonoBehaviour, именно она вызывает реакцию на щелчок мыши. Запустите игру и посмотрите, как на консоли появляется сообщение. Но вывод на консоль был сделан только с целью тестирования, мы же хотим открыть карту.
5.2.3. Открытие карты по щелчку
Перепишите код в соответствии со следующим листингом (пока запустить этот код не получится, но это не повод для беспокойства).
Листинг 5.2. Сценарий, скрывающий рубашку после щелчка на карте
using UnityEngine;
using System.Collections;
public class MemoryCard : MonoBehaviour {
[SerializeField] private GameObject cardBack; ¬ Переменная, которая появляется на панели Inspector.
public void OnMouseDown() { |
|
Просто запускаем код деактивации, если объект |
if (cardBack.activeSelf) { |
¬ |
в данный момент является активным/видимым. |
cardBack.SetActive(false); ¬ Делаем объект неактивным/невидимым.
}
}
}
В этом сценарии есть два ключевых дополнения: ссылка на объект в сцене и метод SetActive(), деактивирующий данный объект. Первая часть, то есть ссылка на объект, аналогична тому, что мы делали в предыдущих главах: переменная помечается как сериализованная, а затем объект с вкладки Hierarchy перетаскивается на эту переменную на панели Inspector. После того как ссылка на объект установлена, код начинает влиять на объект сцены.
Вторым ключевым дополнением является команда SetActive. Она деактивирует любой объект GameObject, делая его невидимым. Если теперь перетащить