
- •Джим Адамс
- •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 Словарь терминов
- •Алфавитный указатель

Джим Адамс
объекта в мире, ICS может работать с несколькими экземплярами одного и того же объекта. Каждый раз, когда системе управления имуществом требуется информация о предмете, она обращается к главному списку предметов за его спецификациями. Это позволяет экономить память, сохраняя в ICS только ссылки с номерами объектов в MIL (как показано на рис. 11.7).
Рис. 11.7. Если система управления имуществом хранит только номера для ссылок на предметы, можно сэкономить значительный объем памяти, разместив всю информацию о предмете в главном списке предметов
Для игровых карт и уровней замечательно подойдет простая система управления имуществом (называемая ICS карты, map ICS), хранящая только список предметов и их местоположение на карте, поскольку она позволит разместить повсюду предметы, чтобы игроки могли собирать их. Настоящая проблема возникнет, когда игроки начнут собирать разбросанные предметы, добавляя их к своему имуществу. Накапливаются дублирующие экземпляры, добавляются новые предметы, а другие предметы используются или выбрасываются. Предметы быстро приходят в беспорядок. Обработка наборов находящихся у персонажей объектов является работой системы управления имуществом персонажей, которая несколько сложнее, чем вариант, относящийся к карте.
Разработка ICS карты
ICS карты следит за предметами, находящимися внутри уровней, включая те предметы, которые находятся внутри других, — например, меч лежащий в сундуке. Способ размещения предметов на карте зависит от используемого типа карты. На трехмерных картах для размещения предметов вы используете три координаты — X, Y и Z. Если вы разделили ваш мир на несколько карт, придется следить за предметами каждой карты, используя собственный файл предметов для каждой карты.
ICS карты представлена структурой и классом:
netlib.narod.ru |
495 |

Глава 11. Определение и использование объектов
typedef struct sMapItem |
|
{ |
// Номер предмета в MIL |
long ItemNum; |
|
long Quantity; |
// Количество предметов |
float XPos, YPos, ZPos; |
// (например, монет) |
// Координаты на карте |
|
sMapItem *Prev, *Next; |
// Указатели связанного списка |
long Index; |
// Индекс данного предмета |
long Owner; |
// Индекс владельца |
sMapItem *Parent; |
// Родитель предмета |
sMapItem()
{
Prev = Next = Parent = NULL; Index = 0; Owner = -1;
}
~sMapItem() { delete Next; Next = NULL; } } sMapItem;
class cMapICS
{
private:
long m_NumItems; // Количество предметов на карте sMapItem *m_ItemParent; // Родитель связанного списка
//предметов карты
//Чтение из файла длинного целого числа
//или числа с плавающей точкой
long GetNextLong(FILE *fp); float GetNextFloat(FILE *fp);
public:
cMapICS(); // Конструктор ~cMapICS(); // Деструктор
//Загрузка, сохранение и освобождение
//списка предметов карты
BOOL Load(char *Filename);
BOOL Save(char *Filename);
BOOL Free();
//Добавление и удаление предмета на карте
BOOL Add(long ItemNum, long Quantity,
float XPos, float YPos, float ZPos, sMapItem *OwnerItem = NULL);
BOOL Remove(sMapItem *Item);
//Возвращает количество предметов или
//родителя связанного списка объектов
long GetNumItems(); sMapItem *GetParentItem(); sMapItem *GetItem(long Num);
};
Сначала вы видите структуру sMapItem, которая хранит информацию для каждого предмета на карте. ItemNum — это номер для ссылки на
элемент MIL (который должен находиться в диапазоне от 0 до 1023, если вы
496 |
netlib.narod.ru |

Джим Адамс
используете программу MIL Editor), а Quantity — это количество предметов ItemNum (это позволяет, например, представить горсть монет
как единый объект). Затем расположены координаты предмета на карте
XPos, YPos и ZPos.
Далее следуют указатели Prev и Next. Они добавлены для формирования связанного списка структур sMapItem. Следующая пара переменных, Index и Owner, используются при загрузке и сохранении предметов на карте. Index хранит текущий индекс предмета в связанном списке. Если предмет принадлежит другому предмету, переменная Owner хранит индекс родительского объекта (в противном случае значение Owner равно –1).
При загрузке (или добавлении) объекта вы устанавливаете заключительную переменную в sMapItem (Parent), чтобы она указывала
на структуру данных действительного владельца предмета. Концепция связанного списка структур sMapItem показана на рис. 11.8.
Рис. 11.8. Вы храните список предметов карты в виде связанного списка. В процессе чтения с диска предметы нумеруются, что помогает устанавливать отношения родитель-потомок между объектами
Структура sMapItem использует и конструктор и деструктор,
вызываемые когда для структуры выделяется память и при освобождении занятых ресурсов соответственно. Обе функции обеспечивают правильность указателей связанного списка и, когда структура удаляется, все последующие структуры sMapItem в связанном списке удаляются тоже.
netlib.narod.ru |
497 |

Глава 11. Определение и использование объектов
ВНИМАНИЕ! |
Если вы хотите удалить из связанного списка только один |
|
|
экземпляр структуры |
sMapItem, сперва присвойте |
переменной Next удаляемого экземпляра значение NULL.
Это гарантирует, что все последующие экземпляры в связанном списке не будут удалены.
В классе cMapICS есть две закрытые функции (GetNextLong и GetNextFloat) используемые для чтения текста и преобразования его в значение типа long или float. Также в классе cMapICS есть восемь
полезных открытых функций. Давайте познакомимся с ними поближе. cMapICS::Load, cMapICS::Save и cMapICS::Free
Согласно своим именам, это трио функций загружает, сохраняет и освобождает список относящихся к карте предметов. Первая из трех, Load,
создает и загружает список предметов. Для простоты, все предметы хранятся в текстовом файле, использующем следующий формат:
MIL_ItemNum Quantity XPos
YPos
ZPos ParentID
Каждый предмет использует шесть строк текста, и каждый элемент (группа из шести строк) последовательно нумеруется (первый предмет в файле — это предмет 0, второй предмет — предмет 1 и т.д.). Вот пример файла, содержащего два предмета:
// Описание предмета 0:
10 // Номер предмета в MIL (значение long)
1// Количество (значение long)
10.0// XPos (значение float)
0.0 // YPos (значение float)
600.0// ZPos (значение float)
-1 // Владелец (-1 = нет, иначе его индекс) // Описание предмета 1:
1// Номер предмета в MIL
1 // ...
10.0
0.0
600.0
0// Относится к предмету 0 (первому предмету в файле)
Комментарии добавлены только для ясности; в реальном файле их не
будет. Читая список предметов, такой как показан выше, функция Load преобразует текст в числа. Из этих чисел создается структура sMapItem
для каждого загруженного предмета на карте и формируется связанный список загруженных предметов. После считывания данных каждого предмета выполняется сопоставление связанных между собою предметов (с использованием указателя Parent в структуре sMapItem).
498 |
netlib.narod.ru |

Джим Адамс
Здесь нет ничего по-настоящему сложного, так что давайте перейдем прямо к коду cMapICS::Load:
BOOL cMapICS::Load(char *Filename)
{
FILE *fp; long LongNum;
sMapItem *Item, *ItemPtr = NULL;
Free(); // Освобождаем предыдущий набор
// Открываем файл if((fp=fopen(Filename, "rb"))==NULL)
return FALSE;
Сразу после открытия файла (показанного в предыдущем фрагменте кода), вы можете начинать загружать данные предметов. Первый фрагмент данных, который вам надо загрузить — это номер предмета. Как только номер предмета загружен, вы создаете новую структуру данных предмета карты и присоединяете ее к связанному списку предметов. Кроме того, одни предметы могут быть связаны с другими (например, эликсир может находиться в котомке, и в этом случае эликсир и котомка связаны между собою). Процесс продолжается, пока не будут загружены все предметы.
// Бесконечный цикл чтения данных предметов while(1) {
//Получаем номер следующего предмета
//(прерываемся, если больше нет предметов,
//о чем свидетельствует возвращаемое значение -1) if((LongNum = GetNextLong(fp)) == -1)
break;
// Создаем новый указатель карты и привязываем его
Item = new sMapItem(); if(ItemPtr == NULL)
m_ItemParent = Item; else {
Item->Prev = ItemPtr;
ItemPtr->Next = Item;
}
ItemPtr = Item;
//Сохраняем номер предмета в MIL
Item->ItemNum = LongNum;
//Получаем количество
Item->Quantity = GetNextLong(fp);
// Получаем координаты
Item->XPos = GetNextFloat(fp); Item->YPos = GetNextFloat(fp); Item->ZPos = GetNextFloat(fp);
//Получаем номер владельца
Item->Owner = GetNextLong(fp);
//Сохраняем индекс и увеличиваем счетчик
Item->Index = m_NumItems++;
netlib.narod.ru |
499 |

Глава 11. Определение и использование объектов
}
//Закрываем файл fclose(fp);
//Сопоставляем взаимосвязанные объекты
ItemPtr = m_ItemParent;
while(ItemPtr != NULL) {
// Проверяем, относится ли предмет к другому if(ItemPtr->Owner != -1) {
// Находим соответствующий родительский предмет
Item = m_ItemParent; while(Item != NULL) {
if(ItemPtr->Owner == Item->Index) {
// Связываем, устанавливая указатель на родителя
ItemPtr->Parent = Item;
break; // Останавливаем сканирование родителей
}
Item = Item->Next;
}
}
// Переходим к следующему предмету
ItemPtr = ItemPtr->Next;
}
return TRUE;
}
ПРИМЕЧАНИЕ |
Подобно |
большей |
части кода из этой книги, функции |
|
|
класса |
cMapICS |
возвращают |
TRUE, если функция |
завершена успешно, и FALSE, если произошла ошибка.
Функция Save берет внутренний список предметов и, используя указанное вами имя файла, записывает этот список в файл на диске. Функция Save обычно используется для обновления игровых данных, поскольку игроки могут подбирать одни предметы и выбрасывать другие.
Сперва функция Save назначает каждой структуре sMapItem в
связанном списке значение индекса (основываясь на их порядке следования). Первому элементу связанного списка присваивается индекс 0, второму — индекс 1 и т.д. Затем обновляются переменные Owner во всех дочерних объектах и данные записываются в файл:
BOOL cMapICS::Save(char *Filename)
{
FILE *fp; sMapItem *Item; long Index = 0;
//Открываем файл if((fp=fopen(Filename, "wb")) == NULL)
return FALSE;
//Назначаем индексы предметам if((Item = m_ItemParent) == NULL) {
fclose(fp);
return TRUE; // Нет предметов для сохранения
}
500 |
netlib.narod.ru |