Готовый перевод Game Programming Patterns / Паттерны программирования в играх: 2.3. Update Method

Цель

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

Причина

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

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

Ни статуй, поливающих ее молниями.

Ни зомби, патрулирующих вход.

Она просто входит и забирает добычу.

Конец игры.

Вы победили.

Знаете, это никуда не годится.

Кто знает,

может и есть спрос на игры без испытаний.

"10 щелчков мыши для победы!"

может стать следующим хитом продаж.

В склепе должны быть стражники - враги, с которыми наша отважная героиня сможет побороться.

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

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

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

// Патрулирование вправо.

// Патрулирование влево.

Дело в том, что скелет, конечно, двигается туда и обратно, но игрок этого никогда не увидит.

Программа находится в бесконечном цикле и это совсем не то, что мы хотим.

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

Придется убрать эти циклы и положиться на внешний игровой цикл для итерации.

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

Естественно, Game Loop (Цикл игры) это очередной паттерн в этой книге.

Я показал, что было до и после, что бы было видно как код становится сложнее.

Сначала патрулирование влево и вправо происходило в двух простых циклах

Направление патрулирования хранилось неявно в самих циклах.

Теперь, же каждый кадр приходится возвращаться во внешний игровой цикл, а потом продолжать с того же места. Для этого мы явно храним направление в переменной patrollingLeft.

Раз это более менее работает, то продолжим.

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

Они должны стрелять огненными молниями так часто, что бы держать её на цыпочках.

Если продолжать в духе "самого простого кода", то получится:

Я совершенно уверен, что у вас не возникнет ощущения, что всё это будет легко поддерживать.

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

Что бы все они работали одновременно мы смешали их код в пюре.

Если ваш процесс разработки напоминает "пюре", то у вас явно возникла проблема.

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

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

Для этого нам понадобится слой абстракции. Мы добавим его путём определения абстрактного метода update().

Главный игровой цикл (Game loop) обеспечивает функционирование набора объектов, но не знает к какому типу они относятся.

Все что он (Game Loop) знает - это то, что у них есть метод update().

Так мы отделим объекты друг от друга и от игрового цикла.

На каждом фрейме (кадре), главный игровой цикл проходит по коллекции объектов и вызывает для каждого метод update().

И каждый объект выполняет свои действия, которые должны быть выполнены за один фрейм.

Вызов этого метода для каждого объекта на каждом фрейме обеспечивает их одновременные действия.

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

Пока один объект обновляется, все остальные ждут.

Давайте рассмотрим это подробнее.

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

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

Паттерн

Ировой мир обслуживает коллекцию объектов.

Каждый объект имплементирует метод "update", который обновляет состояние для данного фрейма.

Каждый фрейм игра обновляет каждый объект в коллекции.

Когда использовать

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

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

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

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

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

Тогда такой паттерн может вам в этом помочь.

Update метод хорошо применим когда

Ваша игра содержит какое-то число объектов или систем, которые необходимо одновременно обсчитывать.

Поведение отдельно взятого объекта слабо зависит от остальных.

Их поведение изменяется во времени.

Помните

Этот способ очень простой и в нем почти нет подводных камней.

Переведено на Нотабеноиде
http://notabenoid.org/book/51192/215219

Переводчики: MrSmith33, fregate, Deo, Vladislav86

adm244

Настройки

Готово:

16.43% КП = 1.2

Непереведённые фрагменты будут пропущены.