Программирование шаблона


Программирование шаблона
Приготовьтесь к беспощадной драке, поскольку пришло время спуститься с небес на землю и заняться шаблонами подразделений. Данный раздел книги более сложен, чем остальные, так что будьте внимательн...
Окно программы D3DFrame_UnitTemplate
На Рисунок 8.7 показано окно программы D3DFrame_UnitTemplate, входящей в сопроводительные файлы к книге. На рисунке видны четыре вертолета летящих над травяным полем. В верхнем левом углу окна вы...
Класс CUnitDefense
Помните, как типы защиты помогают структурировать данные подразделений? Теперь вы добрались до практического примера, показывающего как реализовать эту концепцию в виде класса. Откройте заголовочн...
Члены данных класса CUnitDefense
Класс очень простой и содержит только открытые члены данных, конструктор, деструктор и единственный метод. Главным образом я использую классы как структуры данных, так что не ожидайте наличия соте...
Коэффициенты защиты
Как видно из Рисунок 8.8, я предусмотрел четыре коэфиициента защиты: для ракет, для пуль, для лазера и для рукопашной схватки. Это придает игре достаточную гибкость для поддержки четырех различных...
Очки повреждений
Далее на Рисунок 8.8 изображена переменная m_iHitPoints. Я использую ее для хранения общего количества очков повреждений, которое данное подразделение может получить во время битвы. Когда количест...
Скорость восстановления
Раньше я не упоминал о восстановлении здоровья подразделений, так что эта идея может показаться вам новой. В классе типа защиты есть переменная с именем m_iRegenRate, позволяющая создавать подразд...
Тип защиты
В переменной m_iType хранится число, определяющее тип защиты. Например, ноль может соответствовать броне легкого танка, а единица — броне среднего танка. Диапазон значений зависит от того, как мно...
Название защиты
Переменная m_szName хранит название защиты в виде строки символов. Я использую ее чтобы было проще узнать тип защиты подразделения без необходимости запоминать соответствующие числовые значения. Э...
Методы класса CUnitDefense
В классе есть только конструктор, деструктор и функция сброса значений переменных, так что в плане функциональности он весьма ограничен. Вот как выглядит код, реализующий перечисленные функции://...
Класс CUnitOffense
Подобно классу типов защиты, класс типов атаки помогает вам организовать данные о подразделениях. Я пользуюсь классом с именем CUnitOffense, который выполняет за меня всю необходимую работу. Посмо...
Члены данных класса CUnitOffense
Члены данных класса выглядят очень знакомо, за исключением того, что эти значения относятся к атаке, а не к обороне. Члены данных класса показаны на Рисунок 8.9....
Коэффициенты поражения
На рис 8.9 показаны четыре коэффициента поражения: для ракет, для пуль, для лазера и для рукопашной схватки. Точно также как и в классе обороны, эти значения относятся к тем типам атаки, которые у...
Радиус взрыва
Переменная m_iSplashRadius сообщает, какое количество повреждений может нанести разрыв снаряда, выпущенного из данного типа оружия. Это полезно для таких типов вооружения, как гранаты, катапульты...
Радиус взрыва
На Рисунок 8.10 изображены три танка. Нижний танк стреляет из своего главного орудия по одному из двух верхних вражеских танков. Радиус взрыва танкового снаряда равен 2, а значит его сфера повреж...
Скорострельность
Переменная m_iRateOfFire сообщает вам, сколько раундов игры должно пройти, прежде чем оружие сможет снова выстрелить. Быстродействующее оружие, такое как автомат, может стрелять залпами в каждом р...
Скорость снаряда
Переменная m_fProjectileSpeed задает с какой скоростью снаряд покидает ствол оружия. Это значение применимо только для снарядов и ракет, поскольку в рукопашной схватке снаряды отсутствуют, а лазер...
Дальнобойность
Переменная m_iRange сообщает вам количество блоков игрового поля, на которое может выстрелить данный тип оружия. Это применимо только к вооружению, действующему на расстоянии, поскольку для ручног...
Тип атаки
Переменная m_iType хранит число, соответствующее данному типу атаки. Это работает точно так же, как и для типов защиты....
Название типа атаки
Переменная m_szName хранит название типа атаки в виде последовательности символов. Это поле действует аналогично полю с названием типа защиты....
Методы класса CUnitOffense
В классе есть только констуктор, деструктор и функция установки начальных значений, действующая во многом так же как одноименная функция класса типов защиты. Вот как выглядит код реализации функци...
Класс CUnitMovement
Класс способов передвижения также помогает организовать ваши боевые единицы. Для выполнения этой работы я использую класс CUnitMovement. Вот как выглядит его заголовок:class CUnitMovement { public...
Члены данных класса CUnitMovement
Класс содержит переменные, аналогичные тем, которые находятся в классе атаки, за исключением того, что их значения относятся к перемещению, а не атаке. Члены данных класса показаны на Рисунок 8.11...
Скорость передвижения
На Рисунок 8.11 присутствуют несколько переменных, контроллирующих передвижение боевых единиц. Первая из них, скорость передвижения, указывает на сколько блоков игрового поля может переместиться д...
Способ передвижения
Данное поле сообщает вам какой именно способ использует подразделение для своего передвижения. Летает оно, плавает или ползает? Может быть оно ходит? Может быть оно катится? Переменная, задающая с...
Ускорение и торможение
Чтобы добавить сложности, я включил параметры, задающие ускорение и торможение. Ускорение определяет на сколько возрастает скорость подразделения за раунд игры, когда оно разгоняется. Торможение с...
Скорость поворота
Последний уникальный элемент данных класса передвижения сообщает вам насколько быстро подразделение поворачивает. Это число с плавающей точкой, указывающее на сколько градусов может развернуться п...
Два подразделения с разной скоростью поворота
На Рисунок 8.12 скорость поворота левого танка равна 45. Скорость поворота правого подразделения равна 22.5. За два раунда левый танк повернется вправо. И у него останется еще два раунда, прежде...
Методы класса CUnitMovement
В классе есть только констуктор, деструктор и функция установки начальных значений, работающая во многом так же как одноименная функция класса типов атаки. Вот как выглядит код реализации этих фун...
Класс CUnitAnimation
Также как и класс способов передвижения, класс анимации помогает организовать ваши подразделения. Я использую класс с именем CUnitAnimation. Вот как выглядит его заголовок:const int UNITMANAGER_MA...
Члены данных класса CUnitAnimation
В классе анимации есть несколько интересных членов данных. Первые из них хранят количество графическх кадров в различных анимационных последовательностях подразделения. Существует четыре типа аним...
Анимация ожидания
Переменная m_iNumStillFrames сообщает сколько кадров используется в анимационной последовательности, изображающей боевую единицу в состоянии ожидания. Множество подразделений в состоянии ожидания...
Кадры анимации ожидания для танка
Обратите внимание, что для танка, находящегося в состоянии ожидания, достаточно одного кадра. Это вызвано тем, что в состоянии ожидания танк ничего не делает!...
Анимация передвижения
Следующая переменная, m_iNumMoveFrames, сообщает сколько кадров в анимационной последовательности, показываемой при передвижении боевой единицы. Пример показан на Рисунок 8.14....
Кадры анимации передвижения танка
Как видите, при передвижении танка используются три кадра анимации. Положение колес на каждом из кадров слегка отличается. В результате, показываемые один за другим, эти кадры создают иллюзию дви...
Анимация атаки
Переменная, m_iNumAttackFrames, указывает, сколько кадров присутствует в анимационной последовательности, показываемой когда подразделение кого-нибудь атакует. Этот момент иллюстрирует Рисунок 8.1...
Кадры анимации танковой атаки
На Рисунок 8.15 видно, что для анимации атакующего танка используется два кадра. На первом кадре изображен обычный танк, а на втором кадре к его изображению добавляется вспышка выстрела. Красота...
Анимация гибели
Переменная m_iNumDieFrames сообщает вам сколько кадров содержится в анимационной последовательности, показываемой при гибели боевой единицы. Пример показан на Рисунок 8.16....
Кадры гибели танка
Обратите внимание, что на Рисунок 8.16 для анимации гибели танка используются три кадра. В первом кадре изображен обычный танк, во втором кадре нарисован красивый взрыв, а в третьем кадре мы види...
Начальный кадр анимации
Четыре переменных сообщают вам какой кадр является начальным для каждого типа анимации. Сперва это может звучать странно, и чтобы облегчить понимание взгляните на Рисунок 8.17....
Полная анимационная последовательность для танка
На Рисунок 8.17 показаны сразу все кадры анимации танка. Первый кадр — это изображение ожидающего танка. Следующие три кадра содержат анимационную последовательность для движения. Следующие два к...
Данные текстуры
Указатель m_Textures применяется для хранения кадров анимации подразделения. Он указывает на массив объектов CTexture и замечательно справляется с задачей хранения информации. Переменная m_iTotalT...
Методы класса CUnitAnimation
В классе анимации есть уже ставшие привычными конструктор, деструктор и функция установки начальных значений, но к ним добавились две новые функции: vSetRenderDevice() и vLoadTextures()....
Функция CUnitAnimation vSetRenderDevice()
Поскольку DirectX для загрузки текстуры необходимо устройство визуализации, я добавил функцию установки устройства визуализации, которая инициализирует указатель на устройство. В единственном пара...
Функция CUnitAnimation vLoadTextures()
Функция загрузки текстур получает информацию, хранящуюся в относящихся к кадрам анимации членах данных класса и загружает соответствующие файлы с текстурами. Вот ее код:void CUnitAnimation::vLoadT...
Цвета владельца
Здесь начинаются хитрости анимационной графики. Функция загрузки текстур выделяет необходимую для текстур память, а затем в цикле перебирает кадры каждой анимационной последовательности, загружая...
Кадры с цветами владельца для вертолета Apache
На Рисунок 8.18 показаны кадры состояния ожидания для вертолета Apache. Первый кадр содержит изображение самой боевой единицы. На нем вы видите корпус вертолета, оружие, механизмы и лопасти пропе...
Анимационная последовательность
На Рисунок 8.19 показаны анимационная последовательность ожидания и анимационная последовательность передвижения для танка, которые я уже демонстрировал ранее. Однако здесь в них внесено нескольк...
Функция CUnitAnimation vReset()
Поскольку в класс анимации включены графические данные, функция установки начальных значений стала сложнее. Это вызвано тем, что функция должна освобождать память, выделенную для хранения текстур....
Класс CTexture
Как я упоминал ранее, класс текстур используется мной для хранения данных Почему я использую отдельный класс текстур? Я думаю, что такой подход упрощает переход к новым версиям DirectX. Вместо тог...
Члены данных класса CTexture
Переменная m_szName хранит имя файла с текстурой, а переменная m_pTexture хранит загруженные данные. Еще раз упомяну переменную m_pd3dDevice. Она необходима для загрузки данных текстуры....
Методы класса CTexture
Помимо конструктора и деструктора в классе текстуры присутствуют три функции: vLoad(), vRelease() и vSetRenderDevice()....
Функция CTexture vLoad()
Функция загрузки пользуется весьма полезной вспомогательной библиотекой DirectX чтобы загрузить графическое изображение из файла в буфер данных текстуры. Вот как выглядит код этой функции:void CTe...
Функция CTexture vRelease()
Функция освобождения ресурсов очень проста, поскольку ей необходимо только освободить выделенную для хранения текстуры память. Вместо оператора delete используется метод Release, поскольку это тре...
Функция CTexture vSetRenderDevice()
Чтобы обеспечить возможность установки внутреннего указателя на устройство визуализации, я предоставляю функцию задания устройства визуализации. Она получает указатель на основное устройство трехм...
Класс CUnit
Вот мы и рассмотрели все необходимые для подразделения базовые классы. У нас есть готовые к использованию данные защиты, атаки, передвижения и анимации. Отсутствует только клей, который соединит э...
Структура объекта подразделения
На Рисунок 8.20 видно, что класс подразделения состоит из базовых классов и данных состояния. В блоке данных состояния находятся переменные для различных параметров, таких как текущее количество...
Члены данных класса CUnit
Давайте начнем с указателей на базовые типы. В рассматриваемом примере есть тип защиты, три типа атаки, тип перемещения и тип анимации. Я использую три типа атаки потому что на одной боевой единиц...
Взаимосвязь между переменными состояния и базовыми типами
На Рисунок 8.21 вы можете видеть как переменные состояния связаны с соответствующими базовыми типами. Например, максимальное значение номера кадра анимации ожидания берется из находящегося в клас...
Методы класса CUnit
В классе CUnit я реализовал сравнительно мало методов. Идея проста — вы сами добавите необходимые вам методы, базируясь на потребностях собственного проекта. Итак, вот та часть работы, которую я п...
Функция CUnit vReset()
Функция установки начальных значений работает точно так же, как и в других, рассмотренных в этой главе классах, присваивая данным подразделения значения по умолчанию. Здесь нет ничего сложного, по...
Функция CUnit vSetBaseValues()
Данная функция устанавливает указатели на базовые классы для подразделения. Вы можете сделать это вручную, но наличие одной простой функкции сделает вашу жизнь чуть легче. Вот как выглядит код фун...
Функция CUnit vSetPosition()
Функция задания местоположения позволяет установить координаты X и Y подразделения с помощью одного вызова. Она получает данные о новом местоположении подразделения и сохраняет их во внутренних пе...
Класс CUnitManager
Теперь у вас есть класс атаки, класс защиты, класс передвижения, класс анимации и даже класс подразделения, чтобы объединить все предыдущие классы в единое целое. Чего же не хватает? Класса для уп...
Загрузка базовых типов
У вас есть базовые классы для хранения данных подразделения, но как загрузить в них информацию? Один из способов — жестко задать все значения параметров подразделений в коде программы. Подобное сл...
Базовые типы в классе диспетчера подразделений
На Рисунок 8.22 показаны базовые типы, содержащиеся в классе диспетчера подразделений. Слева указаны типы, а в центре — названия реальных полей. Изображения хранилищ данных справа на рисунке пред...
Функция CUnitManager iLoadBaseTypes()
Вы узнали, качие элементы класса хранят информацию базовых типов, но как загружаются данные? Здесь вступает в игру функция iLoadBaseTypes(). Она получает пять параметров, каждый из которых являетс...
Импорт данных из пяти различных
На Рисунок 8.23 показано как диспетчер подразделений загружает информацию в базовые типы из пяти различных файлов данных. Имена этих файлов BaseType_Defense.csv, BaseType_Offense.csv, BaseType_Mo...
Данные защиты в электронной таблице Excel
На Рисунок 8.24 показаны уже представленные ранее данные, но в виде гораздо лучше выглядящей электронной таблицы с названиями столбцов. Если у вас есть программа для работы с электронными таблица...
Данные атаки хранящиеся в электронной таблице Excel
Следом загружаются данные подразделений. Здесь все происходит так же, как и при загрузке типов защиты, атаки и передвижения, за исключением того, что логика загрузки данных подразделений использу...
Функция CUnitManager ptrGetDefenseType()
Данная функция получает в своем единственном параметре строку и ищет тип защиты с указанным именем. Если такой тип найден, функция возвращает указатель на него. Вот как выглядит код этого бриллиан...
Создание подразделений
Теперь, после того как базовая информация о подразделених загружена, вы можете создавать подразделения, которые будут использоваться в игре. Вы не можете модифицировать базовые типы, так что следу...
Функция CUnitManager iAddUnit()
Когда вы хотите ввести в игру новое подразделение, следует вызвать функцию добавления подразделения. Она находит неактивное подразделение и инициализирует его данные для использования в игре. Вот...
Взаимосвязь между статическими
На Рисунок 8.27 видно, как динамические данные подразделений из массива m_UnitObjs используют в качестве основы данные, хранящиеся в базовых типах....
Управление текстурами
Я уже показывал вам управление текстурами ранее, в разделе посвященном импорту данных подразделений. Поскольку функция iLoadBaseTypes() загружает все тербуемые текстуры, можно считать, что управле...
Рисование подразделений
Все эти классы великолепны, но как насчет визуализации? Если вы откроете файл main.cpp из проекта D3DFrame_UnitTemplate, я покажу вам! Спускайтесь вниз до функции vInitTileVB(). Вы, возможно, еще...
Два квадрата с различными базовыми точками
На рисунке изображены два квадрата. У левого квадрата базовая точка находится в левом нижнем углу. У правого квадрата базовая точка расположена в центре. Вращение левого квадрата бдет сопровождат...
Два текстурированных квадрата с различными базовыми точками
На Рисунок 8.29 показаны те же два квадрата, что и ранее, но на них нанесена текстура с изображением танка. Танк слева поворачивается очень странно, поскольку его базовая точка расположена неверн...
Координаты вершин квадрата с базовой точкой в центре
На Рисунок 8.30 вы видите квадрат с базовой точкой, находящейся в центре. Так же там показано расположение осей X, Y и Z относительно вершин квадрата. Точки снизу и слева находятся в отрицательно...
Функция vDrawUnit()
Теперь, когда у вас есть буфер вершин для подразделения, необходимо место для выполнения визуализации. Здесь выходит на сцену функция рисования подразделения. Она работает точно так же, как функци...
Функция vRender()
Сейчас у вас есть буфер вершин для подразделения и функция, помогающая при визуализации. Белым пятном остается место, где создается изображение каждого кадра. Встречайте старого знакомого — функци...
Использование альфаканала
Первые отличия кода функции проявляются в том месте, где я включаю альфа-смешивание. Это действие позволяет видеть блоки карты сквозь текстуры подразделений. Сам процесс достаточно прямолинеен и о...
Отображение активных подразделений
Осталось только выполнить цикл, который будет перебирать все подразделения и отображать те из них, которые в данный момент активны. Выполняющий эту задачу фрагмент кода приведен ниже:// Цикл переб...
Ход выполнения функции визуализации
На Рисунок 8.31 видно, что функция визуализации вызывает перед началом визуализации функцию обновления данных подразделений. Это важный шаг, так как кадры анимации подразделений должны быть обнов...
Обновление кадра анимации
Перед тем как я погружусь в работу функции обновления подразделений, давайте взглянем на следующий код:// Обновление подразделений if(timeGetTime() > dwLastUpdateTime) { vUpdateUnits(); dwLastU...
Обработка ожидающих подразделений
Первое действие представляет собой состояние «ничегонеделанья» или ожидания. Код для его обработки выглядит следующим образом:ptrUnit->m_iCurStillFrame++; if(ptrUnit->m_iCurStillFrame >=...
Обработка поворачивающих подразделений
Второе действие представляет собой разворот подразделения. Вот предназначенный для этого код:// Поворот ptrUnit->m_fRot += ptrUnit->m_Movement->m_fTurnSpeed; // Сброс, если завершен полны...
Обработка атакующих подразделений
Третий тип анимации относится к атакующим подразделениям. Код работает точно так же, как и код для обработки ожидающих подразделений — в нем кадр с изображением атакующего подразделения последоват...
Обработка гибнущих подразделений
Четвертый тип анимации имеет дело с гибнущими подразделениями. Код работает точно так же, как и код для обработки атакующих подразделений — кадры последовательно меняются, пока не будет достигнут...
Обработка перемещающихся подразделений
Последний тип анимации относится к перемещающимся подразделениям. Код, который я поместил в пример выглядит очень похоже на обработку анимации других действий, но в нем отсутствует код для передви...
Загрузка и создание подразделений
Я показал вам как написать классы подразделений, управлять подразделениями и анимировать их. Последняя тема, которую я затрону — загрузка и создание новых подразделений. В рассматриваемом примере...
Итоги
Мы уже достигли конца очередной главы? Это произошло так быстро! Вот несколько секретов, которые мы узнали в этой главе: Вот четыре блока, которые являются фунндаментом разработки подразделений: а...
Обзор DirectInput
DirectInput — это часть DirectX, которая обрабатывает все формы ввода от игрока. Вы можете управлять мышью, клавиатурой, джойстиками, устройствами с обратной связью и многими другими типами устрой...
Объекты DirectInput
На Рисунок 9.1 изображен главный объект DirectInput с двумя объектами устройств. Левый объект является мышью, а правый — клавиатурой. Под мышью изображен экземпляр объекта устройства, представляю...
Интерфейс IDirectInput8
Рабочей лошадкой DirectInput является интерфейс IDirectInput8. Это COM-объект, отвечающий за настройку среды ввода. После того, как вы создали объект DirectInput можно создавать устройства для объ...
Интерфейс IDirectInputDevice8
Объект DirectInput создает устройства в виде объектов интерфейса IDirectInputDevice8. Интерфейс IDirectInputDevice8 выполняет большую часть работы по поддержке конкретного устройства. Чтобы создат...
Ввод с клавиатуры
То, что вы прочитали можно назвать самым коротким обзором DirectInput. Причина подобной краткости в том, что стратегические игры не требуют сложных устройств ввода. Нет никакой необходимости испол...
Проект DInput_Simple
В сопроводительные файлы книги включен проект DInput_Simple. Он строит небольшое приложение, создающее объект клавиатуры и читающее поступающие от него данные. Окно программы показано на Рисунок 9...
Окно программы DInput_Simple
На Рисунок 9.2 изображено обычное окно с текстом, сообщающим, что для выхода из программы следует нажать на клавишу Esc. Вместо того, чтобы использовать для перехвата нажатия на клавишу Esc сообщ...
Инициализация DirectInput
Откройте файл main.cpp и найдите код функции WinMain(). В ней вы найдете обычный код создания объектов Windows, за которым следует код инициализации DirectInput и устройства клавиатуры, выглядящий...
Функция iInitDirectInput()
Функция iInitDirectInput() — это мое собственное творение и я использую ее для создания главного объекта DirectInput. Код, используемый мной для создания упомянутого объекта должен выглядеть для в...
Функция iInitKeyboard()
Теперь, когда у нас есть действующий объект ввода в форме глобального указателя pDI, можно создать интерфейс объекта клавиатуры. Здесь выходит на сцену моя функция iInitKeyboard(). В ней я создаю...
Буферизованный ввод с клавиатуры
Следующая часть функции может показаться вам странной, поскольку пока я еще не объяснил ее назначение. Дело в том, что для клавиатуры имеется два способа получения входных данных: непосредственный...
Непосредственное чтение данных клавиатуры
На Рисунок 9.4 видно, что программа обработала только нажатие клавиши L, поскольку возвращаются только данные о непосредственно нажатых клавишах. Вы когда-нибудь играли в игру, которая в половине...
Буферизованный ввод с клавиатуры
На Рисунок 9.5 показан тот же процесс, что и на Рисунок 9.4, за исключением того, что функция чтения с клавиатуры получает каждое нажатие клавиш, произошедшее с начала игрового цикла. Это более м...
Функция IDirectInputDevice8 SetProperty()
Реализация буферизованного ввода достаточно проста — достаточно установить свойство устройства клавиатуры. Это осуществляется с помощью функции установки свойств. Вот как выглядит ее прототип:HRES...
Установка формата данных клавиатуры
Затем вы должны задать формат данных клавиатуры. Это простая формальность, для соблюдения которой достаточно вызвать функцию IDirectInputDevice8::SetDataFormat(). Функция получает один параметр, з...
Установка уровня кооперации
Поскольку DirectX предоставляет прямой доступ к аппаратуре, очень важен уровень кооперации устройства. Он определяет как программа может использовать данный ресурс совместно с другими приложениями...
Захват клавиатуры
Последний, относящийся к DirectX этап — вызов функции IDirectInputDevice8::Acquire(). Эта функция необходима для привязки приложения к используемому им устройству ввода. Всякий раз когда окно теря...
Раскладка клавиатуры
В рассматриваемом примере я покажу вам как считывать коды клавиш DirectInput и ASCII-коды клавиш. Чтобы получить возможность преобразования кодов DIK в коды ASCII вы должны вызвать функцию GetKeyb...
Чтение данных клавиатуры
Вернемся к функции WinMain() и рассмотрим следующий фрагмент кода:while(msg.message != WM_QUIT) { if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&...
Функция iReadKeyboard()
Вместо того, чтобы одним махом показать вам весь код функции, я разделил его на небольшие кусочки. Вот первый фрагмент функции iReadKeyboard():if(!pKeyboard || !pDI) { return(INPUTERROR_NOKEYBOARD...
Определение состояния DIK
Массив didKeyboardBuffer хранит данные возвращенные DirectInput. Чтобы сделать их читаемыми, необходимо проверить значение каждого элемента массива. Если результат поразрядной логической операции...
Преобразование кода DIK в код ASCII
Для преобразования кодов DIK в коды ASCII я написал следующую функцию:BYTE Scan2Ascii(DWORD scancode) { UINT vk; // Преобразование скан-кода в код ASCII vk = MapVirtualKeyEx(scancode, 1, g_Layout)...
Ввод текста в игре
Решение задачи ввода текста в игре может казаться лежащим на поверхности, но есть множество моментов, на которые следует обратить внимание. Как, например, вы будете обрабатывать ввод текста в разг...
Пример ввода текста в игре
На Рисунок 9.7 вы видите уже ставший знакомым интерфейс игры Battle Armor с полем ввода текста в центре экрана. В это поле вводится имя игрока. Обратите внимание, что я ввел в это поле строку «Lo...
Навигация по меню
Вы можете вспомнить, как в главе 6 навигация по меню была реализована в функции проверки ввода. Внутри нее программа смотрела, активирована ли какая-нибудь из зон меню. Если да, код определял како...
Структура функции проверки ввода
На Рисунок 9.9 видно как функция проверки ввода проверяет активные зоны, в случае необходимости обновляет меню, а также проверяет клавиатуру. Ключевой особенностью рассматриваемого примера являет...
Активация ввода текста
Функция установки активных зон отвечает за размещение в интерфейсе игры горячих точек, реагирующих на щелчки кнопок мыши. Помимо этого она применяется для активации ввода текста в экране начала но...
Обработка текстового ввода
Теперь, когда система текстового ввода активизирована, вам необходимо обработать поступающие от клавиатуры данные и сохранить результат в буфере символов. Этим занимается функция vCheckInput(). Ра...
Блоксхема ввода данных с клавиатуры
На Рисунок 9.10 показана логика, необходимая для получения данных от клавиатуры и их помещения в текстовое поле. Начнем сверху: программа вызывает функцию чтения с клавиатуры, чтобы проверить ест...
Отображение введенного текста
Вы видели как инициализируется текстовый ввод и как происходит обработка полученных от клавиатуры данных, но где же отображение текста? Эта сложная задача возложена на функцию визуализации, котора...
Ход выполнения процедуры отображения текста
На рис 9.11 видно как функция визуализации проверяет номер текущего экрана, чтобы выяснить что именно должно быть отображено. Если активен экран номер четыре, она переходит к визуализации текстов...
Интерфейс шрифта
Возможно, рассматривая код визуализации вы заметили, что для отображения текста на экране я использую объект с именем pD3DXFont. Это экземпляр предоставляемого DirectX интерфейса ID3DXFont. Данный...
Функция ID3DXFont DrawText()
Прототип функции DrawText() выглядит следующим образом:INT DrawText( LPCSTR pString, INT Count, LPRECT pRect, DWORD Format, D3DCOLOR Color ); Первый параметр, pString, исключительно прост, ведь в...
Итоги
В этой главе я показал вам как реализовать в ваших играх ввод данных с клавиатуры. Есть множество доступных методов ввода, и я надеюсь, что вы возьмете показанное вам в этой главе за основу более...
Основы редактирования карт
Первый вопрос, который вы должны задать: «Что такое редактор карт?». Редактор карт помогает вам собирать вместе графические блоки карты в формате, пригодном для использования в вашей игре. Он очен...
Редактор уровней игры Warcraft III
На Рисунок 10.1 представлено окно редактора уровней игры Warcraft III, поставляемого вместе с игрой и являющегося очень мощным инструментом. Он позволяет вам редактировать карты, поставляемые с и...
Компоненты редактора карт
Давайте еще раз взглянем на Рисунок 10.1, чтобы выделить компоненты редакторов карт и уровней. На представленной иллюстрации можно отметить несколько ключевых компонентов: Область редактирования....
Область редактирования
Область редактирования — это компонент редактора карт в котором осуществляется фактическое редактирование карты. Обычно область редактирования представляет вид на карту, который во многом, если не...
Редактор уровней Warcraft III с включенной сеткой
На рисунке показана область редактирования редактора уровней игры Warcraft III с включенной сеткой редактирования. Как видите, сетка ускоряет выравнивание плиток....
Область выбора блоков
Поскольку карты создаются из блоков, вам в редакторе необходимо предусмотреть область выбора блоков. В ней отображаются доступные блоки, и вы можете выбрать тот, который собираетесь использовать,...
Миникарта
Область мини-карты показывает вам, как редактируемый мир выглядит с большой высоты. На Рисунок 10.1 и Рисунок 10.2 мини-карта расположена в левом верхнем углу интерфейса. Хороший метод для примене...
Область вывода информации
Хорошей идеей будет предусмотреть в редакторе область для вывода текстовых сообщений. Вы можете показывать в ней общее количество используемых блоков, размер карты, текущие координаты и другую инф...
Просмотр карты
Хватит уже теории! Как насчет какого-нибудь кода, который покажет вам как создать свой собственный редактор карт? Загрузите проект D3D_MapViewer и следуйте вперед. Программа D3D_MapViewer создает...
Окно программы просмотра карты
На Рисунок 10.3 вы видите выглядящий знакомым набор блоков, отображенный в окне несколько большего размера. Отличие этой блочной карты от примеров из главы 5 заключается в том, что вы можете пере...
Глобальные переменные карты
В заголовочном файле main.h проекта находится несколько исключительно важных типов данных, используемых для просмотра карты. Вот их краткий список:int g_iTileSize = 32; int g_iTilesWide = 20; int...
Глобальные переменные для просмотра карты
На Рисунок 10.4 видно как ширина и высота карты задают ее общий размер. Также видно как размер окна просмотра задается в блоках. Кроме того, можно обратить внимание как координаты области просмот...
Ход выполнения программы
Ход выполнения программы очень похож на работу остальных примеров в этой книге. Сперва выполняется инициализация составляющих программу систем. После ее завершения программа начинает обработку соо...
Ход выполнения программы просмотра карт
На Рисунок 10.5 появилась только одна новая функция — vInitMap()....
Генерация случайной карты
Функция vInitMap() отвечает за создание случайной карты. Взгляните как выглядит код, выполняющий эти действия:void vInitMap(void) { int i; // Заполнение карты случайными блоками for(i = 0; i <...
Навигация по карте
На блок-схеме программы, изображенной на Рисунок 10.5, присутствует вызов функции vCheckInput(). Навигация по карте осуществляется путем нажатия на клавиши, так что это очень важная функция. Следу...
Ход выполнения функции проверки входных данных
На Рисунок 10.6 показан ход выполнения функции проверки входных данных. В первой части кода я проверяю буфер клавиатуры, чтобы убедиться, что пользователь нажимал на какие-нибудь клавиши. Если да...
Загрузка изображений блоков
Вы уже посмотрели, как программа осуществляет навигацию на карте, но что насчет отображения графики? Программа бесполезна без визуальной обратной связи. Старая добрая функция vInitInterfaceObjects...
Визуализация блоков
Функция vRender() занимается отображением блочной карты. В ней я в цикле перебираю блоки карты и отображаю текстуры, соответствующие номерам блоков. Вот код цикла визуализации:// Сверху вниз for(i...
Редактирование карты
К данному моменту у вас появилась лишь возможность интерактивного просмотра карты. Как насчет того, чтобы действительно поредактировать ее? Заучит заманчиво, а? В этом разделе я покажу вам как нап...
Окно программы D3D_MapEditorLite
На Рисунок 10.7 изображено окно программы D3D_MapEditorLite. Оно выглядит очень похоже на окно программы просмотра карт, о которой вы уже читали. Главным отличием данной программы является добавл...
Глобальные переменные карты
В заголовочном файле проекта main.h появилось несколько новых членов данных, необходмых для редактирования. Вот они в порядке их появления:int g_iCurTile = 0; int g_iCurTileSet = 0; int g_iMaxTile...
Ход выполнения программы
Ход выполнения программы редактирования карты практически не отличается от работы программы просмотра карты. Также как и в программе просмотра карт, здесь сперва инициализируются клавиатура, систе...
Программирование панели инструментов
Панель инструментов с областью выбора блоков является очень важной частью редактора карт. Без нее динамическое редактирование блочной карты было бы очень трудным. Код использует стандартные приемы...


- Начало -