Введение
В пятом классе у нас с другом был доступ к заброшенному классу с парочкой стареньких TSR-80
. Вдохновил нас учитель, который подарил нам брошюру с простыми BASIC
программами, чтобы нам было с чем возиться.
Привод для считывания аудиокассет для компьютеров был сломан, поэтому если нам хотелось запустить какую-нибудь из программ, нам каждый раз приходилось вводить ее вручную. В основном мы предпочитали программы всего из нескольких строк наподобие:
10 PRINT "BOBBY IS RADICAL!!!"
20 GOTO 10
Как будто если компьютер выведет это сообщение достаточное количество раз, утверждение станет правдой.
И даже в этом случае нас подстерегали всевозможные трудности. Мы не имели представления о том как программировать, поэтому любая допущенная синтаксическая ошибка оказывалась для нас непреодолимой преградой. Если программа не работала, что случалось довольно часто, мы просто вводили ее заново.
В самом конце брошюры с кодами программ находился настоящий монстр - программа, которая занимала несколько полных страниц мелкого кода. Нам потребовалось немало времени прежде чем даже осмелиться за нее взяться. Но это все равно было неизбежно, потому что листинг был озаглавлен как "Тоннели и тролли". Мы не имели ни малейшего представления о том, что она делает, но название явно намекало на то что это игра. А что может быть интереснее чем собственноручно запрограммированная игра?
Нам так и не удалось ее запустить, а через год нам пришлось освободить этот класс (только гораздо позже когда я уже постиг основы BASIC
, я понял что это была всего лишь программа-генератор персонажей для настольной игры, а не сама игра). Тем не менее жребий был брошен - с тех пор я решил для себя что буду разработчиком игр.
Когда я еще был подростком у нас дома был Macintosh
с QuickBASIC
и немного позже с THINK C
. Я проводил за попытками написания игровых программ все свои летние каникулы. Учиться самому было сложно и даже мучительно. Начинать писать игру всегда было довольно легко - скажем экран с картой или небольшой паззл. Но по мере добавления новых возможностей программировать становилось все сложнее и сложнее. Как только у меня переставало получаться держать всю игру в голове целиком, все рушилось.
Поначалу задача была просто получить что-то рабочее. Затем становилось понятнее как писать программы, которые не осмыслишь в голове целиком. Вместо того чтобы просто читать книги наподобие "Как программировать на C++", я начал искать книги о том как организовывать программный код.
Не одно свое лето я провел за ловлей змеек и черепашек в болотах южной Луизианы. И, если бы там не было так жарко, вполне возможно я бы занимался герпентологией и писал бы другие книги.
Через несколько лет друг дал мне книгу Паттерны проектирования: Приемы объектно-ориентированного проектирования. Наконец-то! Это была книга, о которой я мечтал еще с подросткового возраста. Я прочел ее от корки до корки за один присест. У меня все еще были проблемы со своими программами, но мне было приятно видеть что не только у меня одного возникают подобные сложности и есть люди которые нашли способ их преодолеть. Наконец-то у меня появилось ощущение что я работаю не просто голыми руками, а у меня появились инструменты.
Тогда мы с ним встретились впервые, и уже через пять минут после знакомства я сел на пол и провел несколько часов за чтением полностью его игнорируя. Надеюсь, что с тех пор мои социальные навыки хоть немного улучшились.
В 2001-м я получил работу своей мечты: должность инженера-программиста в Electronic Arts
. Я не мог дождаться момента, когда смогу увидеть как выглядят настоящие игры и как профессионалы собирают их целиком. Как им удается создавать такие громадные игры как Madden Football
, которые ни у одного человека точно не поместятся в голове? На что похожа их архитектура? Как отделены друг от друга физика и рендеринг? Или как код ИИ (прим.: искусственный интеллект) взаимодействует с анимацией? Как, имея единую кодовую базу, добиться ее работы на разных платформах?
Разбираться в исходном коде было одновременно унизительно и удивительно. В графической части, ИИ, анимации, визуальных эффекта был восхитительный код. У нас были люди, умеющие выжать последние такты из ЦПУ (прим.: центральное процессорное устройство) и высвободить их для более нужных вещей. Еще до обеда эти люди успевали делать такие вещи, про возможность которых я даже не подозревал.
Но вот архитектура, соединяющая все эти отличные компоненты вместе, зачастую хромала и делалась в последнюю очередь. Они настолько концентрировались на функциональности, что на организацию кода обращалось слишком мало внимания. Высокая связанность (coupling) отдельных модулей была обычным делом. Новый функционал прикручивался к старой кодовой базе как попало. Для моего разочарованного взгляда это выглядело, как работа множества программистов, которые, если и открывали когда-либо Паттерны проектирования, то не продвинулись в чтении дальше раздела про Синглтон (Singleton).
Конечно не все было настолько плохо. Я ведь представлял себе игровых программистов как сидящих в башне из слоновой кости мудрецов, неделями дискутирующих о каждой мелочи в архитектуре игры. Реальность заключалась в том что я видел код, написанный в условиях жесткого дедлайна для платформы, на которой каждый такт ЦПУ был на вес золота. Люди потрудились на славу и, как я понял впоследствии, они действительно во многом выбрали лучшее решение. Чем больше я тратил времени на работу с этим кодом, тем больше я понимал сколько брильянтов он в себе таит.
К сожалению тут уместен именно термин "таит". Это были зарытые в коде алмазы, а прямо по ним топталось множество людей. Я наблюдал, как люди в мучениях переизобретали решения, прекрасные примеры которых уже находились в коде с которым они работали.
Именно эта проблема и побудила меня на написание данной книги. Я откопал и отполировал для вас лучшие из найденных мной в различных играх шаблоны для того чтобы вы могли тратить свое время на изобретение чего-то нового, а не на переизобретение уже существующего.
Что есть в магазинах?
Сейчас продаются десятки книг, посвященных игровому программированию. Для чего понадобилось писать еще одну?
Большинство книг по программированию игр, которые я видел, делятся на две категории:
Узко-специализированные книги. Эти книги концентрируются на чем-то одном и глубоко описывают только этот конкретный аспект. Они учат вас
3D
графике, рендерингу в реальном времени, симуляции физики, искусственному интеллекту или работе со звуком. Многие разработчики игр вообще специализируются только в определенной области.Книги обо всем. В противоположность первым, эти книги пытаются охватить все части игрового движка. Они объединяют их вместе и показывают как собрать законченный движок, обычно для
3D
шутер от первого лица.
Мне нравятся книги из обеих категорий, но я считаю, что все они оставляют слишком много белых пятен. Книги, концентрирующиеся на отдельных аспектах редко описывают, как данный кусок кода будет взаимодействовать с остальной игрой. Вы можете быть волшебником в области физики или рендеринга, но как правильно связать эти две подсистемы?
Вторая категория охватывает все, но зачастую подход получается очень монолитным и слишком жанрово-ориентированным. Сейчас, в период расцвета казуальных и мобильных игр, создаются игры самых различных жанров. Мы не можем больше просто продолжать клонировать Quake. Книги, показывающие вам создание движка под определенный жанр, не очень помогут вам если у вас совсем другая игра.
В отличие от других моя книга построена по принципу à la carte (франц.: по желанию). Каждая из глав в этой книге представляет собой законченную идею, которую вы можете использовать в своем коде. Таким образом, вы получаете возможность смешивать их и использовать только то что лучше всего подходит именно для вашей игры.
Есть еще один хороший пример принципа à la carte - хорошо известная серия Жемчужины игрового программирования (Game Programming Gems).
Как все это связано с шаблонами проектирования
Каждая книга, имеющая в заголовке слово "шаблоны", так или иначе связана с классической книгой "Паттерны проектирования: Приемы объектно-ориентированного проектирования", написанной Эрихом Гаммой, Ричардом Хелмом, Ральфом Джонсоном и Джоном Вличидесом (их еще часто называют "Банда четырех").
Называя свою книгу "Шаблоны игрового программирования" я вовсе не имею в виду, что книга банды четырех неприменима в играх. Совсем наоборот: вторая часть этой книги как раз обозревает многие из шаблонов, впервые описанных в Паттернах проектирования, но с той точки зрения как они могут быть применены в программировании игр.
Более того, я считаю что эта книга будет полезна и для тех, кто не занимается разработкой игр. Использование описанных шаблонов будет уместным во многих не игровых приложениях. Я вообще мог бы назвать книгу Еще больше шаблонов проектирования, но на мой взгляд игровые примеры выглядят выразительнее. Или вам интереснее в очередной раз читать книгу о списках сотрудников и банковских счетах (прим.: часто в качестве примеров применения шаблонов проектирования используют банки, клиентов, счета и пр.)?
Паттерны проектирования сами по себе также были написаны под впечатлением от другой книги. Идея создания языка шаблонов, описывающих ничем не ограниченные решения проблем пришла из книги Язык шаблонов (A Pattern Language) Кристофера Александера (и его соавторов Сары Ишикавы и Мюррея Силверстейна).
Их книга была посвящена архитектуре (в духе настоящей архитектуры, которая помогает строить дома, стены и т.д.), но они надеялись что и другие смогут использовать подобную структуру для описания решений в других областях. Паттерны проектирования банды четырех стараются применить тот же подход в программировании.
Вместо того чтобы попытаться низвергнуть "Паттерны проектирования", я рассматриваю свою книгу как их расширение. Пускай многие представленные здесь шаблоны будут полезны и в других типах программного обеспечения, я считаю что лучше всего они применимы именно к игровым задачам.
Время и последовательность действий зачастую являются ключевыми частями игровой архитектуры. События должны происходить в правильной последовательности и в нужное время.
Цикл разработки предельно сжат и множеству разработчиков необходимо иметь возможность быстро внедрять и итерационно менять широкий набор поведения, не наступая друг другу на ноги и не оставляя после себя следов по всей кодовой базе.
После того как поведение определено, начинается взаимодействие. Монстры кусают героя, зелья смешиваются, а бомбы взрывают врагов и друзей. Все эти взаимодействия должны реализовываться без превращения кодовой базы в спутанный клубок шерсти.
И наконец, для игр критична производительность. Игровые разработчики постоянно участвуют в гонке за первенство по максимально эффективному использования своей платформы. Небольшой трюк по сбережению нескольких тактов может отделять игру с наивысшим рейтингом и миллионными продажами от проблем с падением
fps
(кадров в секунду) и злыми рецензиями.
Как читать эту книгу
Вся книга разделена на три большие части. Первая - это введение и описание самой книги. Главу из этой части наряду со следующей вы сейчас и читаете.
Вторая часть - Обзор шаблонов проектирования рассматривает несколько шаблонов из книги банды четырех. Относительно каждого я высказываю собственное мнение и описываю его применимость в игровом программировании.
И, наконец, последняя часть - это сама соль данной книги. В ней описаны тринадцать новых шаблонов, которые я видел в играх. Она делится еще на четыре части: Последовательные шаблоны, Поведенческие шаблоны, Шаблоны уменьшения связности (decoupling) и Оптимизационные шаблоны.
Каждый шаблон внутри раздела описывается в виде стандартизирвоанной структуры так чтобы вам было проще использовать эту книгу для поиска того что вам нужно:
Секция Задача представляет собой краткое описание шаблона в терминах задачи, для решения которой он предназначен. Это первое на что вы будете обращать внимание, когда будете искать в книге решение возникших у вас трудностей.
Секция Мотивация описывает пример проблемы, которую позволяет решить шаблон. В отличие от алгоритма, без приложения к конкретной проблеме шаблон сам по себе не имеет формы. Изучать шаблоны без примеров - это как учиться печь хлеб не упоминая того как месить тесто. Этот раздел - тесто, которое мы будем печь дальше.
Секция Шаблон описывает сущность шаблона из предшествующего примера. Если вам нужно формализованное описание шаблона - вы найдете его здесь. Также вам будет полезно заглянуть сюда, если вы уже знакомы с шаблоном, но подзабыли детали.
Итак, шаблон у нас уже описан на конкретном примере. Но, как теперь понять что шаблон подходит именно для той проблемы, решением которой вы сейчас заняты? Секция Когда использовать содержит рекомендацию когда шаблон стоит использовать, а когда его лучше избегать. Секция Имейте в виду посвящена последствиям, которые вы получите применив шаблон в своем коде.
Если вам, как и мне, нужен конкретный пример, как именно чего-либо добиться, тогда секция Пример кода для вас. Здесь подробно разбирается реализация шаблона чтобы вы точно смогли понять как он работает.
Шаблон - это собственно шаблон решения. Каждый раз когда вы его используете, вы реализовываете его немного по-другому. Следующая секция - Архитектурные решения, раскрывает некоторые варианты применения шаблона.
В конце находится еще одна коротенькая секция Смотрите также, в которой описывается связь шаблона с другими и с первоисточниками из Паттернов проектирования. Здесь вы получите более ясную картину о том, какое место занимает шаблон в экосистеме остальных шаблонов.
О примерах кода
Примеры кода в этой книге приводятся на C++
, но это совсем не значит, что шаблоны можно реализовывать только на этом языке, или что C++
лучше всех остальных. Для наших целей годится любой ООП язык.
C++
я выбрал по нескольким причинам. Самая главная из которых заключается в том что на сегодняшний день это самый популярный для написания коммерческих игр язык. Для индустрии это lingua franca. Более того синтаксис C
, на который опирается C++
является также основой для Java
, C#
, JavaScript
и многих других языков. Даже, если вы не знаете C++
, приведенный в книге код будет понятен без приложения особых усилий.
Цель этой книги не в том чтобы научить вас C++
. Примеры наоборот максимально упрощены и даже не демонстрируют хороший стиль использования C++
. Они предназначены для того чтобы в них лучше читалась идея, а не просто читался хороший код.
В частности код не использует "модные" решения из С++11
или более новых реализаций. В нем не используются стандартные библиотеки и довольно редко используются шаблоны. В результате C++
код получился "плохим", но я не считаю это недостатком потому что таким образом он стал проще и его будет легче понять людям, использующим C
, Objective C
, Java
и другие языки.
Чтобы не тратить место на код который вы уже видели и который не относится к самому шаблону, он иногда будет приведен с сокращениями. В этом случае пример кода будет сопровождаться пояснением о том, что делает отсутствующая в листинге часть кода.
Представим себе функцию, которая выполняет некоторые действия и возвращает результат. Описываемый шаблон зависит только от возвращаемого значения, а не от того что делает функция. В таком случае пример кода будет выглядеть следующим образом:
bool update()
{
// Do work...
return isDone();
}
Куда двигаться дальше
Шаблоны - это постоянно обновляющаяся и расширяющаяся часть программирования. Эта книга продолжает начинание банды четырех в области документирования и демонстрации найденных шаблонов и этот процесс не будет остановлен, когда высохнут чернила на этих страницах.
Именно вы ключевая часть этого процесса. По мере того как вы будете изобретать новые шаблоны, улучшать (или опровергать!) уже существующие, вы будете приносить пользу всему сообществу разработчиков. Так что если у вас есть свои суждения, дополнения и другие комментарии касательно написанного, прошу выходить на связь.