
- •Джим Адамс
- •2-е издание
- •Оглавление
- •Благодарности
- •Об авторе
- •Введение
- •О чем эта книга
- •Для кого предназначена книга
- •Организация книги
- •Содержимое CD-ROM
- •Типографские соглашения
- •Что нужно для начала
- •Глава 1 Подготовка к работе с книгой
- •Глава 1 Подготовка к работе с книгой
- •DirectX
- •Подготовка DirectX
- •Отладочные и дистрибутивные версии
- •Установка DirectX 9
- •Установка DirectMusic Producer
- •Включаемые файлы и библиотеки
- •Подготовка компилятора
- •Указание каталогов для DirectX
- •Связывание с библиотеками
- •Установка поведения по умолчанию для char
- •Окончательные и отладочные версии
- •Многопоточные библиотеки
- •Программирование для Windows
- •Потоки и многопоточность
- •Критические секции
- •Использование COM
- •Инициализация COM
- •IUnknown
- •Инициализация и освобождение объектов
- •Запрос интерфейсов
- •Поток выполнения программы
- •Модульное программирование
- •Состояния и процессы
- •Состояния приложения
- •Процессы
- •Обработка данных приложения
- •Использование упаковки данных
- •Тестирование системы упаковки данных
- •Построение каркаса приложения
- •Структурирование проекта
- •Завершаем подготовку
- •Глава 2 Рисование с DirectX Graphics
- •Глава 3 Взаимодействие с пользователем с DirectInput
- •Глава 4 Воспроизведение звуков и музыки с DirectX Audio и DirectShow
- •Глава 2 Рисование с DirectX Graphics
- •Сердце трехмерной графики
- •Системы координат
- •Конструирование объектов
- •Списки, полосы и веера
- •Порядок вершин
- •Окрашивание полигонов
- •Преобразования
- •Начинаем работать с DirectX Graphics
- •Компоненты Direct3D
- •Инициализация системы
- •Получение интерфейса Direct3D
- •Выбор видеорежима
- •Установка метода показа
- •Создание интерфейса устройства и инициализация дисплея
- •Потеря устройства
- •Знакомство с D3DX
- •Трехмерная математика
- •Матричная алгебра
- •Конструирование матриц
- •Комбинирование матриц
- •Переход от локальных координат к координатам вида
- •Переходим к рисованию
- •Использование вершин
- •Настраиваемый формат вершин
- •Использование буфера вершин
- •Создание буфера вершин
- •Блокировка буфера вершин
- •Заполнение данных вершин
- •Поток вершин
- •Вершинные шейдеры
- •Преобразования
- •Мировое преобразование
- •Преобразование вида
- •Преобразование проекции
- •Материалы и цвета
- •Очистка порта просмотра
- •Начало и завершение сцены
- •Визуализация полигонов
- •Показ сцены
- •Использование наложения текстур
- •Использование наложения текстур в Direct3D
- •Загрузка текстуры
- •Установка текстуры
- •Использование выборок
- •Визуализация текстурированных объектов
- •Альфа-смешивание
- •Включение альфа-смешивания
- •Рисование с альфа-смешиванием
- •Копирование с учетом прозрачности и альфа-проверка
- •Загрузка текстур с цветовым ключом
- •Включение альфа-проверки
- •Пример копирования с учетом прозрачности
- •Освещение
- •Использование точечного света
- •Использование зонального света
- •Использование направленного света
- •Фоновый свет
- •Установка света
- •Использование нормалей
- •Да будет свет!
- •Использование шрифтов
- •Создание шрифта
- •Рисование текста
- •Щиты
- •Частицы
- •Сортировка по глубине и Z-буферизация
- •Работа с портом просмотра
- •Работа с сетками
- •X-файлы
- •Формат X-файлов
- •Использование иерархии фреймов
- •Создание X-файлов с сетками
- •Разбор X-файлов
- •Сетки в библиотеке D3DX
- •Объект ID3DXBuffer
- •Стандартные сетки
- •Визуализация сетки
- •Скелетные сетки
- •Загрузка скелетных сеток
- •Обновление и визуализация скелетной сетки
- •X-стиль трехмерной анимации
- •Техника ключевых кадров
- •Анимация в X-файлах
- •Заканчиваем с графикой
- •Знакомство с устройствами ввода
- •Взаимодействие через клавиатуру
- •Работа с клавиатурой в Windows
- •Играем с мышью
- •Удовольствие с джойстиком
- •Использование DirectInput
- •Представляем основы DirectInput
- •Инициализация DirectInput
- •Использование устройств DirectInput
- •Получение GUID устройства
- •Создание COM-объекта устройства
- •Установка формата данных
- •Установка уровня кооперации
- •Установка специальных свойств
- •Захват устройства
- •Опрос устройства
- •Чтение данных
- •DirectInput и клавиатура
- •DirectInput и мышь
- •DirectInput и джойстик
- •Заканчиваем с вводом
- •Глава 4 Воспроизведение звуков и музыки с DirectX Audio и DirectShow
- •Основы звука
- •Цифровая звукозапись
- •Музыкальное безумие
- •MIDI
- •DirectMusic
- •Знакомство с DirectX Audio
- •Использование DirectSound
- •Инициализация DirectSound
- •Установка уровня кооперации
- •Установка формата воспроизведения
- •Создание объекта первичного звукового буфера
- •Установка формата
- •Запуск первичного звукового буфера
- •Использование вторичных звуковых буферов
- •Блокируй и загружай — загрузка звуковых данных в буфер
- •Воспроизведение звукового буфера
- •Изменение громкости, позиционирования и частоты
- •Регулировка громкости
- •Позиционирование
- •Изменение частоты
- •Потеря фокуса
- •Использование уведомлений
- •Использование потоков для сканирования событий
- •Загрузка звука в буфер
- •Потоковое воспроизведение звука
- •Работа с DirectMusic
- •Начинаем работу с DirectMusic
- •Создание объекта исполнителя
- •Создание объекта загрузчика
- •Работа с музыкальными сегментами
- •Загрузка музыкальных сегментов
- •Загрузка инструментов
- •Настройки для MIDI
- •Установка инструментов
- •Использование циклов и повторов
- •Воспроизведение и остановка сегмента
- •Выгрузка данных сегмента
- •Изменение музыки
- •Установка громкости
- •Смена темпа
- •Захват аудио-канала
- •Присоединяемся к MP3-революции
- •Использование DirectShow
- •Загрузка медиа-файла
- •Управление воспроизведением вашей музыки и звуков
- •Воспроизведение звука
- •Приостановка воспроизведения
- •Завершение воспроизведения
- •Обнаружение событий
- •Освобождение ресурсов DirectShow
- •Заканчиваем с музыкой
- •Глава 5 Работа с сетью с DirectPlay
- •Знакомство с сетями
- •Сетевые модели
- •Лобби
- •Задержка и запаздывание
- •Коммуникационные протоколы
- •Адресация
- •Введение в DirectPlay
- •Сетевые объекты
- •Работа с игроками
- •Сетевые сообщения
- •Асинхронная и синхронная работа
- •Безопасность
- •Гарантированная доставка
- •Регулировка потока
- •От маленьких байтов к большим словам
- •Идентификация приложений по GUID
- •Инициализация сетевого объекта
- •Использование адресов
- •Инициализация объекта адреса
- •Добавление компонентов
- •Установка поставщика услуг
- •Выбор порта
- •Назначение устройства
- •Использование обработчиков сообщений
- •Конфигурирование данных сессии
- •Данные сессии сервера
- •Данные сессии клиента
- •Работа с сервером
- •Поддержка игроков
- •Работа с сообщениями о создании игрока
- •Получение имени игрока
- •Уничтожение игроков
- •Получение данных
- •Отправка сообщений сервера
- •Завершение сессии на главном узле
- •Работа с клиентом
- •Получение и отправка сообщений
- •Получение идентификатора игрока
- •Завершение сессии клиента
- •Заканчиваем с сетями
- •Глава 6 Создаем ядро игры
- •Знакомство с концепцией ядра
- •Системное ядро
- •Использование объекта ядра cApplication
- •Обработка состояний с cStateManager
- •Процессы и cProcessManager
- •Управление данными с cDataPackage
- •Графическое ядро
- •Графическая система и cGraphics
- •Изображения и cTexture
- •Цвета и cMaterial
- •Освещение с cLight
- •Текст и шрифты с использованием cFont
- •Вершины и cVertexBuffer
- •Мировое преобразование с cWorldPosition
- •Преобразование вида и cCamera
- •Загружаемые сетки и использование cMesh
- •Рисуем объекты, используя cObject
- •Делаем сетки двигающимися с cAnimation
- •Ядро ввода
- •Использование DirectInput с cInput
- •Устройства ввода и cInputDevice
- •Использование ядра ввода
- •Звуковое ядро
- •Управление DirectX Audio с cSound
- •Использование волновых данных и cSoundData
- •Воспроизведение звука с cSoundChannel
- •Слушаем музыку с cMusicChannel
- •Смешивание инструментов с cDLS
- •Воспроизведение MP3 с cMP3
- •Сетевое ядро
- •Запрос адаптера с cNetworkAdapter
- •Серверы и cNetworkServer
- •Работа клиента и cNetworkClient
- •Заканчиваем изучать ядро игры
- •Часть III Программирование ролевых игр
- •Глава 7 Использование двухмерной графики
- •Глава 8 Создание трехмерного графического движка
- •Глава 9 Объединение двухмерной и трехмерной графики
- •Глава 10 Реализация скриптов
- •Глава 11 Определение и использование объектов
- •Глава 12 Управление игроками и персонажами
- •Глава 13 Работа с картами и уровнями
- •Глава 14 Создание боевых последовательностей
- •Глава 15 Сетевой режим для многопользовательской игры
- •Глава 7 Использование двухмерной графики
- •Знакомство с блоками и картами
- •Использование блоков с DirectX
- •Построение класса для работы с блоками
- •cTiles::Create
- •cTiles::Free
- •cTiles::Load
- •cTiles::Free
- •cTiles::GetWidth, cTiles::GetHeight и cTiles::GetNum
- •cTiles::SetTransparent
- •cTiles::Draw
- •Использование класса работы с блоками
- •Основы работы с блочной графикой
- •Рисование основной карты
- •Использование нескольких слоев
- •Добавление объектов
- •Плавная прокрутка
- •Карта и мышь
- •Создание класса карты
- •Псевдотрехмерные блоки
- •Работа с большими растрами
- •Создание больших блоков
- •Большой пример
- •Заканчиваем с двухмерной графикой
- •Сетки в качестве уровней
- •Загрузка уровней
- •Рисование комнат
- •Усовершенствование базовой техники
- •Знакомство с пирамидой видимого пространства
- •Плоскости и отсечение
- •Проверка видимости с плоскостями
- •Проверка всей пирамиды
- •Класс cFrustum
- •cFrustum::Construct
- •cFrustum::CheckPoint, CheckCube, CheckRectangle и CheckSphere
- •Разработка профессионального трехмерного движка
- •Знакомство с движком NodeTree
- •Создание узлов и деревьев
- •Сканирование и рисование дерева
- •Работа с группами материалов
- •Создание класса cNodeTreeMesh
- •cNodeTreeMesh::Create и cNodeTreeMesh::Free
- •cNodeTreeMesh::SortNode
- •cNodeTreeMesh::AddNode
- •cNodeTreeMesh::Render
- •Использование cNodeTreeMesh
- •Добавление к миру трехмерных объектов
- •Вычисление ограничивающей сферы
- •Ограничивающие сферы и пирамида видимого пространства
- •Обнаружение столкновений сеток
- •Столкновение с миром
- •Испускание лучей
- •Блокировка пути
- •Перемещение вверх и вниз
- •Быстрая проверка пересечения
- •Обнаружение столкновений в классе cNodeTreeMesh
- •Когда сталкиваются сетки
- •Щелчки мыши и сетки
- •Использование небесного куба
- •Создание класса небесного куба
- •cSkyBox::Create и cSkyBox::Free
- •cSkyBox::LoadTexture
- •cSkyBox::Rotate и cSkyBox::RotateRel
- •cSkyBox::Render
- •Использование класса небесного куба
- •Заканчиваем с трехмерной графикой
- •Глава 9 Объединение двухмерной и трехмерной графики
- •Смешивание двух измерений
- •Использование двухмерных объектов в трехмерном мире
- •Рисование блоков в трехмерном мире
- •Загрузка сетки уровня
- •Загрузка блоков
- •Подготовка к рисованию
- •Рисование сетки уровня
- •Рисование двухмерных объектов
- •Перемещение в трехмерном мире
- •Добавление трехмерных объектов к двухмерному миру
- •Работа с двухмерным фоном
- •Работа с сеткой сцены
- •Визуализация сцены
- •Добавление трехмерных объектов
- •Столкновения и пересечения
- •Заканчиваем смешивание графики
- •Глава 10 Реализация скриптов
- •Что такое скрипты
- •Создание системы Mad Lib Script
- •Проектирование системы Mad Lib Script
- •Программирование системы Mad Lib Script
- •Работа с шаблонами действий
- •Создание элементов скрипта
- •Объединяем все в классе cActionTemplate
- •Работа с редактором MLS Editor
- •Выполнение скриптов Mad Lib
- •Применение скриптов в играх
- •Заканчиваем со скриптами
- •Определение объектов для вашей игры
- •Форма объекта
- •Определение функции объекта
- •Оружие
- •Броня
- •Аксессуары
- •Коллекции
- •Транспорт
- •Прочее
- •Добавление функций к объекту
- •Категории предметов и значения
- •Задание цены предметов
- •Флаги предмета
- •Ограничения использования
- •Присоединение скриптов к предметам
- •Сетки и изображения
- •Итоговая структура данных предмета
- •Главный список предметов
- •Конструирование MIL
- •Использование редактора MIL
- •Доступ к предметам из MIL
- •Управление предметами с помощью системы контроля имущества
- •Разработка ICS карты
- •cMapICS::Load, cMapICS::Save и cMapICS::Free
- •cMapICS::Add и cMapICS::Remove
- •cMapICS::GetNumItems, cMapICS::GetParentItem и cMapICS::GetItem
- •Использование класса cMapICS
- •Разработка ICS персонажа
- •Определение класса cCharICS
- •Использование класса cCharICS
- •Заканчиваем с объектами и имуществом
- •Глава 12 Управление игроками и персонажами
- •Игроки, персонажи, монстры — о боже!
- •Определение персонажей в вашей игре
- •Способности персонажа
- •Атрибуты персонажа
- •Дополнительные статусы персонажа
- •Классы персонажей
- •Действия персонажей
- •Персонажи игроков
- •Передвижение игрока
- •Управление ресурсами
- •Увеличение опыта и силы
- •Независимые персонажи
- •Персонажи монстров
- •Графика персонажей
- •Перемещение персонажей
- •Управление персонажем игрока
- •Управление направлением
- •Управление поворотом
- •Управление от первого лица
- •Управление независимыми персонажами
- •Ожидание
- •Блуждание по области
- •Ходьба по маршруту
- •Использование маршрутных точек
- •Ходьба от точки к точке
- •Быстрее Пифагора
- •Прохождение маршрута
- •Следование за другим персонажем
- •Избегание персонажа
- •Автоматическое управление персонажами
- •Общение между персонажами
- •Говорящие куклы
- •Управляемые скриптами говорящие куклы
- •Показ диалогов и другого текста
- •Класс cWindow
- •cWindow::cWindow и cWindow::~cWindow
- •cWindow::Create и cWindow::Free
- •cWindow::SetText
- •cWindow::Move
- •cWindow::GetHeight
- •cWindow::Render
- •Использование cWindow
- •Скрипты и персонажи
- •Класс скрипта
- •Создание производного класса скрипта
- •Производный класс
- •Использование производного класса
- •Управление ресурсами
- •Использование предметов
- •Использование магии
- •Торговля и обмен
- •Работа с магией и заклинаниями
- •Графика заклинания
- •Функция заклинания
- •Изменение здоровья и маны
- •Установка и снятие статусов
- •Воскрешение и мгновенная смерть
- •Расколдовывание
- •Телепортация
- •Нацеливание заклинаний, стоимость и шансы
- •Главный список заклинаний
- •Список заклинаний
- •Определение заклинаний с MSL Editor
- •Создание контроллера заклинаний
- •Сетки и sSpellMeshList
- •Отслеживание заклинаний с использованием sSpellTracker
- •Класс cSpellController
- •cSpellController::cSpellController и cSpellController::~sSpellController
- •cSpellController::Init и cSpellController::Shutdown
- •cSpellController::Free
- •cSpellController::GetSpell
- •cSpellController::Add
- •cSpellController::SetAnimData
- •cSpellController::Update
- •cSpellController::Render
- •Определение жертвы и обработка эффекта заклинания
- •Использование контроллера заклинаний
- •Сражения и персонажи
- •Использование правил сражения для атаки
- •Нанесение удара
- •Отклонение атаки
- •Обработка ущерба
- •Заклинания в битве
- •Интеллект в битвах
- •Построение главного списка персонажей
- •MCL Editor
- •Использование определений персонажей
- •Создание класса контроллера персонажей
- •Сетки и sCharacterMeshList
- •Зацикливание анимации и sCharAnimationInfo
- •Перемещение и sRoutePoint
- •Отслеживание персонажей с sCharacter
- •Класс sCharacterController
- •Использование sCharacterController
- •Демонстрация персонажей в программе Chars
- •Заканчиваем с персонажами
- •Глава 13 Работа с картами и уровнями
- •Размещение персонажей на карте
- •Список персонажей карты
- •Загрузка списка персонажей карты
- •Использование списка персонажей карты в вашей игре
- •Скриптовое размещение
- •Использование триггеров карты
- •Сферические триггеры
- •Кубический триггер
- •Цилиндрический триггер
- •Треугольный триггер
- •Срабатывание триггеров
- •Создание класса триггера
- •cTrigger::cTrigger и cTrigger::~cTrigger
- •cTrigger::Load и cTrigger::Save
- •cTrigger::AddTrigger
- •cTrigger::AddSphere, cTrigger::AddBox, cTrigger::AddCylinder и cTrigger::AddTriangle
- •cTrigger::Remove и cTrigger::Free
- •cTrigger::GetTrigger
- •cTrigger::GetEnableState и cTrigger::Enable
- •cTrigger::GetNumTriggers и cTrigger::GetParentTrigger
- •Использование триггеров
- •Определение файла триггеров
- •Загрузка файла триггеров
- •Касание триггера
- •Блокирование пути барьерами
- •cBarrier::SetMesh и cBarrier::SetAnim
- •cBarrier::Render
- •Добавление барьеров с cBarrier
- •Использование класса барьера
- •Создание файла данных барьеров
- •Загрузка данных барьеров
- •Проверка столкновений с барьерами
- •Визуализация барьеров
- •Использование автоматических карт
- •Автоматические карты в действии
- •Большие карты, малые карты
- •Загрузка и отображение автоматической карты
- •Создание класса автоматической карты
- •cAutomap::cAutomap и cAutomap::~cAutomap
- •cAutomap::Create и cAutoMap::Free
- •cAutomap::Load и cAutomap::Save
- •cAutomap::GetNumSections и cAutomap::EnableSection
- •cAutomap::SetWindow и cAutomap::Render
- •Использование cAutomap
- •Заканчиваем с картами и уровнями
- •Проектирование внешних боевых последовательностей
- •Техническая сторона
- •Разработка боевых последовательностей
- •Глобальные данные
- •cApp::cApp
- •cApp::Init
- •cApp::Shutdown
- •cApp::Frame
- •cApp::GetCharacterAt
- •Использование боевых аранжировок
- •Заканчиваем с боевыми последовательностями
- •Безумная многопользовательская сеча
- •Проектирование многопользовательской игры
- •Демонстрационная программа Network Game
- •Создание архитектуры многопользовательской игры
- •Работаем вместе: клиент и сервер
- •Взгляд на сервер
- •Взгляд на клиента
- •Работа над игровым сервером
- •Хранение информации игрока
- •Обработка сообщений
- •От сообщений DirectPlay к игровым сообщениям
- •Очередь сообщений
- •Обработка игровых сообщений
- •cApp::AddPlayer
- •cApp::RemovePlayer
- •cApp::PlayerInfo
- •cApp::PlayerStateChange
- •Обновление игроков
- •Обновление сетевых клиентов
- •Вычисление запаздывания
- •Самое трудное позади!
- •Работа над игровым клиентом
- •Обработка данных игрока
- •Сетевой компонент
- •Обработка сообщений
- •cApp::CreatePlayer
- •cApp::DestroyPlayer
- •cApp::ChangeState
- •Обновление локального игрока
- •Обновление всех игроков
- •Клиент во всем блеске
- •Заканчиваем с многопользовательскими играми
- •Часть IV Завершающие штрихи
- •Глава 16 Объединяем все вместе в законченную игру
- •Глава 16 Объединяем все вместе в законченную игру
- •Проектирование простой игры
- •Написание сценария игры
- •Цель игры The Tower
- •Разработка уровней
- •Определение персонажей
- •Распределение персонажей
- •Создание предметов и заклинаний
- •Разработка скриптов
- •Определение управления
- •Планирование хода игры
- •Программирование примера игры
- •Структурирование приложения
- •Конструктор cApp
- •Функция приложения Init
- •Функция Shutdown
- •Обработка кадров в функции Frame
- •Использование обработки на основе состояний
- •Работа с картами
- •Использование барьеров и триггеров
- •Управление персонажами
- •Поддержка торговли
- •Воспроизведение звуков и музыки
- •Визуализация сцены
- •Обработка скриптов
- •Собираем части
- •Завершаем создание игры
- •Часть V Приложения
- •Приложение A Список литературы
- •Рекомендованное чтение
- •Получение помощи в Web
- •Приложение B Содержимое CD-ROM
- •DirectX 9.0 SDK
- •Пробная версия GoldWave 5
- •Пробная версия Paint Shop Pro 8
- •gameSpace Light
- •Приложение C Словарь терминов
- •Алфавитный указатель

Джим Адамс
Системное ядро
Системное ядро обрабатывает инициализацию и поток выполнения программы обычного игрового приложения Windows, а также процессы, состояния и упаковку данных. Это то место, с которого вы начинаете разработку вашего нового игрового проекта.
Использование объекта ядра cApplication
Наиболее полезный объект в системном ядре — это cApplication,
который создает окно вашего приложения и управляет потоком выполнения программы. Объект регистрирует класс окна, создает окно приложения и запускает конвейер сообщений, который обрабатывает для вас посылаемые окну приложения сообщения и в случае необходимости вызывает внутренние функции класса.
При работе приложения класс cApplication вызывает три
предоставляемых вами (через объявление наследуемого класса) перегруженных функции: Init, Shutdown и Frame. У каждой из
функций есть свое особое назначение, с которым вы познакомитесь позже в этом разделе. Для работы с сообщениями Windows вам надо также предоставить обработчики сообщений. Об этом я тоже расскажу чуть позже.
А теперь пойдем вперед и взглянем на приведенный ниже код, содержащий объявление класса cApplication:
class cApplication
{
private:
HINSTANCE m_hInst; // Дескриптор экземпляра
HWND m_hWnd; |
// Дескриптор окна |
||
protected: |
m_Class[MAX_PATH]; |
// Имя класса |
|
char |
|||
char |
m_Caption[MAX_PATH]; |
// Заголовок окна |
|
WNDCLASSEX m_wcex; |
|
// Структура класса окна |
|
DWORD |
m_Style; |
|
// Стиль окна |
DWORD |
m_XPos; |
|
// Координата X окна |
DWORD |
m_YPos; |
|
// Координата Y окна |
DWORD |
m_Width; |
|
// Ширина окна по умолчанию |
DWORD |
m_Height; |
|
// Высота окна по умолчанию |
public: |
|
// Конструктор |
|
|
cApplication(); |
|
|
||
HWND |
GethWnd(); |
// Возвращает дескриптор окна |
||
HINSTANCE GethInst(); // Возвращает дескриптор экземпляра |
||||
BOOL Run(); // Исполняет код класса |
|
// Печать ошибок |
||
BOOL Error(BOOL Fatal, char *Text, ...); |
||||
BOOL Move(long XPos, long YPos); |
// |
Перемещение окна |
||
BOOL Resize(long Width, long Height); // |
Изменение размера |
|||
BOOL ShowMouse(BOOL Show = TRUE); |
// |
клиентской области |
||
// |
Скрывает или |
|||
|
|
|
// |
отображает курсор |
|
|
|
|
|
|
netlib.narod.ru |
|
297 |

Глава 6. Создаем ядро игры
// Обработка событий по умолчанию |
UINT uMsg, |
|
virtual FAR PASCAL MsgProc(HWND hWnd, |
||
|
WPARAM wParam, LPARAM lParam) { |
|
return DefWindowProc(hWnd, uMsg, wParam, lParam); |
||
} |
|
|
// Пользовательские функции, содержащие код игры |
||
virtual BOOL Init() |
{ return TRUE; } |
|
virtual BOOL Shutdown() { return TRUE; } |
|
|
virtual BOOL Frame() |
{ return TRUE; } |
|
};
Количество вызываемых функций в классе cApplication
минимально, поскольку он разработан фактически для того, чтобы исполнять самого себя — вы просто добавляете ваш код игры.
Чтобы использовать класс cApplication вы сначала должны создать класс-наследник, использующий cApplication в качестве базового
класса. Так вы выполняете перегрузку определенных функций для
соответствия вашим собственным требованиям. Перегружаемые функции, как упоминалось ранее, — это Init, Shutdown и Frame.
Вфункции cApplication::Init вы размещаете весь код
инициализации класса, такой как загрузка данных, подготовка состояний и т.д. Противоположность Init — функция cAplication::Shutdown, которая освобождает все ранее выделенные ресурсы. Функция Shutdown
вызывается самой последней, а функция Init — самой первой.
Далее следует функция cApplication::Frame, которая вызывается почти на каждой итерации цикла обработки сообщений (в том случае, если у Windows нет сообщений для обработки). Как можно предположить, функция Frame обрабатывает один кадр из вашей игры, что может включать обработку пользовательского ввода, проверку сетевых данных и рисование графики.
ПРИМЕЧАНИЕ |
Каждая из упомянутых функций (Init, Shutdown и Frame) |
||
|
возвращает логическое значение, сообщающее классу |
||
|
cApplication |
о том, продолжать ли выполнение |
|
|
программы или выйти из нее. Если какая-либо из этих |
||
|
функций возвращает |
FALSE, работа приложения |
прерывается.
У вас мало причин для перегрузки функций обработчиков сообщений, если вам не требуется собственный алгоритм обработки сообщений
Windows. Для обработки сообщений вы перегружаете функцию cApplication::MsgProc, как я вскоре покажу вам.
А пока уделите минуту своего времени на работу с классом cApplication для быстрого создания приложения. Убедитесь, что не
|
забыли включить в ваш проект файлы |
Core_System.h и Core_System.cpp, а |
|
также унаследовали класс вашего приложения, с которым будете работать, |
|
|
как показано ниже: |
|
|
|
|
298 |
netlib.narod.ru |

Джим Адамс
#include "Core_System.h"
class cApp : public cApplication
{
private:
char *m_Name;
public: |
// Конструктор |
cApp(); |
|
BOOL Init(); |
// Перегруженная функция Init |
BOOL Shutdown(); |
// Перегруженная функция Shutdown |
BOOL Frame(); |
// Перегруженная функция Frame |
};
Этот пример кода инициализирует ваше приложение регистрируя класс окна, создавая окно и запуская конвейер сообщений, в котором непрерывно вызывается функция Frame. Цель примера — создание буфера и сохранение
в нем текста (в данном случае моего имени) и отображение этого текста в каждом кадре. Завершая работу приложения вы освобождаете текстовый буфер и выходите из программы.
cApp::cApp()
{
//Присваиваем данным экземпляра
//значения по умолчанию
m_Name = NULL;
//Устанавливаем стиль, местоположение,
//ширину и высоту окна
m_Style |
= WS_OVERLAPPEDWINDOW; |
// Стиль окна |
||||
m_XPos |
= 100; |
// Координата |
X |
окна |
||
m_YPos |
= 20; |
// Координата |
Y окна |
|||
m_Width |
= |
400; |
// Ширина |
клиентской области |
||
m_Height |
= |
400; |
// Высота |
клиентской области |
// Назначаем имя класса и заголовок окна strcpy(m_Class, "NameClass"); strcpy(m_Caption, "My Name Example");
}
BOOL cApp::Init()
{
// Выделяем память для хранения имени if((m_Name = new char[10]) == NULL) strcpy(m_Name, "Jim Adams");
else
return FALSE; return TRUE;
}
BOOL cApp::Shutdown()
{
// Освобождаем буфер имени delete [] m_Name;
m_Name = NULL; // Сброс указателя
}
BOOL cApp::Frame()
{
// Отображаем имя и ждем нажатия OK или CANCEL,
netlib.narod.ru |
299 |

Глава 6. Создаем ядро игры
// выход из программы по CANCEL if(MessageBox(GethWnd(), m_Name, "My name is",
MB_OKCANCEL) == IDCANCEL) return FALSE;
return TRUE;
}
Ну вот! Все, что осталось сделать — это создать экземпляр вашего нового класса и запустить его из функции WinMain:
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
{
cApp App;
return App.Run();
}
Обработка состояний с cStateManager
В главе 1, «Подготовка к работе с книгой», было показано использование класса обработки на основе состояний. В этом разделе я применю данную
информацию в качестве фундамента и покажу вам усовершенствованную версию разработанного в главе 1 класса cStateManager. При создании ваших игр вы обнаружите, что эта версия cStateManager лучше
подходит для управления потоком выполнения игровой программы.
Новый диспетчер состояний добавляет пару концепций: цели вызова и добавление к функциям в cStateManager определяемых пользователем
указателей на данные.
ПРИМЕЧАНИЕ |
Цель вызова (calling purpose) — это, согласно названию, |
|
причина, по которой вызывается состояние. «Целью» |
|
может быть INITPURPOSE (сигнализирует, что функция |
|
должна подготовить себя к работе), FRAMEPURPOSE (для |
|
обработки отдельного кадра) или SHUTDOWNPURPOSE (для |
|
освобождения всех ресурсов, когда обработка завершена). |
Вот код объявления класса cStateManager:
class cStateManager
{
// Указатели на функции состояний (связанный список) typedef struct sState {
void (*Function)(void *Ptr, long Purpose); sState *Next;
//Конструктор структуры, очищающий указатели sState() {
Function = NULL; Next = NULL;
}
//Деструктор структуры для удаления
//из связанного списка
~sState() { delete Next; Next = NULL; } } sState;
300 |
netlib.narod.ru |

Джим Адамс
protected:
sState *m_StateParent; // Родитель связанного списка // стека состояний
public:
cStateManager(); // Конструктор ~cStateManager(); // Деструктор
//Помещает состояние в стек вместе с определяемым
//пользователем указателем. Функция помещения в стек
//вызывает функцию состояния, указывая в качестве
//цели инициализацию
void Push(void (*Function)(void *Ptr, long Purpose), void *DataPtr = NULL);
//Выталкивание верхнего состояния из стека с вызовом
//функции состояния для завершения работы
BOOL Pop(void *DataPtr = NULL);
//Выталкивание всех состояний с завершением работы
//каждого из них
void PopAll(void *DataPtr = NULL);
//Обработка верхнего состояния в стеке с указанием
//обработки отдельного кадра в качестве цели вызова
BOOL Process(void *DataPtr = NULL);
};
Работа с классом cStateManager может сперва показаться
необычной (особенно что касается целей вызова), но не следует
беспокоиться, для этого и существуют примеры! Взгляните на пример, который базируется на предыдущем примере работы с cApplication:
class cApp : public cApplication
{
private:
cStateManager m_StateManager;
// Прототипы функций состояний static void Function1(void *, long); static void Function2(void *, long);
public:
BOOL Init() { m_StateManager.Push(Function1, this); }
};
void cApp::Function1(void *DataPtr, long Purpose)
{
//Получаем указатель на вызывающий класс,
//поскольку функция статическая, а значит
//не имеет назначенного экземпляра класса cApp *cc = (cApp*)DataPtr;
//При инициализации отображаем сообщение
//и помещаем в стек второе состояние if(Purpose == INITPURPOSE) {
MessageBox(cc->GethWnd(), "State 1", "Message", MB_OK);
cc->m_StateManager.Push(Function2, cc); return;
}
netlib.narod.ru |
301 |