30
ЧАСТЬ I Основы программирования в Windows Глава 1 Путешествие в пропасть 29 Глава 2 Модель программирования Windows 61 Глава 3 Профессиональное программирование в Windows 99 Глава 4 GDI, управляющие элементы и прочее 157

ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ЧАСТЬ I

Основыпрограммированияв Windows

Глава 1

Путешествие в пропасть 29Глава 2

Модель программирования Windows 61Глава 3

Профессиональное программирование в Windows 99Глава 4

GDI, управляющие элементы и прочее 157

Page 2: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров
Page 3: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1

Путешествие в пропастьПрограммирование в Windows — это непрекращающаяся война

с длинной историей. Разработчики игр долгое время воздержива-лись от работы под Windows, но их сопротивление оказалось бес-полезным. В этой главе предлагается совершить небольшой экс-курс в Windows и вкратце рассматриваются следующие вопросы.

• История игр• Типы игр• Элементы программирования игр• Используемые для программирования игр инструменты• Простая игра FreakOut

Небольшая историяВсе началось где-то в 1960-х годах, во времена первых мэйн-

фреймов. Мне кажется (но, пожалуйста, не ссылайтесь на моислова), что первой компьютерной игрой была Core Wars (“Войны впамяти”) на машинах под управлением Unix. В 1970-х годах появи-лось множество текстовых и графических (впрочем, это былаочень “сырая” графика) приключенческих (так называемых броди-лок) игр для различных типов мэйнфреймов и мини-компьютеров.

Как ни странно, но большинство игр были сетевыми! Мне ка-жется, что до 90% игр составляли многопользовательские игры ти-па MUD, имитаторы наподобие Star Trek или военные имитаторы.Однако широкие массы не изведали вкуса игр до тех пор, пока непоявилась игра Нолана Башнелла (Nolan Bushnell) Pong, которая иоткрыла эру видеоигр.

Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров. Каждый из них имел свои за и про-тив. Atari 800 был самым мощным (я уверен, что мог бы написатьверсию Wolfenstein для этого компьютера), TRS-80 в наибольшей

Page 4: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

30 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

степени подходил для бизнеса, а Apple был самым“раскрученным”.

Понемногу игры завоевывали рынок программного обеспечения для этих систем, ивсе большее число подростков играли в них ночи напролет. В те дни компьютерныеигры выглядели именно как компьютерные игры, и лишь немногие программисты зна-ли, как они создаются. Книг на эту тему не было вовсе. Все, что было, — это самизда-товские брошюры, содержавшие некоторые части огромной мозаики, да редкие ста-тьи в журнале Byte.

Восьмидесятые годы ознаменовались выходом на сцену 16-битовых компьютеровтипа IBM PC (и совместимых с ним), Mac, Atari ST, Amiga 500 и т.п. Пришло время, ко-гда игры стали выглядеть хорошо. Появились даже первые трехмерные (3D) игры ти-па Wing Commander и Flight Simulator, но PC в то время нельзя было назвать игровымкомпьютером. В 1985 году эту нишу прочно занимали Amiga 500 и Atari ST. Но PC по-степенно набирал популярность благодаря дешевизне и применимости в бизнесе. Вы-вод из всего этого: в конечном счете всегда побеждает компьютер, захвативший ры-нок, независимо от его технологичности или качества.

В начале 90-х годов несомненным лидером на рынке стал IBM PC-совместимыйкомпьютер. С выходом Microsoft Windows 3.1 он окончательно превзошел Apple Mac-intosh, став “компьютером делового человека”. И все же PC отставал от своих конку-рентов в части графики и аудио, что никак не давало играм для него выглядеть так жехорошо, как играм на Amiga.

И вот — да будет свет!..1В конце 1993 года Id Software выпустила продолжение игры Wolfenstein 3D (одна

из первых 3D-игр, также разработанная Id Software) — DOOM. PC стал компьютером,на котором можно не только работать, но и играть, компьютером для работы и длядома. DOOM доказала (если это было все еще кому-то не ясно), что PC можно заста-вить делать все. Это очень важный момент. Запомните его. Нет никакой замены во-ображению и решимости. Если вы верите в то, что нечто возможно, — это так и есть!

После невероятного успеха DOOM Microsoft начала пересмотр своей позиции от-носительно игр и их программирования. Стало очевидно, что индустрия развлеченийогромна и будет только расти, и Microsoft решила занять достойное место в этой ин-дустрии.

Проблема была в том, что даже Windows 95 имела очень слабые видео- и аудио-возможности, так что Microsoft разработала специальное программное обеспечениеWin-G для решения вопросов, связанных с видео. Win-G была заявлена как основнаяподсистема программирования игр и графики. По сути, она представляла собой всеголишь набор графических вызовов для вывода растровых изображений, и примерночерез год Microsoft буквально отрицала ее существование — поверьте, это чистаяправда!

Однако к тому времени уже вовсю шла работа над новой системой, которая долж-на была объединять графику, звук, ввод информации, сетевые возможности и 3D-системы. Так родился продукт DirectX. Как обычно, маркетологи Microsoft немедленнозаявили, что DirectX и есть окончательное решение всех проблем программированияигр на платформе PC и что игры в Windows будут такими же быстрыми (и даже быст-рее), чем игры под DOS32. Но этого не произошло.

1 Автор цитирует строчку из известной эпиграммы: “Был этот мир глубокой тьмой окутан.

Да будет свет! И вот явился Ньютон”. — Прим. перев.

Page 5: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 31

Первые версии DirectX потерпели фиаско, но как программный продукт, а не кактехнология. Microsoft просто недооценила сложность программирования видеоигр. Ноуже с DirectX 3.0 этот продукт начинает работать лучше, чем DOS! Тем не менеебольшинство компаний, разрабатывающих игры, в те годы (1996–1997) продолжалиработать с DOS32 и не спешили переходить к DirectX, пока не вышла версия 5.0 этогопродукта.

Используя технологию DirectX, вы можете создать виртуальную DOS-подобнуюмашину с адресным пространством в 4 Гбайт (или больше) и линейной памятью и про-граммировать так, как вы бы это делали, работая под DOS (если, конечно, это то, чтовам нравится). Но что гораздо важнее, теперь у вас есть возможность немедленноработать с вновь появляющимися технологиями графики и звука благодаря особенно-стям разработки DirectX. Впрочем, об этом мы еще поговорим в нашей книге, а покавернемся к истории.

Первой игрой нового поколения была DOOM, использовавшая программную расте-ризацию. Взгляните на рис. 1.1, где приведена копия экрана игры Rex Blade, клонаDOOM. Следующее поколение 3D-игр, например Quake I, Quake II или Unreal, по сути,стало “квантовым скачком” в технологии. Взгляните на рис. 1.2, где показана копия эк-рана игры Unreal. Эта игра и подобные ей используют программную растеризацию со-вместно с аппаратным ускорением для получения лучшего из этих двух миров. Смеювас заверить, Unreal II или Quake III, работающие на Pentium IV 2.4 GHz с видеокартойGeForce IV TI, выглядят очень привлекательно.

А что же остается нам? Конечно, игры типа Quake и Unreal требуют годы работыбольших коллективов, но я надеюсь, что вы, по крайней мере, сможете принять уча-стие в подобных проектах.

На этом с историческими уроками покончено. Поговорим о более близких вещах.

Рис. 1.1. Rex Blade : первое поколение технологии DOOM

Проектирование игрОдин из самых сложных этапов написания видеоигр — их проектирование. Конеч-

но, трехмерная математика сложна, но не менее важно подумать о привлекательностиигры, ее сложности, используемом языке (включая сленг и жаргоны). Иначе кто оце-нит так тщательно разработанные вами объемные следы плазменных зарядов?

Page 6: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

32 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

Типы игрВ настоящее время существует множество игр, которые можно условно разделить

на несколько типов.DOOM-подобные игры. В большинстве своем это полностью трехмерные игры,

типичными примерами которых являются DOOM, Hexen, Quake, Unreal, Duke Nukem 3Dи Dark Forces. Технологически это наиболее сложные в разработке игры, требующиехорошего знания различных технологий.

Спортивные игры. Могут быть как двухмерными, так и трехмерными, но все чащеи чаще они становятся трехмерными. В любом случае спортивные игры бывают какдля команды, так и для одного человека. Графика в спортивных играх прошла долгийпуть, и хотя она не столь впечатляюща, как в DOOM-подобных играх, от этого она нестановится менее захватывающей. Однако наиболее сильной стороной спортивныхигр является система искусственного интеллекта, который в играх этого класса обыч-но наиболее развит по сравнению с другими играми.

Рис. 1.2. Копия экрана игры Unreal

Боевые игры. Обычно предназначены для одного или двух игроков, и их действиерассматривается со стороны либо при помощи подвижной 3D-камеры. Изображениеможет быть двухмерным, 2.5D (множественные растровые 2D-изображения трех-мерных объектов) или полностью трехмерным. Игры этого типа не так популярны наплатформе PC, вероятно, из-за проблем интерфейса с контроллерами и в связи спредназначением игр для двух игроков.

Лабиринты. Типичные представители этой старой школы игр — Asteroids, PacMan, Jazz Jackrabbit. Обычно это двухмерные игры, хотя в последнее время появи-лись их трехмерные версии; правда, сценарий таких игр тот же, что и у двухмерных.

Механические имитаторы. Это игры, осуществляющие некоторый вид вождения,полета, плавания и подобных действий. В большинстве случаев это трехмерные игры,и таковыми они были всегда (хотя и выглядели до последнего времени существеннохуже, чем сейчас).

Page 7: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 33

Имитаторы экосистем. Это новый класс игр, не имеющих аналогов в реальноммире (если не рассматривать таковым весь мир). В качестве примера можно привестиPopulous, SimCity, SimAnt, Civilization и др. Эти игры позволят вам убедиться, трудноли быть Богом и управлять некой искусственной системой — городом, колонией илицелым миром. Сюда же входят игры — имитаторы экономической системы (например,Gazzillonaire; кстати, очень неплохая игра).

Стратегические или военные игры. Подразделяются на ряд подтипов, перечис-лять которые здесь не имеет смысла. Сюда входят такие игры, как Warcraft, Diablo, Fi-nal Fantasy и т.п. Некоторые из этих игр являются играми реального времени, но приэтом требуют наличия стратегического мышления; другие — типичные представителиигр, в которых действие осуществляется на основе ходов противников.

Интерактивные повести. Обычно эти игры содержат предварительно созданнуюграфику и видео, и вы путешествуете по заранее созданным дорогам и рассматривае-те заранее созданные виды, разгадывая различные головоломки. Обычно такие игрыне дают особой свободы выбора перемещений.

Ретро-игры. Это игры для тех, кто помнит старые добрые времена и предпочитаетигры тех лет. Зачастую это переделки старых игр на новый лад, т.е. игры с тем же со-держанием, но с использованием современных возможностей.

Головоломки и настольные игры. Здесь может быть все, что угодно: двухмер-ность, трехмерность, предварительный рендеринг и т.п. Tetris, Monopoly, Mahjong —вот некоторые из огромного списка игр, входящих в эту категорию.

Мозговой штурмПосле того как вы решите, игру какого типа хотите создать (что обычно просто, так

как все мы знаем, что нам нравится), наступает время глубоких размышлений над бу-дущей игрой. Это тот момент, когда вы остаетесь один на один с самим собой и датьвам совет просто некому. К сожалению, не существует способа постоянной генерацииидей хороших игр.

Вы должны придумать игру, которая понравится не только вам, но и другим людями которую можно реально создать. Конечно, вполне можно использовать в качестветочки отсчета другие игры, но избегайте точного копирования чужого продукта. Почи-тайте научную фантастику и игровые журналы, выясните, какие игры имеют наиболеевысокий уровень продаж. Посмотрите различные фантастические кинофильмы —возможно, кроме идей по поводу игры вы сможете почерпнуть и идеи по поводу кра-сивых визуальных эффектов.

Лично я обычно сижу с друзьями (или даже один) и выдаю множество идей, кото-рые представляются мне привлекательными. Затем я развиваю эти идеи до тех пор,пока они не становятся достаточно правдоподобными или пока не доходят до абсурдаи не разваливаются на глазах. Порой очень обидно быть переполненным идеями ичерез пару часов оказаться с пустыми руками. Не отчаивайтесь — так и должно быть.Если идея, пережив ночь, на следующее утро все еще кажется вам привлекатель-ной — у нее есть шансы быть воплощенной в жизнь.

Page 8: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

34 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

Читайте внимательно, так как я хочу сказать нечто важное. Не откусывайте больше,чем сможете пережевать! Я получаю тысячи писем от новичков, которые в качествесвоей первой игры твердо намерены создать игру уровня DOOM или Quake. Этогопросто не может произойти. Вы должны быть счастливы, если вам удастся создатьклон Asteroids за три-шесть месяцев работы, так что старайтесь не переоценить себяи ставьте перед собой реальные цели. Думайте о том, что в состоянии сделать личновы, поскольку в конце работы, скорее всего, вы останетесь в одиночестве — все ва-ши помощники просто улизнут от нее. Кроме того, идея вашей первой игры должна

быть простой.

Теперь перейдем к более детальному рассмотрению вопросов.

Разработка документации и сценарияПосле того как у вас появилась идея, вы должны изложить ее на бумаге. Сейчас,

когда я занимаюсь большими игровыми продуктами, я просто вынужден создавать на-стоящую проектную документацию, но для небольших игр сойдет и несколько страницдетального описания. В основном документация представляет собой карту или набро-сок игры. В ней должно быть перечислено как можно больше детальной информацииоб игре, ее уровнях, правилах и т.д. Тогда вы точно знаете, чего хотите, и можете сле-довать изложенному на бумаге плану. В противном случае детали будут все время из-меняться, и в конечном счете ваша игра окажется непоследовательной и бессвязной.

Обычно для начала я записываю небольшую историю: примерно одну-две страни-цы описания, о чем же эта игра, кто ее основной персонаж, в чем состоит ее идея. И,наконец, как выиграть в этой игре. Затем я принимаю решение об уровнях игры и ееправилах и переношу их на бумагу как можно более детально. После того как это сде-лано, я могу добавлять или удалять из этого описания те или иные детали, но у менявсе равно остается рабочий план. Даже если я придумаю сто новых идей, я не забудуо них и смогу всегда добавить их в игру.

Не пренебрегайте набросками — они здорово помогут вам в работе. На рис. 1.3показан пример простейших набросков сценария игры. Как видите, ничего сложного:просто смотри на рисунки и работай над ними.

Сцена 3: Уровень 1Астероидное поле

. . .

.

Сцена 2: Главное меню•Игрок выбирает корабль

Сцена 1: Введение•Показ города•Начало монолога

Raptor

TalonStrife

Выбор корабля

Все корабливращаются

Подсветка

Подсветка

Каркаснаясхема

Система двойной звезды

Вид из“BladeRunner”

Рис. 1.3. Наброски сценария игры

Жизнеспособность игрыПоследняя часть разработки игры — проверка ее жизнеспособности. Вы в самом

деле уверены, что ваша игра понравится людям? Не лжете ли вы самому себе? Этовесьма серьезный вопрос. Имеется около 10 000 различных игр и около 9 900 компа-

ВНИМАНИЕ

Page 9: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 35

ний, занимающихся ими, — о такой конкуренции стоит задуматься заранее. Думайте нео том, нравится ли эта игра вам, а о том, как заставить ее понравиться другим.

Ничто, кроме глубоких раздумий и усиленного бета-тестирования игры, не сможет вданном случае вам помочь. Подумайте о привлекательных деталях, на которые обыч-но ловится много игроков, — вплоть до отделки кабины пилота мореным дубом.

Компоненты игрыТеперь пришло время узнать, чем же видеоигра отличается от программ других ти-

пов. Видеоигры — исключительно сложная разновидность программного обеспеченияи, вне всякого сомнения, наиболее трудная для написания. Конечно, написатьMS Word сложнее, чем Asteroids, но я пока не встречал программы, которая была бысложнее Unreal.

Это означает, что вы должны изучить новый способ программирования, в большейстепени подходящий для приложений реального времени и имитаторов, чем построч-ная, управляемая событиями или последовательная логика программ, над которымивы работали ранее. Видеоигра представляет собой в основном непрерывный цикл,который осуществляет работу логики программы и вывод на экран, обычно со скоро-стью 30 кадров в секунду (frames per second, fps) или выше. Скорость вывода близкак скорости показа кинофильма, с той разницей, что в данном случае кинофильм соз-дается по мере его показа.

Взглянем на упрощенный цикл игры, показанный на рис. 1.4. Далее описаны все егочасти.

ИнициализацияВ этой части вы выполняете стандартные операции, обычные для любой програм-

мы, такие, как распределение памяти, захват ресурсов, загрузка данных с диска и т.п.

Вход в цикл игрыВ этой части выполнение кода входит в основной цикл игры. Здесь начинается

собственно действие игры, которое продолжается до тех пор, пока пользователь невыйдет из основного цикла.

Page 10: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

36 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

Инициализация•Распределение памяти•Загрузка файлов•Построение таблиц•

Главный цикл событийВызов служб WindowsИнициализация таймера

Подготовкаочередного кадрав буфере памяти

Логика игры•ИИ игры•Обнаружение столкновений•Физическая модель

Получение пользова-тельского ввода

Завершение работы•Освобождение памяти•Закрытие файлов

Выход в систему

Обработкасобытий Windows

Копированиеизображенияна экран

Буфер памятикадров

Ожидание

Синхронизациявремени длявывода 30 fps

Цикл

Клавиатура

Джойстик

Выход?

Мышь

Рис. 1.4. Обобщенная архитектура цикла и гры

Получение пользовательского вводаВ этой части ввод пользователя обрабатывается и/или буферизуется для после-

дующего использования системой искусственного интеллекта (ИИ) и логики игры.

ИИ и логика игрыЭта часть содержит основной код игры. Именно здесь выполняется работа искус-

ственного интеллекта, логики игры и физической модели, результаты которой исполь-зуются для вывода на экран очередного кадра.

Подготовка очередного кадраВ этой части результаты ввода пользователя и работы искусственного интеллекта,

логики игры и физической модели используются для подготовки очередного кадраанимации игры. Обычно это изображение подготавливается в отдельном буфере па-мяти, не связанном с экраном, так что процесс подготовки пользователю не виден. За-тем подготовленное изображение быстро выводится на экран.

Синхронизация выводаСкорость работы компьютера зависит от уровня сложности игры. Например, если

на экране происходит действие, включающее 1000 объектов, процессор явно будет

Page 11: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 37

загружен существенно сильнее, чем при наличии всего 10 объектов. Соответственноварьируется частота вывода кадров, что недопустимо. Следовательно, требуется не-кий механизм синхронизации, обеспечивающий постоянную частоту кадров (обычно 30fps считается оптимальной скоростью вывода).

ЦиклЭта часть кода предельно проста — она обеспечивает возврат к началу цикла и

выполнение очередного прохода.

Завершение работыЭта часть кода означает завершение работы игры и возврат в операционную сис-

тему. Однако до возврата вы должны освободить все захваченные ресурсы, как и привозврате из любой другой программы.

Конечно, приведенная схема несколько упрощена, но указывает все существенныечасти игры. В большинстве случаев игра представляет собой конечный автомат,имеющий ряд состояний. В листинге 1.1 цикл показан более детально, примерно так,как он мог бы выглядеть в реальной игре.

Листинг 1.1. Простой цикл событий игры

// Определения состояний цикла игры#define GAME_INIT // Инициализация игры#define GAME_MENU // Игра в режиме меню#define GAME_STARTING // Игра начинает работу#define GAME_RUN // Игра работает#define GAME_RESTART // Перезапуск игры#define GAME_EXIT // Выход из игры

// Глобальные переменные игрыint game_state = GAME_INIT; // Начальное состояние игрыint error = 0; // Возврат ошибки ОС

void main(){// Реализация основного цикла игры

while( game_state != GAME_EXIT ) { // Какое текущее состояние игры? switch( game_state ) { case GAME_INIT: // Инициализация игры { // Распределение памяти // и захват ресурсов Init();

// переход в состояние меню game_state = GAME_MENU; } break;

Page 12: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

38 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

case GAME_MENU: // Игра в режиме меню { // Вызов функции меню // и переключение состояния game_state = Menu(); } break;

case GAME_STARTING: // Игра начинает работу { // Это необязаьельное состояние, которое // обычно используется для // дополнительной работы с захваченными // ресурсами Switch_For_Run();

// Переход в состояние работы game_state = GAME_RUN; } break;

case GAME_RUN: // Игра работает { // Эта часть содержит логику игры

// Очистка экрана Clear();

// Получение ввода Get_Input();

// Работа логики и ИИ Do_Logic();

// Вывод очередного кадра Render_Frame();

// Синхронизация Wait();

// Единственный способ изменения этого // состояния - через взаимодействие с // пользователем (либо, возможно, // вследствие проигрыша) } break;

case GAME_EXIT: // Выход из игры { // Раз мы здесь, работа программы // успешно завершается и мы должны // освободить ресурсы и выполнить // остальную работу этого типа Release_And_Cleanup();

// Раз мы здесь, ошибок не было error = 0;

Page 13: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 39

// Здесь переключение состояний не // требуется, так как все равно // осуществляется выход из программы } break;

default: break; } // switch } // while

// Возврат кода ошибки операционной системе return( error );} // main

Хотя листинг 1.1 и нефункционален, я думаю, что основную идею вы уловили. Всециклы игр в той или иной степени следуют приведенной схеме. Взгляните также нарис. 1.5, где приведена диаграмма переходов конечного автомата игры. Как видите,все более-менее просто.

Позже в этой главе при рассмотрении демонстрационной игры FreakOut мы ещепоговорим о циклах и конечных автоматах.

Общие рекомендациипо программированию игр

Теперь я хочу поговорить о некоторых общих принципах и методах программиро-вания, о которых не стоит забывать и которым необходимо по возможности следо-вать для того, чтобы программирование игр стало более простой задачей.

Начнем с того, что видеоигры представляют собой программы с исключительновысокой производительностью. В наиболее критических по времени работы или тре-бованиям к памяти частях кода больше нельзя использовать API высокого уровня.Все, что связано с внутренним циклом вашей игры, должно быть написано вами само-стоятельно, иначе неизбежны проблемы с производительностью игры. Это, понятно,не означает, что вы не должны использовать API DirectX, поскольку DirectX разраба-тывался с учетом требования максимальной производительности. Но, вообще говоря,избегайте вызовов функций высокого уровня.

Page 14: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

40 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

GAME_RESTARTGAME_STARTING

GAME_INIT

GAME_RUN

GAME_EXIT

GAME_MENU

Рис. 1.5. Диаграмма переходов в цикле игры

Помня об этом, рассмотрим ряд приемов, которые не стоит забывать при работенад играми.

Не бойтесь использовать глобальные переменные. Многие видеоигры не используютпередачу параметров в критических ко времени выполнения функциях, вместо этогоприменяя глобальные переменные. Рассмотрим, например, следующую функцию:

void Plot(int x, int y, int color){ // Вывод точки на экран video_buffer[x + y*MEMORY_PITCH] = color;} // PlotВ данном случае тело функции выполняется гораздо быстрее, чем ее вызов, вслед-ствие необходимости внесения параметров в стек и снятия их оттуда. В такой ситуа-ции более эффективным может оказаться создание соответствующих глобальных пе-ременных и передача информации в функцию путем присвоения им соответствую-щих значений.

int gx, gy, gcolor; // Глобальные переменные

void Plot_G(void){ // Вывод точки на экран video_buffer[gx + gy*MEMORY_PITCH] = gcolor;} // Plot_G

СЕКРЕТ

Page 15: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 41

Используйте встроенные функции. Предыдущий фрагмент можно еще больше улуч-шить с помощью директивы inline, которая полностью устраняет код вызова функции,указывая компилятору на необходимость размещения кода функции непосредствен-но в месте ее вызова. Конечно, это несколько увеличивает программу, но скоростьдля нас гораздо важнее2.

inline void Plot_I(int x, int y, int color){ // Вывод точки на экран video_buffer[x + y*MEMORY_PITCH] = color;} // Plot_IЗаметим, что здесь не используются глобальные переменные, поскольку компиляторсам заботится о том, чтобы для передачи параметров не использовался стек. Тем неменее глобальные переменные могут пригодиться, если между вызовами изменяет-ся только один или два параметра, поскольку при этом не придется заново загру-жать старые значения.

Всегда используйте 32-битовые переменные вместо 8- или 16-битовых. Pentium и бо-лее поздние процессоры — 32-битовые, а это означает, что они хуже работают сословами данных размером 8 и 16 бит и их использование может замедлить работу всвязи с эффектами кэширования и другими эффектами, связанными с адресациейпамяти. Например, вы можете создать структуру, которая выглядит примерно сле-дующим образом:

struct CPOINT{ short x, y; unsigned char c;} // CPOINTХотя использование такой структуры может показаться стоящей идеей, на самом де-ле это вовсе не так! Эта структура имеет размер 5 байт: (2*sizeof(short)+sizeof(unsigned char)) = 5. Это не очень хорошо в силу особенностей адресации памятиу 32-битовых процессоров. Гораздо лучше использовать следующую структуру:

struct CPOINT{ int x, y; int c;} // CPOINTТакая структура гораздо лучше. Все ее элементы имеют одинаковый размер —4 байта, а следовательно, все они выровнены в памяти на границу DWORD. Несмот-ря на выросший размер данной структуры, работа с ней осуществляется эффектив-нее, чем с предыдущей.

В действительности вы можете доводить размер всех своих структур до величины,кратной 32 байтам, поскольку это оптимальный размер для стандартного кэша про-цессоров класса Pentium. Довести размер до этого значения можно путем добавле-ния дополнительных искусственных членов структур либо посредством соответст-вующих директив компилятора. Конечно же, такой рост размера структур приведет к

перерасходу памяти, но он может оказаться оправданным увеличением скорости работы.

2 Теоретически возможна ситуация, когда из-за использования встроенных функций внутрен-

ний цикл может вырасти и перестать полностью помещаться в кэше процессора, что приведет к

СЕКРЕТ

СЕКРЕТ

Page 16: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

42 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

struct в C++ представляет собой аналог class, у которого все члены по умолчанию от-крыты (public).

Тщательно комментируйте ваш код. Программисты, работающие над играми, поль-зуются дурной славой в связи с тем, что не комментируют свой код. Не повторяйте ихошибку. Ясный, хорошо комментированный код стоит лишней работы с клавиатурой.

Программируйте в стиле RISC. Другими словами, делайте ваш код как можно болеепростым. В частности, в силу особенностей архитектуры процессоры класса Pentiumпредпочитают простые инструкции сложным, да и компилятору работать с ними иоптимизировать их легче. Например, вместо кода

if ( (x += (2*buffer[index++])) > 10 ){ // Выполняем некоторые действия} // ifиспользуйте код попроще:

x += 2*buffer[index];index++;

if (x > 10){ // Выполняем некоторые действия} // ifТому есть две причины. Во-первых, такой стиль позволяет при отладке вставлять до-полнительные точки останова между разными частями кода. Во-вторых, такой подходоблегчает работу компилятора по оптимизации этого кода.

Вместо умножения целых чисел на степень двойки используйте побитовый сдвиг.Поскольку данные в компьютере хранятся в двоичном виде, сдвиг влево или вправоэквивалентен соответственно умножению или делению, например:

int y_pos = 10;

// Умножаем y_pos на 64y_pos = (y_pos << 6); // 2^6 = 64

// Делим y_pos на 8y_pos = (y_pos >> 3); // Ѕ^3 = 1/8Вы еще встретитесь с подобными советами в главе, посвященной оптимизации.

Используйте эффективные алгоритмы. Никакой ассемблерный код не сделает алго-

ритм ( )2O n более быстрым. Лучше использовать более эффективные алгоритмы,

чем пытаться оптимизировать никуда не годные.

снижению производительности по сравнению с использованием обычных функций. Злоупотреб-лять встроенными функциями не следует, и не только по этой причине. — Прим. ред.

C++

СЕКРЕТ

СЕКРЕТ

СЕКРЕТ

СЕКРЕТ

Page 17: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 43

Не оптимизируйте ваш код в процессе программирования. Обычно это просто пус-тая трата времени. Перед тем как приступать к оптимизации, завершите написаниеесли не всей игры, то по крайней мере основной ее части. Тем самым вы сохранитесилы и сэкономите время. Только когда игра готова, наступает время для ее профи-лирования и поиска проблемных участков кода, которые следует оптимизировать.

Не используйте слишком сложные структуры данных для простых объектов. Не стоитиспользовать связанные списки для представления массива, количество элементовкоторого точно известно заранее, только в силу того, что такие списки — это очень“круто”. Программирование видеоигр на 90% состоит из работы с данными. Хранитеих в как можно более простом виде с тем, чтобы обеспечить как можно более быст-рый и простой доступ к ним. Убедитесь, что используемые вами структуры данныхнаиболее подходят для решения ваших задач.

Разумно используйте C++. Не пытайтесь применять множественное наследованиетолько потому, что вы знаете, как это делается. Используйте только те возможности,которые реально необходимы и результаты применения которых вы хорошо себепредставляете.

Если вы видите, что зашли в тупик, остановитесь и без сожалений вернитесь назад.Лучше потерять 500 строк кода, чем получить совершенно неработоспособный про-ект.

Регулярно делайте резервные копии вашей работы. При работе с игровой програм-мой достаточно легко восстановить какую-нибудь простую сортировку, но восстано-вить систему ИИ — дело совсем другое.

Перед тем как приступить к созданию игры, четко организуйте свою работу. Исполь-зуйте понятные и имеющие смысл имена файлов и каталогов, выберите и придержи-вайтесь последовательной системы именования переменных, постарайтесь разде-лить графические и звуковые данные по разным кат алогам.

Использование инструментовВ прошлом создание игр не требовало иного инструментария, кроме простого тек-

стового редактора и, возможно, простого самодельного графического редактора. Носегодня создание игр — задача более сложная. Как минимум, вам нужен компиляторC/C++, графический редактор и программа для обработки звука. Кроме того, вам мо-жет потребоваться программа для моделирования трехмерных объектов, а также про-грамма для работы с музыкой, если вы используете в своей игре возможности MIDI.

Компиляторы C/C++Для разработки программного обеспечения для Windows 95/NT наилучший компи-

лятор — MS VC++ 6.0+. Он может выполнить все, что вам потребуется, и даже боль-ше. Генерируемые им EXE-файлы содержат наиболее быстрый код. Компилятор Bor-land также неплох (и существенно дешевле), но его возможности гораздо ниже. В лю-бом случае полные версии ни того и ни другого вам не нужны. Студенческой версии,способной создавать EXE-файлы Win32, более чем достаточно.

СЕКРЕТ

СЕКРЕТ

СЕКРЕТ

СЕКРЕТ

СЕКРЕТ

СЕКРЕТ

Page 18: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

44 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

Программное обеспечение для двухмерной графикиПри работе над играми вам нужны программы для рисования, черчения и обработ-

ки изображений. Программы для рисования позволяют пиксель за пикселем создаватьизображение из графических примитивов и управлять им. С точки зрения отношенияцена/производительность лидером мне представляется Paint Shop Pro. Неплох ProCreatePainter, но он предназначен для художников-профессионалов, не говоря уже о его це-не. Я лично предпочитаю Corel Photo-Paint, но его возможности определенно вышетребований новичков.

Программы для черчения также позволяют создавать изображения, но из кривых,линий и двухмерных геометрических примитивов. Эти программы не так необходимы,но если вам потребуется программа такого типа, рекомендую воспользоваться AdobeIllustrator.

Последними в списке программ для работы с двухмерным изображением упоми-наются программы для обработки изображений, среди которых я назвал бы AdobePhotoshop и Corel Photo-Paint. Хотя лично мне больше нравится последняя, выбор завами.

Программное обеспечение для обработки звукаДевяносто процентов звуковых эффектов (SFX), используемых сегодня в играх,

представляют собой цифровые образцы звука. Для работы с ними вам потребуетсяпрограмма обработки звука. Наилучшая программа для этого — Sound Forge Xp. Приналичии множества возможностей по обработке звука эта программа остается оченьпростой в использовании.

Моделирование трехмерных объектовОбычно такого рода программное обеспечение стоит слишком дорого, но в по-

следнее время мне попались несколько относительно недорогих программ модели-рования трехмерных объектов, достаточно мощных, чтобы создавать видеоклипы.Лично я пользуюсь Caligari TrueSpace, которая стоит всего лишь несколько сотен дол-ларов.

Если вы хотите большей мощности и натурализма — обратитесь к 3D Studio Max,которая, правда, стоит около $2500. Однако мы в основном будем использовать дан-ное программное обеспечение для создания трехмерных каркасов, а не реалистичныхизображений, так что Caligari TrueSpace будет вполне достаточно.

Музыкальные и MIDI-программыНа сегодня в играх используются два вида музыки: чисто цифровая (типа CD) и

MIDI (musical instrument digital interface — цифровой интерфейс музыкальных инстру-ментов), представляющая собой синтезированный на основе нотного представлениязвук. Для работы с MIDI вам требуется соответствующее программное обеспечение, издесь я бы посоветовал воспользоваться программой Cakewalk. Более подробно оMIDI речь идет в главе 10, “DirectSound и DirectMusic”.

Page 19: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 45

Использование компилятораЗачастую в изучении программирования игр для Windows крайне сложно научиться

правильно пользоваться компилятором. Очень часто вы бодро запускаете среду про-граммирования, запускаете компиляцию, и ваш экран переполняется сообщениями обошибках. Чтобы помочь вам, рассмотрим некоторые основные концепции.

1. Пожалуйста, прочитайте документацию к компилятору, ну пожалуйста, пожалуй-ста! Я вас очень прошу!

2. Вы должны установить на машине DirectX SDK. Для этого требуется лишь пе-рейти в каталог DirectX на компакт-диске, прочитать файл README.TXT и вы-полнить все, что там сказано (а именно запустить программу INSTALL.EXE).

3. Мы будем создавать EXE-программы Win32, а не DLL, компоненты ActiveX ит.п. Поэтому первое, что вам нужно, — создать новый проект и установить типсоздаваемого файла Win32 Application. Этот шаг при работе с компиляторомVC++ 6.0 показан на рис. 1.6.

4. Добавьте в проект исходные файлы при помощи пункта Add Files из главногоменю. Это действие показано на рис. 1.7.

5. Приступив к работе с DirectX, мы должны включить в проект большинство из пе-речисленных далее и представленных на рис. 1.8 библиотек COM интерфейсовDirectX.

• DDRAW.LIB • DSOUND.LIB • DINPUT.LIB • DINPUT8.LIB • DSETUP.LIB

Если вы не используете DirectSetup, библиотека DSETUP.LIB вам не потребуется.

Эти библиотечные файлы DirectX после установки DirectX SDK находятся в ка-талоге LIB. Вы должны явно добавить эти файлы в ваш проект; добавления путик файлам недостаточно, так как компилятор при этом будет, скорее всего, нахо-дить старые файлы от DirectX 3.0 из поставки компилятора. Кроме того, вамследует добавить в проект библиотеку расширений Windows мультимедиаWINMM.LIB, которая находится в каталоге LIB вашего компилятора.

6. Вы готовы к компиляции программы.

Если вы используете Borland, то в поставке DirectX SDK для вас предназначен специ-альный каталог с этим именем, и добавлять в свой проект библиотечные файлы выдолжны именно из этого каталога.

Если после прочтения этого раздела у вас остались вопросы — ничего страшного.Мы еще вернемся к вопросам использования компилятора при рассмотрении про-граммирования в Windows и изучении DirectX.

НА ЗАМЕТКУ

ВНИМАНИЕ

Page 20: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

46 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

Рис. 1.6. Создание Win32 EXE-файла в Vis-ual C++ 6.0

Рис. 1.7. Добавление файлов в проект Visual C++ 6.0

Пример: игра FreakOutПока мы еще окончательно не свихнулись со всеми этими отвлеченными разгово-

рами о Windows, DirectX и 3D-графике, давайте сделаем остановку и рассмотрим пол-ностью готовую игру — конечно, простенькую, но несомненно игру. Здесь вы увидитецикл игры, некоторые графические вызовы и то, как компилируется игра.

Page 21: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 47

DDraw.Lib

Компоновщик

Компилятор

Файлы ресурсов

Заголовочные .h-файлы

Файлы игры

Исходные .cpp-файлы с кодом C++

Game.EXE

Выполнение программы

DSound.Lib

Dinput.Lib

Dinput8.Lib

DSetup.Lib

Стандартныебиблиотеки Win32

Динамическиебиблиотеки DirectX

•••

Библиотекиимпорта DirectX,необходимыедля разрешенияссылок прикомпоновке

Рис. 1.8. Ресурсы, необходимые для создания приложения Win32 DirectX

Проблема только в том, что мы все еще находимся в главе 1, а в игре используют-ся материалы из последующих глав. Давайте договоримся так: в игре мы просто ис-пользуем API черного ящика. Исходя из этой посылки, я задамся вопросом: “Каковабсолютный минимум требований при создании двухмерной игры типа Breakout?” Все,что нам действительно нужно, — это следующая функциональность:

• переход в произвольный графический режим;• вывод цветных прямоугольников на экран;• получение клавиатурного ввода;• синхронизация цикла игры с использованием некоторых функций работы с тай-

мером;• вывод цветной строки текста на экран.В связи с этим я создал библиотеку BLACKBOX.CPP|H, которая содержит набор

функций DirectX (точнее, только функций DirectDraw) вместе с кодом, реализующимтребующуюся нам функциональность. Поэтому пока что вам не нужно разбираться стем, как именно работают эти функции, прототипы которых имеются в файлеBLACKBOX.H; вы должны просто использовать их и не забыть добавить в проектфайлы BLACKBOX.CPP|H.

Используя библиотеку BLACKBOX, я написал игру FreakOut, которая демонстриру-ет ряд концепций, обсуждаемых в этой главе. Во FreakOut имеются все основныекомпоненты реальных игр, включая цикл игры, подсчет очков, систему уровней и дажефизическую модель мяча (впрочем, чрезвычайно примитивную). На рис. 1.9 показанакопия экрана игры. Конечно, это не Arkanoid, но для четырех часов работы, согласи-тесь, это не так уж и плохо.

Прежде чем перейти к исходному тексту игры, взгляните на проект игры и различ-ные его компоненты (рис. 1.10).

Как видно из рисунка, игра состоит из следующих файлов.FREAKOUT.C Основная логика игры, использующая BLACKBOX.CPP и создаю-

Page 22: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

48 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

PP щая минимальное приложение Win32BLACKBOX.CPP

Библиотека игры (пока мы ее не рассматриваем)

BLACKBOX.H Заголовочный файл библиотеки BLACKBOXDDRAW.LIB Библиотека импорта DirectDraw, необходимая для компоновки при-

ложения. Эта библиотека не содержит реальный код DirectX, апредставляет собой необходимого для компоновки программы по-средника, который загружает динамическую библиотекуDDRAW.DLL, выполняющую всю необходимую работу

DDRAW.DLL Динамическая библиотека DirectDraw, содержащая COM-реализацию функций интерфейса DirectDraw, вызываемых с уча-стием библиотеки импорта DDRAW.LIB. Вам не нужно самим бес-покоиться о загрузке этой библиотеки и подобных вещах — простоубедитесь, что в системе установлены файлы времени исполненияDirectX

Рис. 1.9. Экран игры FreakOut

Компоновщик

Работа программыDDRAW.DLL

Загружается во время работы

FREAKOUT.EXE

Компилятор

Исходный файл игрыFREAKOUT.CPP

Библиотека DirectXDDRAW.LIB

Набор графическихфункцийBLACKBOX.CPPBLACKBOX.H

Рис. 1.10. Структура FreakOut

Page 23: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 49

Таким образом, для компиляции необходимо включить в проект исходные файлыBLACKBOX.CPP и FREAKOUT.CPP, скомпоновать его с библиотекой DDRAW.LIB ине забыть убедиться, что BLACKBOX.H находится в рабочем каталоге, чтобы компи-лятор мог найти его.

Теперь взглянем на файл BLACKBOX.H и выясним, прототипы каких функций в немимеются (листинг 1.2).

Листинг 1.2. Заголовочный файл BLACKBOX.H

// BLACKBOX.H

// Предотвращение многократного включения#ifndef BLACKBOX#define BLACKBOX

// ОПРЕДЕЛЕНИЯ ////////////////////////////////////////////

// Размер экрана по умолчанию#define SCREEN_WIDTH 640#define SCREEN_HEIGHT 480#define SCREEN_BPP 8 // бит на пиксель#define MAX_COLORS 256 // Максимальное количество цветов

// MACROS /////////////////////////////////////////////////

// Асинхронное чтение клавиатуры#define KEY_DOWN(vk_code) \ ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)#define KEY_UP(vk_code) \ ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

// Инициализация структур DirectDraw#define DD_INIT_STRUCT(ddstruct) \ { memset(&ddstruct,0,sizeof(ddstruct)); \ ddstruct.dwSize=sizeof(ddstruct); }

// Типы ///////////////////////////////////////////////////

// Основные беззнаковые типыtypedef unsigned short USHORT;typedef unsigned short WORD;typedef unsigned char UCHAR;typedef unsigned char BYTE;

// Внешние объекты ////////////////////////////////////////

extern LPDIRECTDRAW7 lpdd;extern LPDIRECTDRAWSURFACE7 lpddsprimary;extern LPDIRECTDRAWSURFACE7 lpddsback;extern LPDIRECTDRAWPALETTE lpddpal;extern LPDIRECTDRAWCLIPPER lpddclipper;

Page 24: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

50 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

extern PALETTEENTRY palette[256];extern PALETTEENTRY save_palette[256];extern DDSURFACEDESC2 ddsd;extern DDBLTFX ddbltfx;extern DDSCAPS2 ddscaps;extern HRESULT ddrval;extern DWORD start_clock_count;

// Прямоугольник обрезкиextern int min_clip_x, max_clip_x, min_clip_y, max_clip_y;

// Изменяются при вызове DD_Init()extern int screen_width, // Ширина экрана screen_height, // Высота экрана screen_bpp; // Бит на пиксель

// Прототипы //////////////////////////////////////////////

// Функции DirectDrawint DD_Init(int width, int height, int bpp);int DD_Shutdown(void);LPDIRECTDRAWCLIPPER DD_Attach_Clipper( LPDIRECTDRAWSURFACE7 lpdds, int num_rects, LPRECT clip_list);int DD_Flip(void);int DD_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);

// Функции работы со временемDWORD Start_Clock(void);DWORD Get_Clock(void);DWORD Wait_Clock(DWORD count);

// Графические функцииint Draw_Rectangle(int x1, int y1, int x2, int y2, int color,LPDIRECTDRAWSURFACE7lpdds=lpddsback);

// Функции gdiint Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE7 lpdds=lpddsback);int Draw_Text_GDI(char *text, int x,int y,int color, LPDIRECTDRAWSURFACE7 lpdds=lpddsback);

#endif

Пока что не напрягайте излишне свои мозги, пытаясь разобраться со всем этим ко-дом и глобальными переменными. Просто посмотрите на объявленные в заголовоч-ном файле функции. Как видите, они обеспечивают всю необходимую функциональ-

Page 25: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 51

ность для нашего простого графического интерфейса. Теперь с помощью этих функ-ций я создаю игру FREAKOUT.CPP, приведенную в листинге 1.3. Рассмотрите приве-денный код, в особенности основной цикл игры и вызовы функций.

Листинг 1.3. Исходный файл FREAKOUT.CPP

// FREAKOUT.CPP - демонстрационная игра

// Включаемые файлы ///////////////////////////////////////

#define WIN32_LEAN_AND_MEAN // Включение всех макросов#define INITGUID // Включение графического // интерфейса пользователя

#include <windows.h> // Включение элементов Windows#include <windowsx.h>#include <mmsystem.h>

#include <iostream.h> // Включение функций C/C++#include <conio.h>#include <stdlib.h>#include <malloc.h>#include <memory.h>#include <string.h>#include <stdarg.h>#include <stdio.h>#include <math.h>#include <io.h>#include <fcntl.h>

#include <ddraw.h> // Включение DirectX#include "blackbox.h" // Включение библиотеки

// Определения ////////////////////////////////////////////

// Определения окна игры#define WINDOW_CLASS_NAME "WIN3DCLASS" // Имя класса

#define WINDOW_WIDTH 640 // Размер окна#define WINDOW_HEIGHT 480

// Состояния цикла игры#define GAME_STATE_INIT 0#define GAME_STATE_START_LEVEL 1#define GAME_STATE_RUN 2#define GAME_STATE_SHUTDOWN 3#define GAME_STATE_EXIT 4

// Определения блоков#define NUM_BLOCK_ROWS 6#define NUM_BLOCK_COLUMNS 8

Page 26: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

52 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

#define BLOCK_WIDTH 64#define BLOCK_HEIGHT 16#define BLOCK_ORIGIN_X 8#define BLOCK_ORIGIN_Y 8#define BLOCK_X_GAP 80#define BLOCK_Y_GAP 32

// Определения ракетки#define PADDLE_START_X (SCREEN_WIDTH/2 - 16)#define PADDLE_START_Y (SCREEN_HEIGHT - 32);#define PADDLE_WIDTH 32#define PADDLE_HEIGHT 8#define PADDLE_COLOR 191

// Определения мяча#define BALL_START_Y (SCREEN_HEIGHT/2)#define BALL_SIZE 4

// Прототипы //////////////////////////////////////////////

// Консоль игрыint Game_Init(void *parms=NULL);int Game_Shutdown(void *parms=NULL);int Game_Main(void *parms=NULL);

// Глобальные переменные //////////////////////////////////

HWND main_window_handle = NULL; // Дескриптор окнаHINSTANCE main_instance = NULL; // Экземплярint game_state = GAME_STATE_INIT; // Начальное состояние

int paddle_x = 0, paddle_y = 0; // Позиция ракеткиint ball_x = 0, ball_y = 0; // Позиция мячаint ball_dx = 0, ball_dy = 0; // Скорость мячаint score = 0; // Счетint level = 1; // Текущий уровеньint blocks_hit = 0; // Количество выбитых блоков

// Сетка игры

UCHAR blocks[NUM_BLOCK_ROWS][NUM_BLOCK_COLUMNS];

// Функции ////////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam){

Page 27: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 53

// Главный обработчик сообщений в системеPAINTSTRUCT ps; // Используется в WM_PAINTHDC hdc; // Дескриптор контекста устройства

// Какое сообщение полученоswitch(msg) { case WM_CREATE: { // Инициализация return(0); } break;

case WM_PAINT: { // Рисование hdc = BeginPaint(hwnd,&ps);

// Теперь окно действительно

// Конец рисования EndPaint(hwnd,&ps); return(0); } break;

case WM_DESTROY: { // Уничтожение приложения PostQuitMessage(0); return(0); } break;

default:break;

} // switch

// Обработка по умолчанию остальных сообщенийreturn (DefWindowProc(hwnd, msg, wparam, lparam));

} // WinProc

// WINMAIN ////////////////////////////////////////////////

int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow){

WNDCLASS winclass; // Класс, создаваемый намиHWND hwnd; // Дескриптор окна

Page 28: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

54 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

MSG msg; // СообщениеHDC hdc; // Контекст устройстваPAINTSTRUCT ps;

// Создание структуры класса окнаwinclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;winclass.lpfnWndProc = WindowProc;winclass.cbClsExtra = 0;winclass.cbWndExtra = 0;winclass.hInstance = hinstance;winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);winclass.hCursor = LoadCursor(NULL, IDC_ARROW);winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);winclass.lpszMenuName = NULL;winclass.lpszClassName = WINDOW_CLASS_NAME;

// Регистрация класса окнаif (!RegisterClass(&winclass)) return(0);

// Создание окна (обратите внимание// на использование WS_POPUP)if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // Класс "WIN3D Game Console", // Заголовок WS_POPUP | WS_VISIBLE, 0,0, // Координаты GetSystemMetrics(SM_CXSCREEN), // ширина GetSystemMetrics(SM_CYSCREEN), // высота NULL, // Дескриптор родителя NULL, // Дескриптор меню hinstance, // Экземпляр NULL))) // Параметры созданияreturn(0);

// Сокрытие мышиShowCursor(FALSE);

// Сохранение дескриптора окна и экземпляраmain_window_handle = hwnd;main_instance = hinstance;

// Инициализация консоли игрыGame_Init();

// Главный цикл игрыwhile(1) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { // Проверка на выход

Page 29: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

ГЛАВА 1. ПУТЕШЕСТВИЕ В ПРОПАСТЬ 55

if (msg.message == WM_QUIT) break;

// Трансляция клавиш TranslateMessage(&msg);

// Пересылка сообщения процедуре окна DispatchMessage(&msg); } // if

// Основная процедура игры Game_Main();

} // while

// Завершение игры и освобождение ресурсовGame_Shutdown();

// Возврат мышиShowCursor(TRUE);

// Выход в Windowsreturn(msg.wParam);

} // WinMain

// Консольные функции T3DX ////////////////////////////////

int Game_Init(void *parms){// Инициализация игры

// Успешное завершениеreturn(1);

} // Game_Init

///////////////////////////////////////////////////////////

int Game_Shutdown(void *parms){// Завершение игры и освобождение ресурсов

// Успешное завершениеreturn(1);

} // Game_Shutdown

///////////////////////////////////////////////////////////

Page 30: ЧАСТЬ I · открыла эру видеоигр. Тогда, в 1976–78-х годах, TRS-80, Apple и Atari 800 представ-ляли весь рынок компьютеров

56 ЧАСТЬ I. ОСНОВЫ ПРОГРАММИРОВАНИЯ В WINDOWS

void Init_Blocks(void){// Инициализация поля блоковfor (int row=0; row < NUM_BLOCK_ROWS; row++) for (int col=0; col < NUM_BLOCK_COLUMNS; col++) blocks[row][col] = row*16+col*3+16;

} // Init_Blocks

///////////////////////////////////////////////////////////

void Draw_Blocks(void){// Вывод блоков на экранint x1 = BLOCK_ORIGIN_X, // Отслеживание текущего положения y1 = BLOCK_ORIGIN_Y;

// draw all the blocksfor (int row=0; row < NUM_BLOCK_ROWS; row++) { x1 = BLOCK_ORIGIN_X;

for (int col=0; col < NUM_BLOCK_COLUMNS; col++) { if (blocks[row][col]!=0) { Draw_Rectangle(x1-4,y1+4, x1+BLOCK_WIDTH-4,y1+BLOCK_HEIGHT+4,0);

Draw_Rectangle(x1,y1,x1+BLOCK_WIDTH, y1+BLOCK_HEIGHT,blocks[row][col]); } // if

x1+=BLOCK_X_GAP; } // for col

y1+=BLOCK_Y_GAP;

} // for row

} // Draw_Blocks

///////////////////////////////////////////////////////////

void Process_Ball(void){// Обработка движения мяча, соударения с ракеткой или// блоком; отражение мяча и удаление блока с экрана

// Проверка соударения с блоком