Лекция #33. Плюсы и минусы игровых "орхетектур". [Лектор - dDIMA] (5 стр)
Автор: Арсений Капулкин
[23:09] <dDIMA> Еслти вы делаете универсальный GameObject() вообще для всего, боюсь, что позиицю и размер получат все (но не все будут обновлять)
[23:10] <IronPeter> инвентори персонажа.
[23:10] <IronPeter> абстрактная сущность.
[23:10] <IronPeter> размер - как рюкзак за плечами.
[23:10] <dDIMA> А если GameObject разбить на мелкие части (либо по идеологии SpriteObject(), GameSysObject и EntityObject(), либо по идеологии Updatable, Renderable) то можно и сэкономить
[23:10] <IronPeter> Но - абстрактное владение. Может у меня вещь в банке лежит.
[23:10] <dDIMA> Я почему и говорил про минус универсального GameObject
[23:11] <IronPeter> негеометрично. Что-то тут не то, Дима.
[23:11] * dDIMA втянул еще травы
[23:11] <dDIMA> поясни, плз?
[23:11] <IronPeter> может пусть будет РендерОбъект, который лежит в РендерСцене.
[23:11] <IronPeter> а геймобъекты будут иметь ссылки на такие и всякие им флажки ставить.
[23:12] <IronPeter> типа SetVisible()
[23:12] <IronPeter> и может не в рендере, а в своем апдейте.
[23:12] <IronPeter> оно менее готично так выйдет.
[23:12] <dDIMA> Смотри
[23:12] <dDIMA> Я писал следующее:
[23:12] <dDIMA> dDIMA: - Модели персонажей должны пропадать на расстоянии 500 метров, мелкие аптечки - на расстоянии 100 метров
[23:12] <dDIMA> dDIMA: - Трупы должны переставать рендериться через 12 секунд после смерти. А некоторые - через 25
[23:12] <dDIMA> dDIMA: - Игрок по разному рендерится, если мы прикрутили к движку кат сцены
[23:12] <dDIMA> dDIMA: - Для пуль сделали контейнер на 500 объектов, чтобы не создавать пульки в рантайме, а брать их уже готовыми. Неактивные пули рендериться не должны
[23:12] <dDIMA> dDIMA: - Гильзы не должны рендериться в зеркалах
[23:12] <dDIMA> dDIMA: и т.п.
[23:12] <dDIMA> Это типа gamespec требования
[23:13] <IronPeter> ну игровая сущность - контейнер пуль.
[23:13] <dDIMA> ага
[23:13] <IronPeter> рожает их, вполне нормально. Добавляет в сцену.
[23:13] <IronPeter> Но именно добавляет, а не рендерит.
[23:13] <dDIMA> на самом деле довольно много из них укладываются в 2 понятия:
[23:13] <dDIMA> visible/invisible
[23:13] <dDIMA> и distance
[23:13] <dDIMA> ну, с точки зрения системы должно быть пофигу - "добавляет в рендер" или "рендерит"
[23:14] <dDIMA> потому что после render(m_model) Fox'у должно быть наплевать, когда там эта геометрия выведется на экран
[23:14] <IronPeter> да вроде как нет.
[23:14] <dDIMA> тогда поясни?
[23:14] <IronPeter> рендерит - это некоторая активность каждый фрейм.
[23:14] <dDIMA> ага
[23:14] <IronPeter> добавляет - это тик апдейта.
[23:14] <IronPeter> который может не быть синхронен кадру. А реже.
[23:15] <dDIMA> может не быть. Но на самом деле мне кажется, что мы экономим немного на вызове activeModelList[index++] = pModel;
[23:16] <dDIMA> тут есть другой момент, более опасный
[23:16] <IronPeter> ну а мне кажется, что мы разносим геймлогику и логику рендерения.
[23:16] <IronPeter> последняя - с PVS и FOV
[23:16] <IronPeter> и кучей заморок. Типа того, что анимацию надо обновлять, если только попали в FOV
[23:16] <dDIMA> я только хочу уточнить, что логика рендеряния имеет слишком много геймлогики
[23:17] <dDIMA> поэтому сделать ее полностью в системном коде не получится
[23:17] <dDIMA> да да, я про это написал, что скин - это чисто визуальная примочка
[23:17] <dDIMA> хотя анимация костей может потребоваться и на апдейте
[23:17] <IronPeter> да.
[23:17] <dDIMA> я насчет опасного момента
[23:17] <IronPeter> и с такого рода мелочами всегда куча проблем.
[23:17] <dDIMA> допустим, у нас тайловая схема и на экране видно 4 тайла из 50
[23:17] <IronPeter> я тоже.
[23:18] <dDIMA> даже еще проще
[23:18] <dDIMA> вот пример
[23:18] <dDIMA> у нас есть апдейт и есть рендеринг
[23:18] <dDIMA> мы убиваем персонажа, и пока он отыгрывает анимацию смерти, отвернулись от него
[23:19] <dDIMA> персонаж вышел из FOV, система убила ему рендер
[23:19] <dDIMA> (хорошо, если и апдейт не прикончила заодно :))
[23:19] <dDIMA> мы подождали 5 секунд, повернулись обратно - и мы видим, как персонаж плавно завершает свою анимацию смерти с того же самого момента, когда мы отвернулись от него
[23:19] <IronPeter> у нас хуже - система отреплицировала объект с сервера, который попал в зону нашего интереса. Потому что прибежали к трупу.
[23:20] <dDIMA> Ээээ
[23:20] <IronPeter> и он начинает играть анимацию смерти.
[23:20] <IronPeter> с нуля.
[23:20] <dDIMA> ага
[23:20] <IronPeter> то же багло.
[23:20] <dDIMA> Вот еще пример - про тайлы
[23:20] <dDIMA> У нас видно 4 тайла из 50
[23:20] <dDIMA> ну что может быть проще - возьмем и вообще прибъем весь процессинг в невидимых тайлах
[23:20] <dDIMA> или даже по стримингу выгрузим их нафиг
[23:21] <dDIMA> И что мы получим в итоге?
[23:21] <dDIMA> Оставили мужиков строить что-то в каком-то квадрате, потом уехали, вернулись, а они даже не приступали
[23:21] <IronPeter> ну мы приходим к тому, что отдельно render отдельно апдейт.
[23:21] <dDIMA> Да
[23:22] <IronPeter> вот пусть не будет Fox::Render?
[23:22] <dDIMA> Причем проектируя логику отсечения в систмном коде, надо быть предельно внимательным
[23:22] <IronPeter> А будет Fox::Update
[23:22] <IronPeter> я за это и боролся только.
[23:22] <_zerg> <IronPeter> у нас было такое багло но мы его побороли
[23:22] <_ShaMan_> хм
[23:22] <dDIMA> И в конце Fox::Update() будет AddModelTo Render(). Так,
[23:22] <dDIMA> ?
[23:23] <IronPeter> Дима, что-то в таком духе. Скорее AddToScene
[23:23] <Zeux> SceneGraph::markVisible(camera); Fox::Update() { if (flags & visible) AddModelToRender(); }
[23:23] <dDIMA> Да да
[23:23] <dDIMA> Но
[23:23] <dDIMA> У нас осталось еще куча обработки, которая чисто рендеряемая
[23:24] <dDIMA> Скины мы можем подсчитать прямо в модели - это не проблема
[23:24] <dDIMA> Анимацию передвинем
[23:24] <dDIMA> Но давай предположим, что это модель мужика, и ему надо (если он рендериться) довернуть процедурно шею в соответствии с тем, куда сейчас идет главный герой
[23:25] <dDIMA> вот кто будет доворачивать шею?
[23:25] <IronPeter> Дима, коллбэк.
[23:25] <IronPeter> который подвешен на кость - локатор.
[23:25] <_ShaMan_> коллбэк чего?
[23:25] <IronPeter> коллбек меня.
[23:25] <dDIMA> Колбэк обратно в Fox :-)
[23:26] <IronPeter> который докручивает кость.
[23:26] <IronPeter> жизнь сложна, если такое надо.
[23:26] <IronPeter> если надо уметь брать анимацию и уже после туда миксить.
[23:26] <dDIMA> Ну, фактически это тот же самый Fox::Render(), только вид сбоку
[23:26] <IronPeter> это апдейт каждый кадр. Впрочем, вероятно вопрос семантики только.
[23:26] <dDIMA> просто кроме колбека на кости бывает еще много чего другого разного
[23:27] <dDIMA> так нам не надо доворачивать его, если мы не видим :)
[23:27] <IronPeter> ну отлично, коллбек не вызовут.
[23:27] <IronPeter> так как вне FOV
[23:27] <dDIMA> Я понимаю, что перформанс пенальти тут нулевой, просто пример неподходящий :)
[23:29] <dDIMA> Народ, можно продолжать бесконечно :). Я только прошу учесть тот факт, что ограничения Апдейта и Рендера в _системном_ коде движка должны всегда тщательно анализироваться. Потому что надо ли апдейтить и рендерить - знает только конкретный сцукоFox
[23:30] <dDIMA> Итак, последняя часть из обещанных - это Resource manager.
[23:30] <dDIMA> Я уже вводил понятие разреза между компонентами.
[23:30] <dDIMA> Если его применить к менеджеру ресурсов, то станет очевидно, что как только у вас в хидерах ресурсной системы появляется понятие enum { Texture, Model, Cursor и т.п. }, то Resource manager как универсальная часть движка перестает существовать.
[23:31] <dDIMA> Вместо него появляется странная система, которая умеет работать с данными, но в которую явно искуственно пролезли куски подсистем текстур, работы с моделями и т.п.
[23:31] <dDIMA> А потом туда в enum полезут карты навигации AI, таблицы настраиваемых параметров и другие game specific параметры
[23:31] <dDIMA> И универсальный ресурс менеджер развалится просто на глазах
[23:31] <dDIMA> В соответствии с принципом из предыдущей части:
[23:31] <dDIMA> Ресурс-менеджер по определению тупая штука
[23:32] <dDIMA> Он умеет загружать данные по их ID в соответствии с заданными алгоритмами и передавать их обработчикам
[23:32] <dDIMA> А логика загрузки текстур должна быть все-таки в текстурном менеджере
[23:32] <dDIMA> Курсоры умеет загружать система UI
[23:32] <dDIMA> Ну и так далее
[23:33] <dDIMA> Так что ресурсному менеджеру достается задача загрузки файлов данных с последующим распределением их по компонентам
[23:33] <dDIMA> Как это делать - вариантов два (как обычно, с промежуточными реализациями)
[23:34] <dDIMA> Существуют функции в соответствующих подсистемах (текстуры и т.п.), которые вызывают методы текстурного менеджера на (как правило, асинхронный) подъем данных в память
[23:34] <dDIMA> И второй вариант: текстурный менеджер самостоятельно занимается подъемом данных в память, обеспечивая среди подписчиков (обсерверов) поиск того, который распознает данные как свои
15 июня 2007 (Обновление: 13 ноя 2009)