Загрузка

Важность структурного подхода к разработке игр

Теги: алгоритмы

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

В данной статье хотелось бы напрямую коснуться вопроса структурного подхода к разработке игр, как необходимого подготовительного этапа к любой задаче. В простых проектах это 'Бумажка и ручка', в сложных и запутанных - Дизайн-документ, но от того, как мы его назовем, суть его не поменяется. Чтобы осилить сложную игру, нужно потренироваться на простой, но как это сделать? Сесть и написать - легко, так без труда сможет каждый, кто научился более или менее осмысленно стучать по клавишам. Но этот подход ни к чему вас не приведет, ибо, постепенно усложняя задачу, вы вдруг осознаете, что уперлись в непреодолимую преграду - сесть и написать уже не получится, а работать по-другому вы не умеете.

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

С ЧЕГО НАЧИНАЕТСЯ РАЗРАБОТКА ИГР

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

Так с чего же начать? Давайте представим, что мы хотим решить уравнение:

6X^2 + 12X^3 + X^4 + 2X^5 = 0 //знак ^ означает возведение в степень

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

(6X^2 + X^4)(2X + 1) = 0, где 6X^2 + X^4 = 0 или 2X + 1 = 0

Ну а здесь, в свою очередь,

X^2(6 + X^2) = 0, где X^2 = 0 или 6 + X^2 = 0<>2X + 1 = 0, где X = -1/2

Что же мы сделали? Мы разделили сложное уравнение на два более простых, которые затем вновь разделили на еще более простые. Решить такую задачу можно и в уме, тогда как изначальное ее представление вызвало бы у нас затруднения даже при решении на бумаге.

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

А вы заметили, что маленькие уравнения полностью локализованы? От решения одного из них не зависит решение другого: X = 0 или 2X + 1 = 0. Все они по-своему влияют на правильность решения общей задачи, но математически друг от друга совершенно не зависят. В этом и заключается основная идея структурного подхода: так умело разделить сложный проект на подзадачи (модули и классы), чтобы их выполнение было совершенно независимым друг от друга, полностью локализованным, самобытным. Конечно, достичь такого эффекта получается далеко не всегда, ибо зачастую полностью избежать соприкосновения элементов не удается, но, несмотря на это, используя подобный структурный подход, мы обязаны максимально, насколько это возможно в конкретной задаче, их локализовать.

Кстати, тем, кто еще не знаком с концепцией ООП (Объектно-ориентированного программирования), советую в самое ближайшее время заняться ее изучением. Именно ООП и направлено на максимальную структуризацию вашей программы: все мелкие задачи разделены на функции, наборы однотипных функций выполняют классы, ну а модули содержат в себе наборы классов, направленные на решение определенных подзадач. Это и называется структурой. Но, разумеется, объяснять принципы ООП в рамках данной статьи я не буду. Здесь я лишь описываю собственный опыт, а с техническими вопросами вы свободно можете ознакомиться на просторах интернета.

КАК ИСПОЛЬЗУЕТСЯ СТРУКТУРНЫЙ ПОДХОД

Думаю, одним из самых простых для понимания примеров использования структурного подхода здесь могла бы послужить идея графического движка. Не  Unreal или Unity, и уж тем более не Game Maker, а самого обычного графического движка, хотя, конечно, такие сейчас намного реже используются для разработки игр. Что он делает? Правильно, выводит на экран графику. И при этом, он полностью независим от всех остальных игровых вычислений. Вы можете использовать этот движок в любой игре (разумеется, соответственно его возможностям) или другой программе, занимающейся выводом графики, и методы его применения не будут совершенно ничем различаться. Вы просто вызываете необходимые вам функции вывода, а все остальное движок делает за вас сам.

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

НЕБОЛЬШОЙ ПРИМЕР, ДВИЖОК PERFECT ENGINE

Этот движок был написан мною в качестве обучающего инструмента для начинающих программистов и вполне успешно может использоваться в простых 2D-играх, где уже неоднократно и был успешно мною опробован. Более подробно о движке вы можете почитать на его официальном сайте (да, сделать что-то и не создать после этого сайт я не умею =)). Ну а вкратце, этот движок, несмотря на свою простоту, может выводить графику с использованием как простых средств GDI, так и сложного рендера на OpenGL или DirectX (если захотите такой написать, стандартно рендера на DirectX нет).

А это уже и есть структурный подход, то есть, разделение проекта на подзадачи. Изначально графический движок полностью отвязан от игрового проекта - это норма. Но, ко всему прочему, Perfect Engine еще и внутренне разделен на две составляющие - Движок и Рендер. И если первая его часть, непосредственно сам Движок, отвечает за выполнение всех математических расчетов и подготовительных действий, то вторая, Рендер, - занимается только финальным выводом графики на экран. И с этой точки зрения, конечно, совершенно неважно, какими средствами вывод будет производиться. Вот небольшой пример на основе функции вывода на экран прямоугольника с текстурой:

pDrawTexture(vTexNum: Integer; vPosX, vPosY, vWidth, vHeight: Real; vIsCenter: Boolean);

И только внутри вызывается функция вывода, доступная в используемом Рендере. Движок не знает совершенно ничего о том, какой Рендер используется, - он просто вызывает назначенную ему функцию, если она поддерживается (была назначена), в противном же случае - не вызывает ничего. Ну а то, какими средствами Рендер выведет эту графику на экран - зависит только от него. Метод (а движок реализован в виде класса) принимает на входе идентификатор текстуры, ее позицию и размер и еще один дополнительный параметр. Далее движок выполняет необходимые действия - некоторые проверки (существует ли выводимая текстура, можно ли вызвать функцию вывода), применяет к объекту воздействие камеры, если это необходимо, проверяет его на попадание в область экрана, вычисляет экранные координаты...

Кстати, интересно реализована в Perfect Engine и камера - она, также, вполне может служить примером локализации подзадач. Реализация камеры выполнена в виде отдельного класса, имеющего в своем арсенале несколько простых эффектов - тряску, плавное и резкое перемещение к цели. Движок же просто использует значения ее позиции для вывода графики, а методы реализации приведенных эффектов его совершенно не интересуют.

ПОДВЕДЕМ ИТОГИ

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

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


Думаю, на этом можно было бы закончить. Напоследок, хочу немного разрекламировать Perfect Engine. Ко всему описанному выше, можно выделить и еще пару любопытных особенностей Движка:

  1. Быстрое подключение (всего 2 строки для начала использования в программе)
  2. Независимость от метода вывода (выбирать Рендер можно при старте программы. Если на компьютере нет поддержки OpenGL, вы можете выводить графику с использованием GDI)
  3. Удобный и автоматизированный менеджер ресурсов
  4. Встроенная камера
  5. Поддержка изображений всех распространенных форматов
  6. Поддержка любых TTF-шрифтов
  7. Поддержка спрайтовой анимации (достаточно просто указать номер кадра, и движок автоматически выведет нужное изображение на экран)

Более подробно о Perfect Engine вы можете почитать на его официальном сайте. Там же (или здесь, в Клубе) можно скачать и игру Crown, реализованную с его использованием и наглядно демонстрирующую практически все его возможности - от использования Рендеров, до удобного управления камерой и реализации спрайтовой (покадровой) анимации.

Спасибо за внимание! Удачи в ваших проектах, выкладывайте их здесь, мы будем рады ознакомиться с ними и почитать о процессе их разработки.

Поделиться
Важность структурного подхода к разработке игр
Чтобы осилить сложную игру, нужно потренироваться на простой, но как это сделать? Сесть и написать - легко, так без труда сможет каждый, кто научился более или менее осмысленно стучать по клавишам. Но этот подход ни к чему вас не приведет, ибо, постепенно усложняя задачу, вы вдруг осознаете, что упе...
article
3 Монеты
SaiLight (3 года назад)

4 комментария:
SaiLight, уровень 4 (3 года назад):

А когда будет новая статья?

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

CTAP4E, уровень 1 (3 года назад):

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

SaiLight, уровень 4 (3 года назад):

CTAP4E, каждому свое: кто-то любит один язык, кто-то другой. Кому-то для проектов нужно пользоваться C-подобными языками, а кто-то обходится Delphi, как я, например. Зависит от потребностей человека. Pascal не умирает, напротив, появляются все новые и новые версии RAD Studio с их Delphi XE, довольно конкурентоспособной современной платформой. Но даже Delphi 7 сегодня, при умелом подходе, может сослужить очень неплохую службу, особенно на простых проектах, где запуск и использование тяжеловесной RAD Studio не будут оправданы.

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

CTAP4E, уровень 1 (3 года назад):

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

А видео в конце шикарное. Кого-то просил или сам делал?

Войти