Привет всем.
Заранее извиняюсь за слишком большое чтиво. : \
Эпизод I. Предисловие.
И опять, я создал тему здесь, чтобы здесь обсудить архитектуру игрвого движка, а точнее её проектирование. Мне НЕ нужны всякие пейперы, посылы в гугл, левые не относящиеся к теме советы. Давайте поговорим о структуре игрового движка.
=====================================================================
Эпизод II. Постановка проблемы.
Итак, начну с описания ситуации:
Я написал графический движок. Он не супер мощный и не со всеми ультрамодными эффектами, шейдерами и прочим.. Обычный, пока ещё довольно таки простой движок. Тоесть графика у меня есть.
Вдоволь "наигравшись" с ним я теперь всерьёз настроен сделать на нём 3D игру (а именно Horror-action. Жанр не придуман сейчас на ходу - идея игры есть, игра вдоль и поперёк продумана уже мною, сюжет понравится довольно таки большому количеству людей, сюжет оригинален - таких фильмов и игр не видел ещё, однако также ни чего революционного.).
Итак для создания игры мне нужно:
1. Графика
2. Физика
3. Ввод
4. Звук
5. Tools (типа редактора уровней, энтитей, можелей и т.д.)
Всё кроме физики у меня есть - самописное. Я решил что я хоть и сумасшедший, но не настолько, чтоб писать ещё и физ. двиг, поэтому юзаю ODE.
Вот мы и подошли к сути: теперь мне нужно всё это (графику, физику и т.д.) объединить в ИГРОВОЙ движок.
Над его структурой в полную силу думаю с вчерашнего дня. Много идей мелькает в голове, но вследствие отсутствия опыта создания ИГРОВОГО двига, я не могу остановиться на одной из них. Поэтому прощу мне помочь в этом, помочь мне выбрать и поделиться своим опытом.
=====================================================================
Эпизод III. It has began...
Как я себе представляю игровой двиг:
Это нечто, которое:
1. Создаёт игровые сущности и удаляет их.
2. загружает игровые миры с файлов (имеется ввиду файл уровня грузим)
3. связывает графическое представление сущности с физическим.
4. связывает Entity и AI
5. Обрабатывает игровую логику.
далее спорные моменты, которые я не могу решить:
что есть Entity? Это игрок, триггер, стул.. а стена, она Entity? Я имею ввиду обычную стену, которая тупо является Solid объектом и всё! В ней нет игровой логики. Она к чему относится? если не она Entity, то что? И в каком виде хранить? Хранить в игрвом двиге или достаточно засунуть в физический и графический?
вот я гружу ща Entity класса Player.. Entity player = EntityFactory.LoadEntity("блаблабла.xml");
а как мне стену грузить? она вроде не Entity.. тогда мне её не учитывать в игровом двиге?
Ещё задача:
у меня в ГРАФИЧЕСКОМ двиге есть камера.. ей можно свободно управлять, и вот мне для CutScene понадобится тоже камера... в игрвом двиге. Тоесть мне опять класс Camera обворачивать ещё одним классом Camera а стену обворачивать ещё одним классов StaticEntity?
Ещё: у меня есть класс сцены в граф двиге.. получается мне нужно делать опять класс сцены в игровом?
Вообщем меня настораживает то, что нужно писать обёртки для классов.
пока что я вижу структуру игрвого двига так:
CGameEngine: CreateGameWindow(), LoadWorld(), CreateEmptyWorld(), DestroyWorld() (эпично xD), Release(), MainLoop()
CEntity: Update(dloat dt), ListenInput(...), Pulse() (AI), от него может наследоваться Entity2D, и другие сущности типа CPlayer
CGameWorld: AddEntity(CEntity entity), DeleteEntity(), Update()
CEntityFactory: LoadEntity(), SaveEntity(сохраняем всё в XML файл), что ещё?
Дополните, пожалуйста.
К меня не возникло желания выйти после пп1-4, соответственно отпишусь.
Сразу вопрос - что есть сцена в рендере? Куча объекто с разными свойствами материалов и тп? Т.е. просто список всех объектов, которые рендерятся? Тогда да, нужно иметь игровую сцену, в которой собраны ентети.
По сути должно быть так, (ИМХО:):
-Любой объект в игре ентити.
-Ентити колектит в себе физику, графику, игровую логику и т.д. Если какой-либо части не надо (скайбоксу ни логики, ни физике не надо), то ее и нет.
-На уровне игры взаимодействие идет только с ентитями, ни чем иным.
-Ентити связаны в дерево. Корень - игра.
>CEntity: Update(dloat dt), ListenInput(...), Pulse() (AI)
В корне не верно. Ентити только апдейтится. Т.к. ентети - является коллекцией разных логических частей объекта, то логично сделать следующим образом. В момент апдейта из CGameWorldEntity зовем апдейт всех детей. У них происходит следующее
Получить координаты физ. представления и сделать их текущими, спустить их в рендер и во все сущности, которым это надо (можно из рендер сущности спрашивать координаты владеющей ей ентити, но это получается перекрестное знание объектов друг о друге, что неправославно). Апдейтим игровое представление ентети - если это наш игрок, то внутри спрашиваем контролы и т.п., если НПЦ, то апдейтим аи. На основании апдейта игрового представления отдаем команды в физ представление и еще куда надо.
В общем случае идея понятна, я надеюсь. Попробуй в такой схеме написать что-нить совсем простое. Там вылезут косяки архитектурные, будешь фиксить;)
L
Зря ты эту тему создал
Сейчас прибежит куча деятелей, и начнут спорить о преимуществах и недостатках онанизма правой и левой рукой
И каждый будет прав.
Hawk
> Сразу вопрос - что есть сцена в рендере? Куча объекто с разными свойствами
> материалов и тп? Т.е. просто список всех объектов, которые рендерятся?
нет сцена хранит всякие настройки сцены, террайн, небо, окиян и сценеграф с остальными объектами. В сценеграфе объекты являюзся узлами сцены. Узлы могут быть дочерними узлами другого узла или иметь свои дочерние узлы. Собсно их трансформация так и объявляется - иерархически.
Hawk
> В корне не верно. Ентити только апдейтится.
да, действительно, спасибо.. я вот тут думаю, как быть с инпутом... у меня чтобы работал инпут нужно Entity унаследовать от интерфейса IInputListener,
потом в инпуте зарегистрировать слушателя и раелизовать метод ListenInput(...) при нажатии кнопки или движении мыши, внутри энтити вызывается эта функция , через которую я могу прочитать кнопки и сдвиг осей мыши.
И вот проблема: когда юзер нажиает кнопку W, Character должен пройти вперёд, а на сколько?? у меня скорость движения перса установена как 0.5 метра/сек.. значит мне нужно знать TimeElapsed между кадрафи (грубо говоря ФПС нужно знать) чтобы рассчитать на сколько вперёд пройти! Как это хэндлить?
Первое самое просто что пришло в голову: при обновлении системы ввода, передавать в неё и DeltaTime и когда она какому либо слушателю передаёт нажатые кнопки, передавать и DT. Как вам?
Hawk
> Там вылезут косяки архитектурные, будешь фиксить;)
гы, так я и пишу здесь, чтоб побольше узнать и поменьше потом фиксить (ой, мне хватило переписываний в граф двиге!)
Nikopol
да ничо, надеюсь хоть какуюто часть отправил назад предисловием а с остальной.. ну что ж, в споре рождается истина, как грится...
ахаха, левой лучше - развивается правое полушарие мозга! Развивается творческий потенциал гвахаха %)
игровое приложение это система работающая с множеством объектов, причем многие из этих объектов повторяются. значит для начала нужен счетчик ссылок :)
почему ОДЕ?
redbox
>игровое приложение это система работающая с множеством объектов, причем многие из этих объектов повторяются. значит для начала нужен счетчик ссылок :)
В игре каждый объект уникален. В рендере нет. Если рендер написан нормально, то счетчик ссыло нужен там. Ну и в других системах, которые отдают ресурсы, не больше.
L
>И вот проблема: когда юзер нажиает кнопку W, Character должен пройти вперёд, а на сколько?? у меня скорость движения перса установена как 0.5 метра/сек.. значит мне нужно знать TimeElapsed между кадрафи (грубо >говоря ФПС нужно знать) чтобы рассчитать на сколько вперёд пройти! Как это хэндлить?
На апдейте плеера опрашиваешь подсистему ввода, на основании нажатых клавиш/поврнутой мыши строишь вектор скорости и скорость вращения. Отдаешь в физику. Все! За этим-то физика и нужна:) Никаких времен кадра, никакого геморроя. Просто достаточно в начале следующего фрейма взять координаты у физ представления.
L
>гы, так я и пишу здесь, чтоб побольше узнать и поменьше потом фиксить (ой, мне хватило переписываний в граф двиге!)
всего сразу не удумаешь, иначе б была отличная дока "Как дизайнить игровой двиг, чтоб всем было зае.. хорошо!" Каждая система пишется с учетом потребностей, ограничений и т.п. Возможно в движке, который должен держать 10000 юнитов в кадре никакая физика и не нужна (ну это я абстрактно)
Правко: послания адресованы
Сори, пришлось писать ищо раз.
L
>В сценеграфе объекты являюзся узлами сцены. Узлы могут быть дочерними узлами другого узла или иметь свои дочерние узлы. Собсно их трансформация так и объявляется - иерархически.
Иерархия ток для партикл системов нужна, да для объектов, которые не имеют физического представления. Всем другим рулит именно физика сцены.
redbox
> игровое приложение это система работающая с множеством объектов, причем многие
> из этих объектов повторяются. значит для начала нужен счетчик ссылок :)
ну эт слишком понятно чтоб спрашивать.. вот я и не спрашивал : )
redbox
> почему ОДЕ?
потомучто C#, а Newton юзал - не понравился а PhysX к сожалению нету нормального враппера.. все мега старые!! Если располагаете новым или знаете где его найти - то поделитесь, буду премного благодарен.
Hawk
> На апдейте плеера опрашиваешь подсистему ввода, на основании нажатых
> клавиш/поврнутой мыши строишь вектор скорости и скорость вращения. Отдаешь в
> физику. Все! За этим-то физика и нужна:) Никаких времен кадра, никакого
> геморроя. Просто достаточно в начале следующего фрейма взять координаты у физ
> представления.
а, блин, ну да.. я ж физдвиг отдельно апдейтю.. он и посчитает сам : )
Hawk
> Иерархия ток для партикл системов нужна, да для объектов, которые не имеют
> физического представления. Всем другим рулит именно физика сцены.
ну вот предположим едит горящая машина! Она является также физическим объектом! но к ней нужно прицепить партикл. и А теперь вопрос, если ты говоришь, что объекты, ИМЕЮЩИЕ физ. представление, НЕ должны быть в сценеграфе, то как я прицеплю систему частиц к этому объекту?
L
> ну вот предположим едит горящая машина! Она является также физическим
> объектом! но к ней нужно прицепить партикл. и А теперь вопрос, если ты
> говоришь, что объекты, ИМЕЮЩИЕ физ. представление, НЕ должны быть в сценеграфе,
> то как я прицеплю систему частиц к этому объекту?
Дык он вроде и сказал что иерархия для партиклов НУЖНА :))
Нод к которому прицеплена машина, и его потомок - нод к которому прицеплен эмитттер, или даже несколько. Так как кроме партиклов наверянка к такой машинке ещё понадобится прицепить что-нить, например истоники света для фар и освещения "огнём" всего вокруг, источник звука горяшего пламени если у тебя звук 3д... конечно это должно быть в сценеграфе рендера/звукового движка, но это всё не надо пихать в физику, так как всё это просто привязано к машине и не имеет физического представления можно сказать что "горящая машина" это игровой объект, а привязанные к нему партиклы, истоники света, звуки и прочее это своего рода атрибуты описывающие каким образом этот игровой объект будет представлен игроку. Вроде об этом Hawk тебе и говорит
L
> LoadWorld(), CreateEmptyWorld()
второе заменяется первым, это позволит просто настраивать шаблон пустого мира, добавлять в него все необходимые базовые объекты без изменений кода, и вообще написания этой ненужной функции.
L
> CEntity: Update(dloat dt), ListenInput(...), Pulse() (AI),
тут тоже ощущение что одно и тоже описано разными словами, чтобы список не выглядел таким пустым.
Не бойся простой структуры. Простота это плюс а не минус движка. L
И еще у тебя список методов класса Engine:
> LoadWorld(), CreateEmptyWorld(), DestroyWorld()
а если у тебя еще есть отдельный класс World то зачем его методы отдаешь классу Engine?
Megabyte-Ceercop
> LoadWorld(), CreateEmptyWorld()
> второе заменяется первым, это позволит просто настраивать шаблон пустого мира,
> добавлять в него все необходимые базовые объекты без изменений кода, и вообще
> написания этой ненужной функции.
да, спасибо, снёс 2
Megabyte-Ceercop
> тут тоже ощущение что одно и тоже описано разными словами, чтобы список не
> выглядел таким пустым.
> Не бойся простой структуры. Простота это плюс а не минус движка.
а эт уже давно убрал.. (мне выше сказали)
Megabyte-Ceercop
> а если у тебя еще есть отдельный класс World то зачем его методы отдаешь классу
> Engine?
а чем ему ещё заниматься? : ) у меня сейчас движок что делает: CreateGameWindow(...), SetCustomWindow(это например игра внутри редактора), инициализирует подсистемы, апдейтит подсистемы и World.. + есть MainLoop в котором выполняется игровой цикл до посинения выхода из программы.
L
мне нравится система примененная в Unity.
есть GameObject - просто контейнер для компонентов (List<Component> говоря на C#)
есть Componentы - графические, физические, логические, сетевые. Componentы соединяются между собой входами и выходами.
Весь "игровой мир" - просто список (или дерево) GameObjectов.
Ну и есть конечно mainloop, в котором делаются апдейты графики, физики, звука, логики и т.д.
В целом банально, зато работает.
L
> что есть Entity?
Так используй наследование же. целая иерархия получится.
Грубо говоря так:
Совсем общая абстрактная ентити
Статический объект | Существо | Транспорт
|
Игрок | Монстр | NPC
Стена тоже ентети, статическая.
> а как мне стену грузить?
Что из разных классов то одно за другим,
А иерархию рекурсивным спуском.
Ну и используй сразу Компоновщик для ентети.
P.S. Голосую за пункт 1.
Зачем mainloop???
Гораздо проще в цикле делать обновления
while(Game.Update( )){};
Тема в архиве.