Форум: "Игры";
Текущий архив: 2004.05.23;
Скачать: [xml.tar.bz2];
ВнизИгровая логика Найти похожие ветки
← →
Stalker_23b (2004-01-11 23:57) [0]В каждой игре мы имеем дело с большим набором динамических взаимодействующих объектов. Как все это организовать? Первая идея - TObjectList со списком объектов, в обсчете кадра все объекты обновляются, создаются новые и удаляются старые - по необходимости. Однако в сложной игре объектов очень много и они сильно взаимосвязаны. Как организовать надежный просчет, реакцию на событие и динамику объектов? Как построить оптимальную иерархию классов и логику для данной игры? Как управлять объектами, сохранять\загружать их из файла? Какие решения вы обычно используете в играх?
← →
K.o.Z © (2004-01-12 03:34) [1]Если знать рациональные ответы на все твои вопросы, то можно смело браться за написание собственного движка %)
← →
cyborg © (2004-01-12 09:22) [2]>>В каждой игре мы имеем дело с большим набором динамических
>>взаимодействующих объектов. Как все это организовать?
Это зависит от типа игры. 2D, 3D, RTS, RPG, аркада, логическая, походовая и пр.
Для объектов выход один - список, т.е. структура, в которой имеются указатели на другие объекты (предыдущий, следующий).
>>Как организовать надежный просчет,
>>реакцию на событие и динамику объектов?
Надёжный он и так будет, еслю глюков не напишеш ;). Выход в списках.
>>Как построить оптимальную иерархию классов и логику для данной игры?
Зависит от игры, просто хорошо обдумай это дело, у меня вообще все объекты в игре это одна запись TSprite=record, от объекта героя, до заднего фона, только данные подключаются к нему в зависимости от самого объекта.
>>Как управлять объектами, сохранять\загружать их из файла?
Последовательный перебор по списку всех объектов, которые нужно обработать в данный момент.
>>Какие решения вы обычно используете в играх?
Зависит от типа игры.
← →
NikeOLD (2004-01-12 12:39) [3]Посмотри исходники DelphiX от Хори. Там все ясно и понятно даже без комментариев
Подсказака: смотри модули где спрайты описаны и движок (engine), сейчас не помню названия :)
← →
Vertex (2004-01-12 16:38) [4]Пишешь класс работающий с указателями на объекты, он будет использовать TList. Описываешь в нем функции добавления, удаления, поиска, доступа и т.д., в зависимости от твоих потребностей. Создаешь класс прородич всех твоих игровых классов, указателем его типа и будет орудовать TList. Все, далее тебе остается тока создавать иерархию классов, но с условием, что все они наследованы от базового, так что тебе никто не запретит пихать их в лист. Как совет, описать еще в базовом классе виртуальные функции отрисовки и отработки и т.д. (типа Draw, Process, OnMouseDown, OnMouseUp, SaveToFile, LoadFromFile), которые будешь вызывать в таймере при прорисовке или при загрузке. Их ты будешь перегружать в нужных потомках, для того, чтобы например нарисоваться по другому.
Но это полбеды, на определенном этапе тебе понадобится доступ из одного класса, например из персонажа к бочке, к которой он подошел, и вот тут гемор. Совет создавай класс типа TGame, в котором будет TList, одна функция прорисовки, процессинга, загрузки и т.д. на всеь лист. А при создании и добавлении в лист объектов передавай им указатель на класс TGame, который является их хозяином, все, теперь объекты имеют доступ ко всему, достаточно гибкая система, но со своими проблемами. А ваще иди к этому сам, дольше идти, но зато когда придешь будешь знать, а главное понимать на много больше, чем те, кто задает вопросы и не всегда получает на них ответы в этих форумах).
← →
Omar2002 © (2004-01-12 21:28) [5]Я в своих играх делаю для каждого набора однотипных обьектов свой класс, в этот класс закладываю все параметры обьекта. Очень удобно и просто, а так же легко поддается апгрейду без переделки движка.
← →
maniac (2004-01-16 02:53) [6]Ладно забью на поспать и поделюсь вселенской тайной.
Есть приложение, оно обьект (tapplication). У него есть цикл работы- запустили, поработали, закрыли.(на дельфи за это отвечает vcl)
Есть движок игрушки, он крутится внутри приложения, инициализируется после запуска, завершается до выхода.
У движка есть подчинённые обьекты - рендер, ввод, звук, сеть, игровой мир. Они инициализируются движком, им же и прибиваются.
Игровой мир - собственно игра и есть. Содержит игровые обьекты (местность/юниты/контроллеры этап/монстров/персонажа и.т.д.)
Когды пользователь делает "сейв" этот игровой мир в записку и попадает.
АИ действует через контроллеров, один из контроллеров завязан на интерфейс пользователя и прокладку между стулом и экраном.
Хранится все это добро в иерархической системе, общается между собой сообщениями (движок:"не могли бы вы, милостливый сударь рендерь, показать на экран чаво-нибудь?",рендер:"спрайты! по зет-ордеру становись, равняйсь.......)
Все.
← →
MrAngel (2004-01-16 03:12) [7]maniac (16.01.04 02:53) [6] - на счёт игрового мира.
"Игровой мир" можно разделить на:
1. Обьекты (меши, уровни, и прочие сетки)
2. Источники света
3. Камеры
4. Текстуры (для мешей, уровней и прочих сеток)
Вопрос касательно прорисовки "Обьектов".
Должен ли прорисовку делать сам "Рендер", т.е. когда он из меша берёт все вертексы или когда рендерит через буффера ?
Или же !!! "Рендер" лишь вызывает, в зависимости от иерархии, методы "Обьектов", которые отвечают за прорисовку. Т.е. по сути дела прорисовка производится внутри обьекта.
← →
maniac (2004-01-16 19:53) [8]Эээ!!
Не совсем - меши/уровни/партиклы/текстуры/свет - подчиненные рендера.
Камеры/Ентайты/физика/контролеры - подчиненные игры.
Обьекты рисуют себя сами, когда рендер их попросит. В 2д - сообщение по зет-ордеру/видимости выбирает обьект и просит нарисоватся. Обьект блитует свой спрайт.
← →
MrAngel (2004-01-17 15:35) [9]
> Не совсем - меши/уровни/партиклы/текстуры/свет - подчиненные
> рендера.
> Камеры/Ентайты/физика/контролеры - подчиненные игры.
Не буду спорить, у меня на счёт этого своё видение иерархии.
> Обьекты рисуют себя сами, когда рендер их попросит. В 2д
> - сообщение по зет-ордеру/видимости выбирает обьект и просит
> нарисоватся. Обьект блитует свой спрайт.
Это ты имел ввиду только для 2D ? Или же это и к 3D тоже относится? Я имею ввиду прорисовку внутри обьекта.
← →
Dikoy (2004-01-17 18:02) [10]TList это конечно хорошо, но поиск в нем организовывать через чур медленно... да и памяти ужирает он прилично...
если планируется большое количество объектов - надо писать свой класс, который будет работать с записями (record) это оптимальнее намного, если прямо написать, учитывая, что в игре все объекты так или иначе взаимосвязаны (причем иногда связь многие ко многим) наилучший вариант использовать деревья, поиск по бинарному дереву, помнится был самым шустрым...
короче читаем кнута и интернет... давно уже с этим не сталкивался, но в инете существует куча ресурсов на эту тему, правда многие не на русском :)
← →
nexxiss © (2004-01-17 21:20) [11]Полностью согласен с Dikoy, балее целесообразно использовать динамические структуры данных: деревья, списки, стеки, деки и очереди, только нужно знать как они реализовываются. Более доступно описано это дело у Н.Вирта, со всеми примерами, но не по всем структурам. В последнем издании примеры написаны на МОДУЛА, благо он схож с ПАСКАЛем, разобраться не составит труда.
← →
maniac (2004-01-18 06:08) [12]2 Dikoy
/// если планируется большое количество объектов - надо писать свой класс, который будет работать с записями (record) это оптимальнее намного,
Чем? Зачем? Обьект это запись которая кроме данных хранит ссылку на свой класс. Не сильно медленней, зато разница в подходах существенна.
/// если прямо написать, учитывая, что в игре все объекты так или иначе взаимосвязаны (причем иногда связь многие ко многим) наилучший вариант использовать деревья, поиск по бинарному дереву, помнится был самым шустрым...
Сейчас обхожусь хешем. Вроде работает.
2 MrAngel
Не догоняю. У обьекта нет поля "спрайт". У игрового обьекта есть свой подчиненный "визуальный обьект" который в ответ на сообщение рендера и занимается рисованием.
← →
MrAngel (2004-01-18 15:30) [13]Вот - ясно я это и хотел узнать.
Просто, видел несколько движков, где прорисовка всего шла именно в "рендере". Причём он мог рисовать ТОЛЬКО треугольники и ВСЕ треугольники находились в ВершинномБуффере. Т.е. "рендер" прорисовывал всё это путём вызова одной gl_ проседуры.
← →
dikoy (2004-01-18 17:08) [14]2 maniac:
Обьект это запись которая кроме данных хранит ссылку на свой класс
:)) здорово сказал :)) вообще-то в переменной объекта хранится ссылка на область данных объекта и на vmt (таблицу методов объекта).
соответственно инициализация указателя на запись и указателя на объект выполняется со значительной разницей в времени выполнения...
это раз...
вызов метода из виртуальной таблицы это поиск по vmt затем только вызов, таким образом если ты из одного объекта вызваешь другой объект время вызова увеличивается в 2 раза... а если ты храниш объект кот. нужно вызвать в списке типа TList то вообще получается здорово :)
одним словом ООП это конечно круто, но во всем нужна мера...
так урывая тики процессора то тут то там и создаются оптимизированные программы... хотя с тем как сейчас развивается "железная" индустрия на это многие попросту забивают :)
← →
maniac (2004-01-18 17:41) [15]Ага а теперь, скажи- сколько надо создавать объектов (в каждом кадре) на П3 чтоб ФПС в результате был ниже (для логики) 20 ?
//вызов метода из виртуальной таблицы это поиск по vmt затем только вызов, таким образом если ты из одного объекта вызваешь другой объект время вызова увеличивается в 2 раза... а если ты храниш объект кот. нужно вызвать в списке типа TList то вообще получается здорово :)
Кстати, не поиск. А выборка по индексу. И только для виртуальных методов.
А если ты динамически ищешь обьект по идентификатору в списке.... Да времени уходит больше, чем вызов плоской процедуры, но оно того стоит.
Оптимизацией надо заниматся после создания устойчивой версии, реализующей все требуемые возможности. "Оптимизация выполняемая заранее - зло..." (цитата)
← →
dikoy (2004-01-18 19:01) [16]>Оптимизацией надо заниматся после создания устойчивой версии, реализующей все требуемые возможности. "Оптимизация выполняемая заранее - зло..." (цитата)
Если в процессе оптимизации придется переписывать половину кода - это уже новый проект...
← →
maniac (2004-01-19 01:24) [17]Проверено на ежиках - нет. Есть серьёзная разница между кодингом заново, и переписыванием старого. Первое - больше напрягает мозги, Второе - пальцы. Если приходилось перерисовывать старый код, обычно сносил все исходники в другую папку, и методом копи-паст оттудова маленькими кусочками.
Просто проблема в чем: есть ошибки проектирования, которые вылазять только после создания устойчивой версии(...или я такой ламер...). И вот тогда и приходится все переделывать. Несоответствие во скорости , кстати - одна из них.
← →
nexxiss © (2004-01-19 02:29) [18]Переделывать приходится тогда, когда ты разработал неправильную структуру данных. Между прочем, это дело занимает уйму времени и от етого зависит работа всего движка и даже проекта. Лучше использовать указатели и т.п. так как указатель не зависимо от типа данных занимает всего 4 байта, массив .... ; хотя память расходуется почти одинакого, зато доступ к данным быстрее. Тем более, при рендере это особо важно, т.к. количество объектов может быть очень большим. С другой стороны это не совсем удобно, но в более менее больших проектах работают, в основном, с памятью напрямую. Правда это зависит от конкретно поставленной задачи. Иногда проще использовать массив ( согласен ). Что касается хранения данных, лучше выбирать бинарное дерево, т.к. скорость работы с ним самая оптимальная, но это не всегда подходит правда. Короче, в начале разработайте правильную структуру данных и их взаимосвязь, а потом начинайте от этого "прыгать".
С уважением nexxiss.
← →
maniac (2004-01-19 06:44) [19]///но в более менее больших проектах работают, в основном, с памятью напрямую.
Это в каких, можно поинтересоватся? И как "напрямую"?
///Короче, в начале разработайте правильную структуру данных и их взаимосвязь, а потом начинайте от этого "прыгать".
Ага и в этом вся проблема.
← →
Dikoy (2004-01-19 11:11) [20]2 maniac:
>Проверено на ежиках - нет. Есть серьёзная разница между кодингом заново, и переписыванием старого. Первое - больше напрягает мозги, Второе - пальцы. Если приходилось перерисовывать старый код, обычно сносил все исходники в другую папку, и методом копи-паст оттудова маленькими кусочками.
Просто проблема в чем: есть ошибки проектирования, которые вылазять только после создания устойчивой версии(...или я такой ламер...). И вот тогда и приходится все переделывать. Несоответствие во скорости , кстати - одна из них.
ошибки проектирования и нерациональное программирование это разные вещи... если у тебя проект весит метров 5 исходниками сколько времени ты потратишь на то, чтобы все оптимизировать путем копи-паста, к тому же копи-паст не всегда реализуем в принципе? ужу лучше сразу drag"n"drop to the trash...
← →
NailMan © (2004-01-19 14:35) [21]Я лично начал с того(точнее начал так в четвертой версии ядра :-) ), что продумал иерархию моих игровых объектов. Условно я разделил все игровые объекты на 2 уровня - уровень конструктивов(объекты, спрайты, FX-сы) и уровень контроллеров - Актеры.
Первые нужны для хранения информации о частях объектов(передвигаемые контейнеры) и собсно они и рендерятся, т.е. являются видимыми на экране, хотя сами никакой геометрии(сетки) и текстур не содержат. Они наследуются от базового класса, в котором реализованы стандартные методы для работы с перемещениями и есть виртуальный метод MoveTo, который перекрывается каждым (конечным) классом как ему уже нужно(естественно у спрайта свой медод движения, а у объекта свой).
Кроме того спрайты подерживают инлайн анимацию - т.е. могут циклически менять свои размеры. Это нужно для создания сигнальных маячков. Объекты только статичные по своей натуре.
Актеры - это уже универсальный объект, который состоит из конструктивов. Он может содержать собственную анимацию(траектория и т.д.), он может двигать свои подчиненные объекты посредством механизма "аниматроников". Этот класс также порожден от базового, но имееет довольно сложную процедуру перемещения - после собственного передвижения в новою позицию(и вращения ессно), он последовательно передвигает все свои конструктивы(они изначально содержат координаты относительно центра Актера) плюс анимирует то что надо инлайновой анимацией.
Сразу скажу что объекты, спрайты и FX-сы в игре сделаны в виде глобальных массивов. Это упрощает доступ к ним при рендере и обсчете коллизий. Актер в себе содержит только лист с индексами принадлежащих ему конструктивов, самих конструктивов в нем нет(казалось бы так было бы логичней сделать).
Есть несколько ограничений - один и тот же объект(спрайт, FX) не может принадлежать разным актерам(ограничения чисто технологические у D3D). Это достигается посредством загрузчика(ресурсного мэнеджера). Он выдает только валидный индекс конструктива запрашивающему Актеру при его создании. Соотвественно при уничтожении Актера, он сообщает загрузчику что мол вот эти конструктивы надо удалить.
Вобщем самое черное дело - это просчет коллизий(у меня построено на сферах исходя из жанра игры). В целом такой просчет очень быстрый - для пары сфер сравнивается квадрат растояний от их центров с суммой квадратов их радиусов. При числе объектов(именно объекты "сталкиваются" друг с другом, а не Актеры) около 20 падения скорости вообще не наблюдается. Думаю если на порядок будет увеличено число, то тоже мало пострадает(алгоритм быстрый и есть варианты оптимизации). Эту опрерацию(коллизию) делает уже клас движка.
MrAngel
Вопрос касательно прорисовки "Обьектов".
Должен ли прорисовку делать сам "Рендер", т.е. когда он из меша берёт все вертексы или когда рендерит через буффера ?
Или же !!! "Рендер" лишь вызывает, в зависимости от иерархии, методы "Обьектов", которые отвечают за прорисовку. Т.е. по сути дела прорисовка производится внутри обьекта.
Именно так. Никто другой кроме самого конечного класса не должен знать как он рендерится. Просто остальным это не нужно знать.
Вообще же стоит сделать несколько вариантов рендера одного и того же класса. Скажем объект содержит 5 материалов, которые имеют разных 5 текстур. Другой объект(или сотня, не суть важно) содержит 10 материалов, у которых 4 материала имеют такие же текстуры как и у первого.
Если делать вариант когда объект последовательно рендерит все свои материалы в цикле, то он должен совершать каджый раз в цикле переключение текстур(что довольно "тяжелая" операция). Даже если делать механизм предотвращения лишних переключений в виде сравнения устанавливаемой текстуры с уже установленной(я сделал по индексу), то такой механизм в этом варианте практически не изменяет погоды. Будут лишь уменьшаться число переключений на концевых материалах. Если же делать модельки с материалами, у которых нет текстур и которые расположены последними(первыми), то такой механизм вообще не работает.
Если делать вариант, когда сцена(она вызывает метод Render у объекта) вызывает на рендер не целиком весего объекта, а его части и при этом делает она это по определенному списку, который отсортирован по индексам использующихся текстур(один объект как бы присутсвует в этом списке числом своих материалов), то механизм со сравнением текстур(индексов) очень и очень сильно улучшит скорость рендера всей сцены: первый кусок устанавливает текстуру, последующие сравнивает и так как у него та же текстурв, то игнорирует. Тот кусок у которого другая текстура, установит ее и все по новой. Цена этому - многократное увеличение вывовов Render у объектов. В целом современные процы с этим справятся на ура, а выгода по переключениям текстур огромна.
← →
Vertex (2004-01-19 18:43) [22]Ребят вы уж определитесь с графикой, 3d или 2d, общие принципы относительно данного вопроса конечно идентичны, но разных мелочей много. Читая я терялся.
Мое мнение рендер объекта для 2/3d должен осуществляться внутри объекта, если тому не противоречит оптимизационная логика.
Списки хранения... ну по мне используй что удобно, а когда сделаешь все и приступишь к оптимизации, глянь на фпс и подумай нуно ли тебе использовать хэш-таблицы, деревья и т.д. Мне не приходилось это делать... Тут dikoy прав, железо не требует этой оптимизации. Да, жаль, что теперь программист, это не программист девяностых, но что тут поделаешь, делфи то тоже делалась для упрощения программинга, вот и новое железо надо воспринимать как результат бесполезности оптимизации. Хотя для души моно, согласен.
← →
cyborg © (2004-01-19 19:32) [23]У меня другая точка зрения. Рисовать должен рендерер, так, как объекты игры не обязаны быть объектами (TObject).
← →
maniac (2004-01-20 10:34) [24]Т-е обьекты внутри игровой логики не обязательно унаследованы от tobject?
← →
NailMan © (2004-01-20 10:43) [25]Vertex
что тут поделаешь, делфи то тоже делалась для упрощения программинга, вот и новое железо надо воспринимать как результат бесполезности оптимизации. Хотя для души моно, согласен.
Ага. Когда у тебя каджый объект для каждого материала будет устанавливать свою текстуру(или пустую), то даже на нормальной машине(FG FX/Radeon и хорошим камнем) игрушка будет максимум давать 50 фпс(при условии большого количества объектов). Это вообще никакой фпс.
Я свою игрушку целенамеренно вытягиваю на минимум - 70фпс в самой сложной сцене.
Оптимизация использования ресурсов - это приоритетная задача геймдевелопера. Ассемблерные замены простых действий - не спорю, нах не нужно. А вот оптимизация математики(sin/cos, sqrt etc) надо обязательно затачивать под все процы(и sse и 3dnow) потому что не использовать такую аппаратную халяву - грех. Тут тоже ничего сложного - качаецца с intel.com или amd.com ихний SDK и под дельфи портируются уже готовые функции. У AMD есть классная фича - быстое копирование небоших блоков данных(да и больших тоже). Я такой фичей сделал быстрое присваивание матриц. Итого прирост фпс на 500 присваиваний за отрисовку был процентов 40, а работы максимум на час.
И нечего надеяться на железо - при фиговом умениии им пользоваться(оптимально) ничего путного не выйдет.
cyborg ©
У меня другая точка зрения. Рисовать должен рендерер, так, как объекты игры не обязаны быть объектами (TObject).
Чем же они могут быть еще? Record"ами? Вобщем-то прошлый век.
имхо - в движке должна быть субординация:
Рендерер должен управлять D3D девайсами и вызывать у ИО методы их рендеринга.
ИО должны уметь перемещаться и сами себя рендерить, так как у каждого свои принципы рендеринга ничем не схожие с другими типами ИО.
Ресурсные мэнеджеры должны им помогать в этом.
У меня рендерер разделенный - сам рендерер отвечает за управление D3D девайсом(установка стейтов, вызовы Clear/Present и т.д.) и сцена(элемент движка) которая работает только с объектами(создает списки на рендер, вызывает их методы Render). Принципиально их можно объединить, но мне так удобней, так как субординация еще более жесче.
Страницы: 1 вся ветка
Форум: "Игры";
Текущий архив: 2004.05.23;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.041 c