Фэндом

Виртуальная лаборатория

Гибкая архитектура игр

204 622статьи на
этой вики
Добавить новую страницу
Обсуждение18 Поделиться

Это заглавная страница коллективного проекта Гибкая архитектура игр

К проекту может присоединиться каждый желающий, взяв на себя некоторые обязательства помочь целям проекта. Для этого поставьте ниже шаблон {{Участник проекта}} и приступайте к работе :).

Обсуждение проекта участниками идет на этой странице. Организационные вопросы и замечания, поправки тех, кто не участвует в проекте, вносите на страницу Обсуждение:Гибкая архитектура игр'.

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


Участник проекта Сергей Яковлев, 01.03.2009 - 01.08.2009

Участник проекта Андрей Пальцев, 01.03.2009 - 01.08.2009

Участник проекта Михаил Нетов, 02.03.2009 - 01.08.2009

Участник проекта Avice, 03.03.2009 - 01.08.2009


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

Постановка задачи Править

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

Условия разработки Править

XNA инструменты Править

  • Microsoft XNA Game Studio 3.0 - это самое то что надо !!!! Ищу любую полезную РУССКОЯЗЫЧНУЮ литературу, примеры и открытый код игр ... Кто знает выклыдывайте прямо здесь S.J. 21:19, 3 марта 2009 (UTC)
  1. cайт сообщества русских XNA разработчиков
  2. еще один сайт XNA разработчиков
  3. Замечательные примеры с открытым кодом
  4. Видео-доклады по созданию игр
  • Вот надо обратить внимание на инструменты, которыми собираются пользоваться одна из групп по разработки игр [1]

Примеры работы с Microsoft Robotics Studio Править

  • Здесь выкладываем все, что известно про Microsoft Robotics Studio ... приветствуется русский язык и наличие кода .. S.J. 15:36, 9 марта 2009 (UTC)
  1. Видео-доклады

Обсуждение Править

  • Обратите внимание !!! Я перенес часть дискусии связанной с организационными вопросами на страницу обсуждения данной статьи ! S.J. 10:26, 3 марта 2009 (UTC)

avice 19:30, 8 марта 2009 (UTC)

  • Хотелось бы получить ответ на такие вопросы :
  1. Каким видят участники проекта конечный продукт по степени сложности в использовании? Будет ли это похоже на "конструкторы" двумерных и трехмерных игр, которых уже существует немало, или какие аналогии можно привести? Для меня этот вопрос полностью неясен.
  2. Будем ли мы уделять главное внимание быстродействию при отрисовке графических сцен, при сетевом взаимодействии и т.п. - а это весьма важные показатели при создании игр - или на первом месте должны быть другие приоритеты? Какие?
  3. И как результирующий первые два вопроса - будем ли мы делать продукт для быстрого изготовления только урезанно-демонстрационных, или по возможности высококачественных игр?
  • Полагаю, что на эти вопросы весьма важно ответить, т.к. они повлияют на многие принимаемые решения....
  1. Незнаю, правильно ли я понял вопрос, но сложности в использовании вообще не должно быть - пользователь должен максимально просто использовать результат наше деятельности. Конструкторы - думаю это лишь малая часть того, что мы здесь задумали, хотя иметь конструктор как в игре Spore я бы не отказался (есть то може они и есть, но не с открытым кодом, и сделанны по совершенно не гибкой архитектуре)
  2. Красивая графика и ее быстродействие - это конечно хорошо, и никто с этим не спорит. Но это лишь один из критериев, я бы сказал это фон игры, а не сама игра. Наибольшое внимание нужно уделять разработки технологии сбалансированных игр (именно в такие интересно играть, даже без графики и с тормозами). Т.е. технически эти критерии не должны противоречить общей архитектуре, которая как вынесенно в заголовок должна быть универсальной и гибкой. Но разумные компромисы - это и есть искусство программирования ... поэтому здесь приоритет Вам - есть идеи, примеры - прошу покажите и объясните, чем по вашему мы должны жертвовать во имя этого ...
  3. Здесь совершенно не зачем выбирать, конечно вначале это будут демо-зарисовки, но они должны вырасти в высококачественную технологию создания игр (и соответственно ряд конкретных шлягерных игр :) ) ... Я препочитаю технику эволюционирования - вначале есть плохой код, который хоть что-то но делает, но постепенно он развивается и становится законадателем моды :) S.J. 21:08, 8 марта 2009 (UTC)
  • В целом Вы ответили на мои вопросы, детальнее я разверну свое видение чуть позже... avice 21:20, 8 марта 2009 (UTC)

От слов к делу Править

Я уже начал рисовать UML-диаграмы, скоро выложу результаты первой прикидки .. S.J. 23:16, 5 марта 2009 (UTC)

Ну, вообщем базовые основы спроектированы, только что-то все пропали :( S.J. 18:16, 8 марта 2009 (UTC)

Общие положения Править

Microsoft Robotics Studio как движок физики Править

  • Думаю достаточно перспективным использовать данный инструмент, во-первых, он совместим с XNA - и может использоваться в играх, во - вторых, он может использоваться в реальных симуляциях - что игру превращает в иследовательскую деятельность ... S.J. 15:39, 9 марта 2009 (UTC)

UpReal 06:14, 25 марта 2009 (UTC) Для XNA рекомендуют использовать движок физики PhysX от компании nVidia. Достоинство - более точное моделирование и использование графического процессора для ускорения расчетов. Недостаток - бесплатное использование только в личных и исследовательских целях. Коммерческое использование, только после согласования с nVidia.

Другие движки физики:

ODE - легкий и компактный движок физики с исходными текстами. Недостаток - managed обертка сделана сторонними разработчиками и не всегда актуальна к текущей версии ODE. Так как в ODE основное внимание уделено быстродействию, то интегрирование происходит с небольшими ошибками и возможны не прогнозируемые движения и возникновение случайных сил. Применяют в основном в играх, где абсолютная точность физических движений не так важна (пример - С.Т.А.Л.К.Е.Р).

Newton - свободный движок без исходных текстов. Устойчивее чем ODE. Но и медленнее работает.

  • Я, конечно понимаю, что Microsoft Robotics Studio ориентированно на более сложно применение и скорее для исследований (что субъективно нужно мне и Михаилу Нетову) - и делать игру в имеющейся среде симуляции, надо иметь крепкие нервы, хотя думаю нет ничего не возможного и вполне реально, там даже есть достаточно интересные приемы и функции. НО просто для игр это может быть лишним усложнением ... но все же мы я думаю хотели бы иметь гибкую архитектуру, и было бы соверщенно не лишним, чтобы как минимум от движка архитектура не зависила бы ... но детали все-же будут отличаться, поэтому на первых порах хорошо бы, что мы ориентировались на какой-то один движок, а потом при желании подключали бы разные движки .. Так вот движок применяемый в Microsoft Robotics Studio - это Microsoft.Robotics.Simulation.Physics ... думаю он ни чем не хуже прочих, а наверняка в чем-то лучше, т.к. нацелен на настоящие моделирование, а не только для игр .. он так же совместим с XNA .. и думаю есть родственные связи с PhysX ... исходя из этого почему бы не остановится на нем ? Какие у него есть недостатки ? S.J. 07:10, 25 марта 2009 (UTC)
  • PhysX от компании nVidia - количество примеров конечно впечатляет ... Но все они на С++, что несколько все же низко уровнево ... хотеось бы чего то более интеллектуального для С# ... возможно для реализации каких-то нестандартных вещей это не плохо, но сравнительно в Microsoft Robotics Studio - мне вообще не пришлось думать о физики, задача состояла только поместить объект в среду моделирования, а там физика уже и так есть (т.е. о ее реализации думать не приходилось, конечно это может быть для уже имеющихся элементов, а со своими прейдется повозится, но все же не на С++) ... S.J. 07:36, 25 марта 2009 (UTC)

UpReal 13:31, 26 марта 2009 (UTC) Для чего нужен движок физики. Обычно на него возлагаются следующие задачи.

1. Определение коллизий. Это для того, что бы один объект не попал внутрь другого. Реализация границ объектов. Самый быстрый способ - у каждого объекта имеется невидимый ящик-контейнер - который и принимает участие в расчетах столкновений. Самый медленный способ - полигональная сетка объекта участвует в расчетах столкновений. Данная часть физического движка необходима во всех применениях и может быть самостоятельной задачей.

2. Расчет движения объекта с учетом его физических характеристик и приложенных сил. Возникновение новых сил и движений в результате столкновений и коллизий. Применяется для анимации поведения объектов по результатам расчетов. Наиболее полно применяется при разработке симуляторов. Эта часть зависит от типа игры.

Языковая среда программирования. Править

C#, VB.net

Достоинства: современная архитекрура среды программирования и выпонения. Что относят к недостаткам:

1. Быстродействие. В современной игре только 10-15% процессорного времени тратится на выполнение програмного кода. Остальное время тратится на отображение сцены и рендеринг. А это происходит на уровне DirectX. Если использовать в С++ все возможности C# (умные указатели, сборка мусора, отражения и т.д) то быстродействие программы будет примерно одинаковое.

2. Все сторонние модули написаны на С++. Решается с помощью классов-оберток на managed C++ и не представляет особых трудностей.

3. Сборка мусора. Решается с помощью культуры программирования критичного кода (с помощью using на пример).

4. Серверная часть может выполняться в среде Mono для Linux платформ.

Вывод: Нет критичной причины для отказа от среды .NET UpReal 16:33, 1 марта 2009 (UTC)

Концепция сервера Править

  • S.J. 16:39, 1 марта 2009 (UTC) Согласен, но есть такой аргумент

avice Есть проблема - серверная часть практически всегда располагается на Linux либо FreeBSD, где C#, увы, неуместен.... Полагаю, этот момент не критичен - применение С++ на серверной стороне ?

UpReal 16:53, 1 марта 2009 (UTC) Серверная часть вполне может выполняться и в среде Mono для Linux платформ.

По быстродействию ни чем не хуже C++. а по надежности гораздо выше. Что для сервера является определяющим. Тем более основное время на сервере тратися на обслуживание MySQL или запись текущих состояний во временные файлы.

--avice 17:46, 1 марта 2009 (UTC) Со средой mono до сего дня был не знаком. Не уверен что по быстродействию он близок к С++, но по надежности - наверняка гораздо выше, а это ИМХО гораздо важнее. Поэтому с удовольствием займусь ознакомлением с этой средой. Также надеюсь на вашу помощь в первоначальном освоении mono...

UpReal 18:03, 1 марта 2009 (UTC) Освоение mono это скорее задача сисадмина. С точки зрения программиста разница не существенна и вполне возможно создание кросс-платформенного приложения. На сегодня, единственное требование - использование FrameWork не выше 2.0.

  • Хорошо, что есть среда Mono, но не зная о ней я кое что подумал ... Поэтому первое, что я подумал, что для сервера лучше было бы программировать на Яве, чем на С++. Потом вспомнил, что я говорил avice`у - предполагая, что сервер должен выполнять основную массу расчетов. В итоге я пришел к выводу что тонкий клиент - это плохо. Нам нужен толстый клиент, т.е. такой, который может спокойно работать без сервера и у которого есть для этого вся логика, а сервер должен выполнять лишь подчиненную роль регистрации новых участников в сети, после чего передавать эту информацию клиенту и клиент работает уже самостоятельно (на прямую) с клиентами участников сети. В чем-то это похоже на скачивание Торрентов (как это делается программно - я не знаю). В итоге тогда имеем:
  1. Для сетевых игр - сервер как дополнительную библиотеку
  2. Такая отдельная библиотека может быть на любом языке, но ограничемся двумя вариантами: 1. С# + Mono 2. Java
  3. С клиентской стороны стоит адаптер сетевых участников, который принимает сигналы от сервера, на наличие соединится/рассоединится с другими клиентами, сам с ними соединяется и приводит информацию к такому формату (классам) как она используется в однопользовательской игре. Т.е. Для всей основной массы кода нет разницы с какими объектами работать из сети или нет. Этим мы предотвращаем то, что код связанный с сетью не будет раскидан по всей программе.

Согласны ? S.J. 08:16, 2 марта 2009 (UTC)

UpReal 05:48, 3 марта 2009 (UTC)

В обычной практике создания online игр применяют систему тостого клиента и тонкого сервера. Исключение пожалуй только SecondLife (OpenSim). Это связано с тем что большая нагрузка на сервер со стороны клиентов. На стороне клиента решаются следующие задачи: отображение мира, расчет физики, проверка столкновений. Т.е. задачи ресурсоемкие. На стороне сервера: Проверка корректности работы клиента (грубая проверка физики и столкновений для защиты от подмены логики работы клиента), Фиксация состояния всех участников игры для информирования клиентов. Транзакция критических состояний на SQL сервере (состояний существенных с точки зрения гейм-плэя). И даже при такой архитектуре сервера тяжело добиться одновременного обслуживания порядка 1000 клиентов.

А как насчет того, чтобы сделать его ЕЩЕ тоньше как я описал выше, т.е. без "Проверка корректности работы клиента (грубая проверка физики и столкновений для защиты от подмены логики работы клиента), Фиксация состояния всех участников игры для информирования клиентов." ... про SQL сервер поговорим потом отдельно ... Возможно тогда это удасться не так тяжело обслуживать 1000 клиентов ... S.J. 10:16, 3 марта 2009 (UTC)

avice 18:56, 8 марта 2009 (UTC)

  • "Обслуживание свыше тысячи клиентов" - весьма условное понятие... Главный тормоз здесь - не только и не столько работа с БД и файлами, как работа в реальной сети... Сервер на С++ легко может обслуживать 50 соединений в секунду - много это или мало? Зависит от многих вещей... например, это реал-тайм шутер, или пошаговая стратегия... Полагаю, тема обслуживания требует более подробного разбора..
  • Пока оптимальная схема сервера видится мне так: Центральный логин-сервер + группа рабочих серверов + группа серверов по работе с БД... Это - в общем виде... Данная схема должна позволить обслуживать неограниченное количество игроков...

UpReal 11:28, 3 марта 2009 (UTC) Проверка необходима по закону онлайн миров - "клиент - это ваш враг, если что-то может быть сделано не коректно - это будет сделано". Так что код клиента надо рассматривать как потенциальную угрозу. Всегда можно подменить клиента или написать эмулятор клиента.

avice 18:56, 8 марта 2009 (UTC)

  • Да, концепция "Клиент - в руках врага" вполне справедлива. Поэтому, уверен, также не стоит применять схему, аналогичную торренту - где Центральный сервер раздает клиентам их адреса, а они общаются между собой напрямую.
  • Единственно заслуживающей реализации считаю группу схем, при которых все критичные данные (карты и характеристики миров, личные данные игроков и т.п) хранятся на сервере, там же производятся основные расчеты, а на клиенте реализуется в основном визуализирующая часть.
  • А поясните мне почему мы считаем, что "Клиент - в руках врага". Как то это странно, клиента пишем мы, сервер по сути вообще не нужен, если клиенты знают с кем играть ... давайте вообще поставим вопрос так - для чего нам сервер ? Но не для чего он мог бы быть, а именно почему без него нельзя обойтись вообще ?! S.J. 20:52, 8 марта 2009 (UTC)
  • Без сервера вполне можно обойтись - если рассматривать очень общую ситуацию. Работа без центрального сервера - это как один из вариантов реализации. Но - прежде чем обсуждать концепцию сервера, нужно ответить на вопросы в разделе Обсуждение. В зависимости от того, какого класса/типа продукт мы хотим иметь - можно обсуждать плюсы и минусы архитектуры сервера (и не только...)... avice 21:07, 8 марта 2009 (UTC)
  • Почему мы считаем, что "Клиент - в руках врага"? Рассмотрим самую простую ситуацию. Игра-единоборство шашки. В эту игру по определению не могут одновременно играть более двух игроков. Центральный сервер "залогинил" игроков и предоставил им играть, обмениваясь данными по сети напрямую. Один из игроков выиграл, и его клиент послал на Центральный сервер сообщение об этом. Второй игрок проиграл, но он уже успел "усовершенствовать" своего клиента (возможно, посредством внедрения в его память, или другим способом) и его клиент ТОЖЕ отправил на сервер сообщение о том, что он выиграл. Центральный сервер никак не сможет определить достоверность обоих сообщений, т.к. никак не отслеживал промежуточные состояния играющих... Таким образом. чем интереснее игроку играть в некую игру, или чем большие материальные или моральные блага он может извлечь из игры при выигрыше, тем больше усилий игрок приложит к тому, чтобы исказить результаты в свою пользу. В случае с соединением точка-точка ему это будет сделать наиболее просто.... Вот примерно так... avice 21:31, 8 марта 2009 (UTC)
  • Применяется также схема без центрального сервера. В этом случае вся серверная логика имеется у каждого клиента, и соответственно каждый клиент может исполнять роль сервера. Эта схема разгружает сеть и дает возможность принимать участие в игре большому количеству игроков, но вышеуказанная схема подмены достоверных событий желательными - может быть практически гарантированно реализована игроками (при наличии соответствующей квалификации)... avice 21:47, 8 марта 2009 (UTC)
  • Примерно ясно ... Скажем так - думаю голоса у нас разделились поровну с вариантами, толстый клиент, тонкий клиент, и средний клиент. Есть мнение, что все они имеют право на существование, но каждый в своем специфичном случае. Поэтому мы скорее всего должны разработать все ТРИ варианта, обсудить какие когда имеет смысл применять, и зделать замену одного типа на другой - вопросом компоновки (т.е. чтобы общая логика блоков не ответственных за сетевые соединения - ничего бы не знала и не предполагала бы какой-то один тип). Думаю это не столь легко. Но давайте начнем с обсуждения когда что пригодно. Вот это момент "он уже успел "усовершенствовать" своего клиента" мне не очень понятен, т.е. вы предполагаете хакерство и защиту от него ? Но что мешает просто посылать шифрованные сообщения с ключами ... ssl вроде называется ? Чем это не замена с авторизацией у сервера ? S.J. 22:00, 8 марта 2009 (UTC)
  • "Усовершенствовать" своего клиента" игрок может следующим способом. Имея на руках программу-клиент, он имеет полный доступ к ее бинарному коду. Запустив клиента, к примеру, в отладчике, он находит участки памяти, куда пишутся некие важные данные - например, количество денег на его счете, или количество жизней, или еще что-то важное для игрока... Затем пишется программа, "внедряющаяся" в код процесса клиента. И эта программа динамически может изменять требуемые участки памяти для внесения корректировок значений. Соответственно, никакая шифрация сетевого трафика не помогает, т.к. алгоритм работы клиента не меняется, изменяются только некоторые данные, передаваемые клиентом по всем правилам, но тем не менне эти данные уже имеют требуемое игроку значение... Если игрок сам не имеет достаточной квалификации, чтобы создать такую программу по "усовершенствованию" клиента, он может заказать ее. К примеру, на одном из фрилансных сайтов, заплатив от $1000 до $2000... Затем - продавая ее игрокам, он не только вернет затраченные деньги, но и практически "похоронит" саму игру.... Вообще - таких способов много, и пока единственная надежная защита от этого - не предоставлять клиентской программе никакой критически важной информации (информацию эту держать на сервере), при этом периодически производить "сверку" состояний клиента - "внутреннего" и "серверного". При любом отклонении состояния клиента от серверного - клиент считается невалидным и связь с ним разрывается.... Вот примерно так все выглядит... avice 22:57, 8 марта 2009 (UTC)
  • Спасибо, теперь доходчиво ... Но давайте попробуем назвать эту критически важную информацию, что это может быть еще, кроме "денег на его счете, или количество жизней". За этим может стоять любое количество ресурсов, текущий уровень, любое состояние юнитов - вообщем ВСЕ, что каается логики игры. Таким образом, приходится ВСЕ переносить на сервер, а клиента делать просто визуализатором. Т.е. в принципе по принципу "банковских автоматов" - только смотришь и заказываешь, а все остальное на сервере. Для категории игр т.н. "тотализаторов" наверное это может быть защитой, но не удивлюсь что и здесь есть способы, т.к. банковские автоматы частенько взламовают. Поэтому нужно взвешвать критичность той самой информации ... это во-первых. Во-вторых если дело не в сетевом трафике, то еще и лучше - нужно шифровать как раз "участки памяти, куда пишутся некие важные данные", плюс делать данные участки с распределенным хранением, а пару байтов хранить на сервере. Таким образом, клиент становится автономным и зависит только не только от ключа получаемого с сервера, но приходится "критические участки" расшифровывать - итого цена повышается в сотни раз, и становится не окупаемой ... S.J. 00:03, 9 марта 2009 (UTC)
  • И главное мы не просто получаем скорость, мы принципиально получаем возможность играть в однопользовательскую игру (в этом режиме можно вообще ничего не шифровать), а это тоже не малый процент всех желаний. Мне вообще было бы странно играть в игру, в которую я не могу поиграть с ИИ, и когда сеть мне вообще не нужна ... S.J. 00:09, 9 марта 2009 (UTC)
  • Еще один доп. способ - нужно сверять код .dll на предмет его изменения, можно не весь выборочно ... а еще лучше перед началом игры заливать с сети определенную .dll изменения в которой критичны, т.е. устранять возможные "усовершенствования" - причем под маркой обновлений :) S.J. 00:23, 9 марта 2009 (UTC)

Концепция модуля Править

UpReal 16:50, 1 марта 2009 (UTC) Модуль - файл типа *.dll содержащий программный код и/или ресурсы (Shaider, texture, mesh, animation ...) публичные классы модуля имеют унифицированные интерфейсы определяющие принадлежность модуля определенному классу модулей. На пример. Модуль - 'камера от первого лица' и модуль 'камера вида с верху' имеют общий интерфейс типа ICamera.

Интерфейсы модулей Править

  • Это не правомерное понятие. Под интерфейсом нужно однозначно понимать конструкцию interface (в данном случае C#). Она относится к классам, а не модулям. Поэтому речь должна идти о общих интерфейсах, которые должны быть реализованы однотипными классами. И совершенно отдельный вопрос как эти классы будут сгруппированны по модулям. Делать мелкие модули - не правомерно, модули должны представлять собой законченную часть предметной области или содержать библиотеку однотипных элементов. S.J. 10:45, 3 марта 2009 (UTC)

UpReal 11:13, 3 марта 2009 (UTC)

В .NET есть такое понятие как много-модульная сборка. Это когда несколько модулей объединяются в один файл. Так что модуль может быть файлом *.dll или входить в состав другого файла *.dll. Так что я скорее понимаю под модулем функциональную сущьность реализующую публичные интерфейсы. Связывание модулей будет происходить на уровне интерфейсов. Так как они более стабильны по своей структуре, в отличии от классов их реализующих. От сюда вытекает необходимость разработки и спецификации интерфейсов. Кстати, публичные интерфейсы можно упаковать в отдельную сборку для контроля версии реализации.

  • Что-то я не понимаю о чем Вы ... Есть два понятия "решение" (Solution, файл с расширение .sln) и проект (Project, файл с расширение .csproj). Решение как правило включает в себя несколько проектов, один из которых считается StartUp. Как они собираются по сути не важно - это могут быть как .exe или как .dll . Каждый из них состоит из классов и все ! Понятия модуля как такового ВООБЩЕ нет ! По привычки люди называют модулем разные вещи - и я не пойму что именно вы таким считаете. Желательно вообще не употреблять это слово. Если Вы говорите о public классах и их членах - то так и говорите, но это не интерфейс в собственном смысле слова. Слово интерфейс без уточнений мы должны оставить за конструкцией interface. В противном случае мы запутаемся и будем говорить о разном ... S.J. 12:55, 3 марта 2009 (UTC)
  • Еще раз давайте разделим вопрос на два, т.к. они мало связанные 1. Каким образом разрабатывать интерфейсы, реализуемые классами и 2. Каким образом группировать классы по проектам (.dll библиотекам) S.J. 13:00, 3 марта 2009 (UTC)

UpReal 13:35, 3 марта 2009 (UTC) Для уточнения Архитектуры программного проекта.

У нас есть исходный код Interface.cs, который содежит следующее:

public interface ICool 
{
  bool IsCool { get; }
}

Его мы вставляем в проект Interfaces.csproj - с компиляцией в Interfaces.dll. Доблестно компилируем и получаем файл Interfaces.dll.

Далее это можно использовать при разработке других *.dll. Скажем разрабатываем SuperCool.dll c с файлом SuperPuper.cs. Устанавливаем References -> Interfaces.dll. Все, исходный текст Interfaces.cs нам больше не нужен! Чтоб не по-портить его нечаянно.

class SuperPuper : ICool 
{
  bool IsCool 
  { 
     get { return true; } 
  }
}

После компиляции проекта мы получим SuperCool.dll. В этой SuperCool.dll мы Абсолютно точно уверены и можем всегда проверить, что существует класс реализующий интерфейс ICool. Больше нам ни чего знать не надо и вредно знать. На пример, что реализующий класс называется SuperPuper - его разработчик может в любой момент поменять и проект от этого не развалится. При такой технологии программирования сборки могут разрабатываться независимо и без знания внутренней структуры других частей программы. Архитектура программы и взаимосвязи выносятся на уровень интерфейсов - это единственное, в чем все участники проекта уверены и могут на эти описания полагаться.

В других модулях используются переменные следующих видов ICool myVariable; // А НЕ SuperPuper myVariable;

  • В принципе согласен, даже более того, что-то подобное я и планировал предложить ... но детали еще обдумаю ... весь вопрос на сколько абсолютно следовать данным рекоммендациям ... то, что в большинстве случаев для независимых библиотек это хорошо - это несомненно ... но гарантировать, что не будет исключений, и что так правильно поступать в тесно связанных библиотеках базового ядра/каркаса - есть сомнения ... но тут уже нужно детализировать дальше ... Другой вопрос - интерфейсы тоже изменяются, фиксировать их как это принято в идеологии COM - это все же идеализация, и тянет за сабой бороду старого кода - тут нужно поступать в соответствии со здравым смыслом ... Но еще раз повторю как рекоммендация по умолчанию - это хороший принцип, и без наличия причин от него отходить не следует .. S.J. 14:54, 3 марта 2009 (UTC)
  • Эта технология применяется для получения гибкости программного продукта и изолирования частей кода между собой.

Как абсолют конечно применять не стоит. Чаще всего монолитные конструкции всегда возможно разделить на части и изолировать друг от друга с помощью интерфейсов. Спецификация интерфейсов, как раз и является областью деятельности архитектора программного комплекса. Он разрабатывает интерфейсы на основании потребностей программистов во взаимодействии частей программы. Я не прошу разработать UML-диаграммы, хватит и простого обсуждения структуры интерфейсов. UpReal 16:28, 3 марта 2009 (UTC)

  • Как дойдет дело я именно возьмусь за UML-диаграммы. В таком крайнем применении интерфейсов все же есть проблема, скажем есть у нас третья библиотека (.dll с соответствующим проектом), где мы хотим использовать ICool myVariable, но его надо прежде создать, т.е. сделать new, и это создание не может быть созданием интерфеса, нужно получить интерфейс от реального объекта класса, например, ICool myVariable = (ICool) new SuperPuper(); В итоге приходим к тому же самому - надо знать что такое SuperPuper, т.е. этом классу мы не сможем поставить internal. Конечно есть ряд выходов из положения, скажем иметь в ядре Менеджер, которого мы и будем просить предоставить интерфейс ICool, и уже его задачей будет решать от какого реального класса нужно создать этот интерфейс ... но тогда ряд классов будет пользоваться менеджером как классом, а не интерфейсом, а сам менеджер вообще не будет пользоваться интерфейсами в обсуждаемом смысле ... S.J. 11:12, 4 марта 2009 (UTC)

UpReal 17:34, 4 марта 2009 (UTC) Создание объекта решается несколькими способами. 1.Фабрикой классов как делалось в COM, В .NET решается с помощью отражения (Reflection) на пример так.

  Assembly asm = Assembly.LoadFrom("SuperCool.Dll");
  foreach (Type type in asm.GetTypes()) {
    if (type.GetInterface(typeof(ICool).Name) != null) {
      myVariable = (ICool)Activator.CreateInstance(type);
      break;
      }
    }

Кстати Ox Game Engine собран именно по этой технологии. Все модули представляют из себя plugin-ы c интерфейсом IGamePlugin. Правда как работать с этой программой я так и не понял. Скомпилировал, посмотрел внутреннее устройство программы и все.

  • Сугубо частный случай - вот поэтому так и нельзя делать всегда, я бы даже сказал вредно для архитектуры ... ладно, дойдет дело обсудим (есть много НО - если в библиотеки такой интерфейс реализуют более одного класса, позднее связывание скорее добавляет ошибки, т.к. компилятор не проверяет, опять же время связывание больше, усложнение на голом месте ... поэтому только в частном случае, а не как правило для архитектуры) ... S.J. 22:00, 4 марта 2009 (UTC)

Движок универсальной логики Править

  • М.Нетов Немного непонятно, что такое движок универсальной логики? Поддерживаются ли произвольные алгоритмы поведения объектов? Могут ли объекты обмениваться информацией? Можно ли менять алгоритмы поведения объектов, используя их под-объекты, функции и параметры как фигуранты изменяемых алгоритмов? (Пример: "перемешаться к заданной точке. при ее достижении - взорвать себя.\ходячая бомба\) M.Netov 13:19, 3 марта 2009 (UTC)
  • Детали нужно еще обдумывать, речь идет скорее о Framworke (каркасе на основе событий). Алгоритмы пишите сами или используете уже ряд готовых функций. Набор поведения и обмен информацией - строго по регламенту, как раз выше мы начали обсуждать применение интерфейсов - для этого тоже. Последний вопрос скорее не понимаю, хотя очень хочется ответить НЕТ. S.J. 22:06, 4 марта 2009 (UTC)

Сцена как набор функциональностей Править

  • Предлагаю на рассмотрение следующий вариант организации сцены, да и движка в целом.

И так начнём с базовых сущностей: Поставщик (Provider) – это по сути, то чем объект (функциональность) может поделится с другими. Т.е. это может быть всё что угодно – объект Game, какой-то Effect, все возможные структуры и др.

Потребитель (Consumer) – это то, что нужно объекту для работы.

Вот эти две сущности и предают архитектуре должную универсальность и динамичность. Достигается это тем, что любой объект сцены жёстко не привязан как к самой сцене, так и к другим объектам сцены. Если ему не хватает данных для его работы (т.е. не все потребители данного объекта соединились с нужными поставщиками сцены, в результате их отсутствия) – объект не обрабатывается.

Что же представляет из себя объект сцены – это класс, который унаследован от ф-ти. Ф-ость – базовый класс, реализующий в себе коллекцию поставщиков и потребителей. В классе наследнике, мы создаём нужные поставщики и потребители, присваиваем им имена и добавляем в коллекцию – всё объект готов принять участие в сцене.

Помимо ф-ти, есть ещё и комплексная ф-ть. Она может содержать в себе как просто ф-ти, так и комплексные ф-ти , образуя этим иерархию объектов. Как и обычная ф-ть, она имеет коллекцию поставщиков и потребителей. Также имеет три виртуальных метода Init(), Update(), Draw(). Сцена наследуется непосредственно от неё. Также от неё могут наследоваться и др. объекты, а может просто использоваться как пустой уровень.

Осталось расписать, как и по каким принципам происходит подключение и отключение ф-тей, но на данном этапе, думаю, этого делать не стоит. Здесь есть достаточно информации, что бы понять основную концепцию и сделать определённые выводы о предлагаемом подходе.

Участник:-Sell-

  • В такого птичьего полета - видно пока следующие: нет ни какого смысла чисто терминологически разделять два понятия на "Поставщик" и "Потребитель" - все это по сути "Сущности" (Entity), а вот то как они агрегируют други друга и показывает кто, как и зачем, и насколько независимо друг друга используют. Таким образом понятно, что все классы должны быть унаследованны от базового Entity - это соответствует "объект сцены – это класс, который унаследован от ф-ти". (Все это хорошо согласуется с подходом принятым в Microsoft Robotics Studio)

Далее "Ф-ость – базовый класс, реализующий в себе коллекцию поставщиков и потребителей." - вот в это думаю есть ошибка проектирования, но тут нужны детали, что вы под этим подразумевали - поэтому подожду диаграмм UML. Хотя следующая фраза выглядит уже лучше "В классе наследнике, мы создаём нужные поставщики и потребители, присваиваем им имена и добавляем в коллекцию" - т.е. это близко по смыслу к компонентной модели - но повторюсь нужны детали.

"комплексная ф-ть" - а это уже следствие агрегации и иерархии компонентов, если вы согласитесь на интерпретацию которую я описал выше. виртуальных метода Init(), Update(), Draw() - а тут уже надо сравнивать с тем что я написал здесь UML проектирование гибкой архитектуры игр в первух разделах ... S.J. 06:24, 27 марта 2009 (UTC)

  • UML диаграммы это, конечно, замечательно, но даже если я их представлю, то сравнивать с приведённым подходом, смысла большого нет. Т.к. это уже следующий уровень т.е. камера будет строиться на функциональности. Вместо этого я приведу участки кода, как построить ту же камеру…

Допустим, требуется создать простую сцену, которая будет визуализировать куб (я не буду полностью расписывать код, только главное).

1. Создание сцены:

   //========================================
   public class Scene: ComplexFunctionality
   {
       //------------------------------------
       private DataProvider<Game> _device;
       private DataProvider<GameTime> _time;
       //------------------------------------
       public Scene()
       {
           _device = AddProvider<Game>("Game");
           _time = AddProvider<GameTime>("Time");
       }
       //------------------------------------
       public Game SetGame
       {
           set { _device._value = value; }
       }
       //------------------------------------
       public GameTime SetGameTime
       {
           set { _time._value = value; }
       }
       //------------------------------------
   }
   //========================================

Добавляем два поставщика – объект Game и GameTime. В последствии в сцену могут быть добавлены ф-ти, которым понадобятся эти объекты. Со сценой всё.

2. Камера. Здесь перед разработчиком выбор, можно сделать так, что бы объекты, которые нуждаются в данных от камеры, были не зависимыми от данного класса камеры, или наоборот будут привязаны (плюс в том, что они будут иметь более высокую производительность при добавлении в сцену). Вариант 2:

       public class Camera : Functionality, IUpdate
   	{
       private DataConsumer<Game> _device;
       private DataConsumer<GameTime> _time;
       //------------------------
       private DataProvider<Camera> _camera; 
       //------------------------
       Matrix _view;
       Matrix _projection;
       BoundingFrustum _frustum;
       //------------------------        
       public Camera()
       {
           //----------------------------
           _camera = AddProvider<Camera>("Camera");   
           _device = AddConsumer<Game>("Game", TypeConsumer.Common);
           _time = AddConsumer<Game>("Time", TypeConsumer.Common);
       }         
       public void Update()
       {
           
       }        
   }

У камеры есть два потребителя (это не принципиально) - _device и _time, один поставщик - _camera. При добавлении камеры в сцену, соответствующие поставщики сцены и потребители камеры должны соединиться и у камеры появятся данные нужные ей для работы.

3. Собственно сам игровой объект.

   public class BasicRender : ComplexFunctionality
   {
       //---------------------
       private DataConsumer<Model> _model;
       private DataConsumer<Matrix> _transform;    
       private DataConsumer<Camera> _camera;
       //---------------------
       public BasicRender()
       {
           //-----------------
           _model = AddConsumer<Model>("Model", TypeConsumer.Current);
           //-----------------
           _transform = AddConsumer<Matrix>("MatWorld", TypeConsumer.Common);            
           _camera = AddConsumer<Camera>("Camera", TypeConsumer.Common);
           //-----------------
       }    
       //--------------------- 
       public override void Render()
       {
           var temp = _model.Value;
           foreach (ModelMesh mesh in temp.Meshes)
           {
               //перебираем шейдеры 
               foreach (BasicEffect effect in mesh.Effects)
               {
                   //передаём шейдеру матрицу вида 
                   effect.View = _camera.Value.View;
                   //передаём матрицу проекции 
                   effect.Projection = _camera.Value.Projection;                    
                   effect.World = _transform.Value;
               }
               //рисуем 
               mesh.Draw();
           }
           base.Render();
       }
       //---------------------        
   }
   //-------------------------

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

Напрасно, но хорошо давайте попробуем разобраться без UML. Объясните мне принципиальную разницу между вашим кодом и следующим:

   //========================================
   public class Scene: ComplexFunctionality
   {
       //------------------------------------
       private Game _device;
       private GameTime _time;
       //------------------------------------
       public Scene()
       {
           _device = new Game();
           _time = new GameTime();
       }
       //------------------------------------
       public Game SetGame
       {
           set { _device = value; }
       }
       //------------------------------------
       public GameTime SetGameTime
       {
           set { _time = value; }
       }
       //------------------------------------
   }
   //========================================

Т.е. какой смысл применять обобщения ? Что они дают ? Метод AddProvider - чей он ? И что он делает ? S.J. 19:26, 27 марта 2009 (UTC)

  • Далее думаю вы все таки достаточно мельком посмотрели мои диаграммы, а код навеняка не смотрели вообще :) Поэтому у вас думаю сложилось неправильное предположении о роли предложенной мной архитектуры. Ваш код и мой очень легко сравнивать ... И вот какие проблемы возникают у Вас: Вы не показываете как ваш код разделен на отдельные длл-ки, судя по всему все эти три класса находятся вместе. Отсюда вы не сможете комбинировать - скажем Юнит такой-то сейчас подключен к камере такой-то, я же смогу камеры легко переключать

skinnedManager.Draw(gameTime, camera1Person.View, camera1Person.Projection);

или

skinnedManager.Draw(gameTime, camera3Person.View, camera3Person.Projection);

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

     //передаём шейдеру матрицу вида 
           effect.View = _camera.Value.View;
           //передаём матрицу проекции 
           effect.Projection = _camera.Value.Projection;                    

А вот как тут могут помочь обобщенные классы пока ни как не понятно ...

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

gridManager.Draw(gameTime, camera3Person.View, camera3Person.Projection);

(При этом мне легко сделать массив ArrayList - в котором будут перечисленны все управляемые объекты, т.к. они все наследуются от ProcessorManager и имеют базовые методы, например Draw).

И совсем отдельный вопрос какой именно внешний вид будет у человечка или поверхности по которой он ходит - это решится при присоединении:

Model dudeModel = Dude.Load<Model>("dude"); skinnedManager.Assign(dudeModel);

При этом замедте, что человечек смог выглядеть по другому (конкретизирую внешний вид), видеть по другому (передавая нужные данные камеры) - и при этом код в длл-ки самого человечка не изменился ... тоже относится и к разным видам камер и прочим объектам ... т.е. я реально лишь из главного проекта - комбинирую готовые части без перекомпиляции, т.е. по сути мне и не нужен код этих длл-ок, достаточно ее подключить и сверху настроить их взаимодействие ... S.J. 20:28, 27 марта 2009 (UTC) S.J. 20:28, 27 марта 2009 (UTC)

  • И так по порядку.. Метод AddProvider<> он принадлежит ф-ти.

Ф-сть имеет коллекцию поставщиков(Provider) и потребителей(Consumer). Этот метод создаёт новый экземпляр объекта Provider и под соответствующим именем добавляет его в коллекцию :). А ссылку на объект возвращает. Что же это нам даёт – теперь, когда мы их добавили, другие объекты сцены смогут их увидеть (подключиться к ним, и получать данные).

Что касается камеры и длл.. Вы совершенно верно заметили, жёсткую привязку, но тут никакой проблемы нет. Вариант 1: Создаём абстрактный класс камеры, добавляем нужные свойства, методы общие для всех камер. + Один поставщик “Camera”. Вариант 2: В камере делаем 2 поставщика “View” и “ Projection”. В объектах соответственно 2 потребителя с такими же именами. Всё проблема решена и все довольны :), но чем меньше поставщиков и потребителей, тем быстрее подключается объект.

Камеру смогут использовать сколько угодно объектов, в зависимости от того на какой уровень в сцене мы её поместим. Т.е. мы можем разместить разные камеры на разных уровнях, а объекты будут подключаться на ближайшем к ним уровне. Также можно разместить на одном уровне несколько камер, но участвовать в сцене сможет только одна, остальные в запасе (на одном уровне не может быть два поставщика с одинаковым именем). Если нужно можно будет поменять одну камеру на другую.

Теперь давайте посмотрим, сигнатуру Вашего метода: gridManager.Draw(gameTime, camera3Person.View, camera3Person.Projection); А как быть, если объекту потребуется ещё какие-то данные от камеры или от других объектов? И ещё этот метод жестко привязан к XNA, как бать с DirectX11? Придётся рядом писать такие же классы для других API?

Да и ещё по поводу длл.. Если нужно, можно будет выносить код во сколько угодно длл. Нам только нужно подключить ядро. Возможно, если мы захотим установить жёсткие зависимости от других объектов движка (как в случае с камерой :), то придётся подключать ещё и основную длл движка, в зависимости от к какому объекту привязываем. Я тут даже подумывал физику прикручивать прямо на C++/CLI, не создавая всякие там надстройки. Результат в длл и всё :). Участник: -Sell-


  • Вы можете дать работающий код - чтобы у меня не возникали вопросы ? S.J. 13:41, 28 марта 2009 (UTC)


  • На счёт кода я постараюсь подготовить и выложить на днях. А пока готов ответить на все вопросы :)..

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

Мне, кажется, вы немного путаете Consumer и Provider. Значит, остановимся подробнее на их устройстве: Consumer (Потребитель) – он содержит в себе ссылку на Provider к которому подключён, если не подключён то Null.

Provider(Поставщик) – в свою очередь содержит ссылку на объект(возможно сам объект) подлежащий синхронизации(данные).

При добавлении ф-ти(комп. ф-ти) на уровень(комп. ф-ость), она проходит процедуру подключения, её Consumer-ры подключаются к провайдерам уже имеющимся в сцене(по иерархии снизу в верх). Её Provider-ры добавляются к провайдерам уровня и происходит переподключение ф-тей(комп. ф-тей) по иерархии в низ. Т.е. если консумеры ф-тей подключены к провайдерам более высокого уровня, то они переподключаются. Процедура немного сложная и в этом возможно её минус, если работать с высокими уровнями то есть вероятность кратковременной потери производительности. Лучше формировать дерево сцены постепенно с верху в низ.

Когда мы добавим на какой-то уровень сцены наш BasicRender он будет производить поиск нужных ему провайдеров в зависимости от его консумеров. В данном случае он будет искать провайдер “Camera” и если найдёт, а он его найдёт т.к. такой провайдер предоставит наша камера, то подключится к нему. Соответственно если мы добавим 2-й экземпляр BasicRender-ра его консумер ”Camera”, найдёт и подключится к той же камере. Подключение производится по имени. И все они получат уже готовый объект “Camera”.

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


  • Вы, меня извините, но вы не отвечаете на мои вопросы. Общий смысл я уловил спрашиваю о деталях - вы отвечаете очень не конкретно ... я могу подождать код, тогда пойму без лишних пояснений ... Но сейчас процесс поиска камеры для BasicRender на столько туманный, что под этим можно понимать что угодно (кстати, он все же ищется (!), а не создается как это вы говорили ранее ;) ) ... если бы вы ответили бы более конкретно на мои вопросы хотя что нибудь бы тогда прояснилось :) ... S.J. 18:42, 28 марта 2009 (UTC)
  • Для прояснения ситуации приведу диаграмму классов самого ядра :)… Если можно ещё раз список интересующих Вас вопросов, а то я уже запутался на что отвечать. Попытаюсь отвечать более конкретней.
ClassDiagram1.png

Участник: -Sell-

Могу повторить:

Вопросы Править

1. покажите мне код созданиях объектов Scene, Camera, BasicRender ... это наверняка будет код вида

Scene locScene = new Scene(); Camera locCamera = new Camera(); BasicRender locBasicRender = new BasicRender();

или вы хотите сказать, что и здесь вы сделаете класс, наследуемый от ComplexFunctionality и создание будет через него, например это будет класс Main ... и тогда вы сделаете только

Main main=new Main();

2. тогда что будет делать метод AddProvider при двух вызовах:

       public BasicRender()
       {
           ...
           _camera = AddConsumer<Camera>("Camera", TypeConsumer.Common);
       }    
       public BasicRender2()
       {
           ...
           _camera = AddConsumer<Camera>("Camera", TypeConsumer.Common);
       }    

По тому как вы написали он даст ссылку на две разные камеры, но у нас бывают случаи когда надо на одну - как этого добится ?

3. Далее вы предполагаете, что объект main таким образом будет хранить ВСЕ ссылки на имеющиеся объекты в своей коллекции и раздавать их агрегируемым классам ? тогда тут что-то не сходится или вы пишите не совсем тот код ...

       public BasicRender()
       {
           ...
           _camera = AddConsumer<Camera>("Camera", TypeConsumer.Common);
       }    

вот этот объект при всем своем желании НИКОГДА не сможет вам вернуть готовую камеру, которая была созданна где то еще, настроена и участвует в игре ... Он может вам создать только НОВУЮ камеру - поэтому я вас спрашивал чем это отличается от new Camera() ... т.е. поставщик уже готовых объектов таким образом не может быть реализован S.J. 13:37, 28 марта 2009 (UTC)

  • Хотя многое я похоже из диаграммы понял ;) Дайте несколько примеров использования метода AddFunctionality() и что он делает ... правильно ли я понимаю, что когда вы пишите код _camera = AddConsumer<Camera>("Camera", TypeConsumer.Common); текущая функциональность соединяется со своими функциональностями более верхнего уровня через _parent_functionality - и бегая по дереву имеющихся функциональностей, разыскивает уже созданную камеру и если ее нет то создает ? Даже если это не так - меня интересует именно этот процесс - что происход здесь ? S.J. 20:22, 28 марта 2009 (UTC)
  • 1. Будет примерно следующим:

Scene scene = new Scene(); // Унаследована от ComplexFunctionality

Camera camera = new Camera(); // Унаследована от Functionality

BasicRender render = scene.AddComplexFunctionality<BasicRender>("Render", true); // Унаследована от Functionality

scene.AddFunctionality("Camera", camera);

2. Вопрос не очень ясен, но попробую ответить. Вообще там метод AddConsumer<> :). Эти методы добавляются разработчиком на этапе разработки класса унаследованного от ф-ти, а не во время выполнения. Разработчик сам определяет какие данные нужны ф-ти для работы. Нужна камера - AddConsumer<Camera>.. Если ф-ти нужно поделиться данными то AddProvider<>.. На счёт общей камеры я, думаю, уже ответил см. выше.

3. Почему сразу ВСЕ – только необходимые. Опять же это на усмотрение разработчика. Тем не менее так оно и получится. Ф-ть будет поставлять готовые объекты.

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

Что даёт метод AddFunctionality, :) он может дать игровому объекту физику, звук и др. В обшем добавляет в объект функционал.

К примеру можем реализовать две ф-ти которые управляют физикой одну на ODE другую на ФизХ. При необходимости мeнять их.

Процесс который Вы просите описать, примерно так и происходит. Только сначала формируется список провайдеров и консумеров. А уже при добавлении происходит подключение. При необходимосте ф-ть можно отключать и подключать.

Участник: -Sell-

Рефакторинг Править

  • Мне пока сложно, что либо утверждать пока я не видел кода ... и если я правильно схватил идею ... а так же если вас интересует мое мнение и вы готовы к экспериментам -> то мне кажется здесь требуется существенное упрощение при том, что основная идея думаю сохранится ... есть такое впечатление, что вы просто хитроумно замаскировали передачу параметров - но это тем ни менее не дает гибкости (независимости сущностей) при программировании, а наоборот, несколько тяжеловесно затрудняет программирование. Источник идеи я понимаю, но поверьте, что такая надетая оболочка мало чего дает ... впрочем я готов попробывать это показать на примере ... подожду когда вы выложите код и проведу пару рефакторингов ... думаю первым делом устранить лишнию сущность Consumer - сдается мне, что в ней нет ни какой необходимости (не идеологической, а технической) S.J. 20:54, 28 марта 2009 (UTC)

А как сюда файл прикрепить :)? Участник: -Sell-

Для этого мы используем гугл-группу vlabdownload, там надо тоже зарегистрироваться и тогда можно закачать материал. S.J. 07:51, 29 марта 2009 (UTC)

  • Если честно, то Вы заставили меня немного сомневаться в выбранном подходе )))..

Я тут подумал о том, как убрать Consumer – ответ никак.. Этим Вы убьёте самый главный плюс. Этот плюс даже не в хитрой системе передачи параметров – он этим достигается, а в том, что мы можем строить цепочки из взаимосвязанных ф-тей. И если нужно подменивать одну цепочку на другую.. При этом отображение и поведение объекта может очень сильно меняться. Что, на мой взгляд, не достижимо каким либо другим подходом. Т.к. невозможно жёстко прописать все возможные поведения объекта, и какие при этом ему потребуются данные. А здесь же объект будет строиться из набора ф-тей, а разработчик при необходимости сможет накидать свою ф-ть, используя при этом данные которые ему необходимы(этим он, возможно, придаст объекту особое поведение). А за получение данных он может не волноваться. Они могут прийти с какого угодно уровня и от какай угодно ф-ти. И при всём при этом мы можем управлять степенью зависимости одной ф-ти от другой.. И потом, назовите мне хоть одну вещь которую я не смогу на ней сделать :). На счёт затруднения программирования, думаю, Вы сделали такое заключение не обоснованно. Здесь я могу применять все прелести ООП. + такого рода обмен данными существенно облегчит управление объектами. Буду рад выслушать Ваше мнение и поучаствовать в экспериментах :). Участник: -Sell-

  • Ну, что же мы будем голословно спорить ... давайте на коде - закачайте на vlabdownload пример, который по вашему мнению лешится каких либо видимых (а не подразумеваемых) преимуществ - если из него в последствии вырезать Consumer. Я же попробую сделать формальный рефакторинг - скажем так, чтобы привести это к одной из вариаций стандартной концепции компонентной модели ... при этом я же писал "основная идея думаю сохранится", правда не гарантирую, что воспринимать вы ее будите так как вы привыкли :)
  • "невозможно жёстко прописать все возможные поведения объекта, и какие при этом ему потребуются данные" - жестко нельзя, но проще можно :) ... по хорошему можно организовать таким образом, чтобы избавится от подключений и тем более от переподключений ... но это следующий этап после того как мы договоримся как убрать облочку данных в виде Consumer ... вообщем если готовы можем серьезно в этом направлении поработать ... конечно, я тоже могу ошибатся, но зато возможно в результате полученный компромис будет более жизненно способным ;) S.J. 13:16, 29 марта 2009 (UTC)
  • Чего-то куда-то залил :). Всё же, теоритически убрать Consumer можно, заменив его на просто ссылку на Provider.

Избавиться от подключений и переподключений скорее всего никак, т.к. потеряем динамичность системы. Но из-за замены Консумера этот процесс скорее всего существенно облегчится :). Участник: -Sell-

  • Спасибо, буду смотреть, но возможно это займет время, т.к. времени не очень много :) Вот видите - вы читаете мои мысли по поводу Consumer, хотя в деталях я не хотел призноваться раньше времени .... но это только начало :) S.J. 07:00, 30 марта 2009 (UTC)
  • И все же голой ссылкой, походу, не отделаться..

Тут ещё есть несколько видов Consumer-ров:

public enum TypeConsumer { Сurrent, Upper, Common }

Отличаются они тем как они будут подклюсаться. Первый вид Current(Текущий) – подключается только на текущем уровне т.е. здесь нет рекурсивного перебора. Upper(Верхний) – подключение производится со следующего уровня рекурсивно вверх. Common(Основной) – с текущего уровня рекурсивно вверх.

Зачем это собственно нужно – что бы можно было выстраивать зависимости данных. Пример. Допустим зависимость положения в пространстве одного объекта от другого. Т.е. мы можем сделать ф-оть которая будет содержать консумер и провайдер с одинаковым именем. Если просто закинуть ф-ть на уровень, то этот консумер подключится к провайдеру и нужных данных он не получит. А вот если мы изменим тип консумера на Upper получим нужное нам поведение. :). Т.е. выход один создать структуру данных, за место голой ссылки. Т.е. заменим один консумер на другой. Текущий:

   public abstract class Consumer
   { 

internal DataProcessor _functionality; internal string _name;

       internal TypeConsumer _type_consumer;
       internal int _level;
       public abstract bool Connected { get; }
       public abstract void Connect(Provider provider);
       public abstract void Disconnect();
       internal abstract void NullReference();
   }

Следующим:

   public struct Consumer
   {
       internal Provider provider;
       internal TypeConsumer _type_consumer;
   }

Хранить его будем в коллекции, обращаться по ключу :). Участник: -Sell-

Я тут немного глянул - вы мне сильно упростили задачу :) В пример BasicRender не создается, а в других местах DataConsumer нету - значит, я спокойно могу все удалить и даже не замечу, как это повлияет на пример :) ... так вот, не могли бы вы подключить BasicRender, чтобы в примере реально было видно, что зависит от DataConsumer ? S.J. 10:43, 30 марта 2009 (UTC)

  • Хотя я похоже чего то не досмотрел ... буду смотреть подробнее .. S.J. 11:04, 30 марта 2009 (UTC)
  • Так посмотрите на TerrainComponent тоже что и BasicRender :). А вообще от DataConsumer зависит то, что находится внутри BasicRender-ра или любой другой ф-ти. Вот удалите консумеры из BasicRender или TerrainComponent и всё сразу увидите :).

Там, кстати, в TerrainComponent ошибка где-то(плохо рисуется), только я её пока не могу словить. Возможно ошибка в ядре. Участник: -Sell-

  • Значит получилось немного не по плану, начал с другой стороны - устранил класс Functionality, теперь все будут ComplexFunctionality - которые я назвал Сущностью (Entity). Разделение только все дублировала и не вносило ни какой ясности - функциональность могла когда нибудь вырасти до ComplexFunctionality, да и вообще это частный случай и очень редкий случай когда не нужны параметры ... Так же зачистил подозрительные массивы _array_i_update _array_i_render - они не использовались, и даже понимая что вы тут замышляли - это нужно делать иначе (но давайте это оставим на потом) ... Камеру я добавил в сцену, чтобы все было однообразно и не управлялось бы из главного класса ... Добавил вариант поиска коннектов у вида TypeConsumer.Full - ищет так: получает самую верхушку, и постепенно просматривая все узлы спускается вниз ... т.е. получается что можно получить функциональность братьев-сестер :) ... т.е. нет необходимости выстраивать полную иерархию, чтобы получить нужное ... т.е. вполне естественно в сцене иметь Камеру и Территорию, и чтобы Территория могла получать данные Камеры ... Вообще иерархический поиск здесь несколько учербен, т.к. Сущности (по вашему Функциональности) нельзя всегда выстроить иерархически, у них связи в виде графа - поэтому иерархичия тут слабо помагает ... исходя из этого скорее всего надо избавится от разных видов TypeConsumer и меть некий по умолчанию, т.е. пользователь не должен заботится об этом - это только вводит путаницу (относительные пути очень не устойчивы - и подверженны частым изменениям - на это полагаться нельзя) ... искать лучше действительнос с верху, т.е. по типу TypeConsumer.Full ... поиск снизу думаю не нужен ... да если вам не жалко - дайте компонент неба (там я так понял не хватает графики), а то очень мрачно и мало примеров взаимодействия компонентов ... если вам интересна получившаяся у меня промежуточная версия - могу выложить, далее всеже думаю разобраться с тем, чем и планировал :)
  • Вариант, конечно, получился своеобразный.. )) Но пока я его не до конца понимаю, поспешных выводов делать не буду. В чём был смыл разделения на две сущности(ф-ть и комп. ф-ть). Уровень т.е. комп. ф-ть содержит три виртуальных метода Init(), Update(), Render(). Если убрать ф-ть, то метод Render(), (условно) камеры унаследованная от ком. ф-ти будет работать в холостую. А большинство объектов – ф-ти(1/3). Думаю этот вопрос надо как-то решать, холостой вызов это куда хуже разделения на две сущности. Хотя это и усложняет подключение.

Сверху в низ – это что-то новое :).. и пока для меня не понятно как такой подход справится к примеру со следующим: Есть у меня 3 уровня в сцене. На первом есть источник света “Свет”(ф-ость + провайдер), он должен распространяться на всю сцену. Условно все объекты будут рассчитывать на это имя провайдера. На втором уровне размещаем 2-й источник, но с тем же именем, как бы его переопределяя для объектов нижних уровней т.е объекты уровнем ниже должны подключиться на уровне 2, а не на 1. Как получить такое поведение с подходом сверху в низ? И потом иерархический поиск будет только при подключении – а далее напрямую.

Выложите если можно Вашу версию – будет очень интересно посмотреть :).Участник: -Sell-

  • Ну сразу камнями не закидывайте - конечно в процессе я мог кое, что обрезать что важно ... "Render(), (условно) камеры унаследованная от ком. ф-ти будет работать в холостую" - это легко исправить - пусть пока поработает :) ... даже если холостой - он зайдет и выйдет ... "с тем же именем, как бы его переопределяя для объектов нижних уровней" - это уже серьезнее и вы излагаете впервые ... надо подумать, возможно можно совместить с вашим поиском Common и если он не найдет тогда использовать Full
  • Консумер оказался устойчивым :) ... удобнее оказалось переделать Провайдеры ... сегодня, завтра я еще покалдую над этим ... переделаю все Провайдеры, на компонентную модель ... и затем выложу .... S.J. 08:21, 31 марта 2009 (UTC)
  • Хорошо, буду ждать :).. Пока тут нашёл ещё один минусик убийства ф-ти, ф-ть не имеет иерархии, а большинству объектов она не нужна. В итоге мы будем зря тратить память из-за усложнённого базового класса. Так же возможно, будут потери производительности при подключении, если сцена сильно разрастётся, из-за того, что количество объектов делилась на большае количество массивов. Я имею ввиду поиск по ключу(это только предположение). Хотя это облегчит процедуру поключения. Участник: -Sell-

Рефакторинг2 Править

  • Закачал версию на vlabdownload (в последствии лучше тоже закачивайте в этот раздел)
  • Значит это черновик - делал наспех, поэтому осталось много грязи в виде коментариев и лишнего кода ... но идею думаю уловить сможете ...
  • Знаю будите ругаться, т.к. удалил ОЧЕНЬ много вашего кода (и это еще не придел :) ), поэтому не удивительно, что наверняка потерял некотурую функциональность, которую вы предполагали ... из того, что теперь нехватает: (1) то, что уже говорилось "с тем же именем, как бы его переопределяя для объектов нижних уровней" (2) подключение в произвольном порядке (переподключения) - это надо делать по другому, думаю на основе событий ...
  • Ценность данного рефакторинга в придельном упрощении и что более главное упрощении с точки зрения пользователя ядра, вся функциональнасть которая потерялась должна быть востановленна, но по другому - так чтобы это было полностью прозрачно для пользователя ядра, т.е. внутри ядра ... Вообщем посмотрите и когда уловите идею, то обсудим уже конкретнее чего не хватает и как это востановить лучшим образом ... S.J. 08:04, 1 апреля 2009 (UTC)
  • Не, ругаться не буду :) .. И так посмотрел Ваш вариант. Что на данный момент меня не устраивает:

Подход с верху в низ, Вы мне пока не показали его преимущество перед с низу в верх :). Почему собственно не устраивает – с ним мы не достигнем нужных результатов, а будем делать лишнюю работу. Он будет искать консумеры не в тех ветках. Плюсом может быть то, что основные провайдеры будут находиться на верхних узлах, а точнее в корне. Но при подходе с низу в верх это легко исправить, к примеру, сделать сущность для хранения определённых провайдеров, таких как Game, GameTime, которые существуют только в одном варианте и искать там в первую очередь. А если не найдёт, то с низу в верх :). На счёт переподключений, то их функция очень важна и если не придумаем как реализовать их проще, то лучше оставить как есть. Оно и так будет упрощено если выкинуть ф-ость. Не факт что с событиями этот процесс облегчится..

Еще в вашем варианте есть одна проблема – что произойдёт когда верхняя ф-ость будет отключена от сцены? Ожидаемое поведение – когда ф-ость отключается, она не должна участвовать в сцене, но её данные должны существовать. А консумеры, которые были к ней подключены, должны найти себе новых поставщиков в сцене.

Могу предложить свой вариант модернизации (на основе Ваших идей :).. И так: 1. Существенно упрощаем Consumer и Provider. Будет это за счёт того что, при отключении ф-ти, консумеры, которые были к ней подключены, сразу узнают об отключении их провайдеров. Сразу начнут поиск новых. За счёт этих упрощений мы выкинем кучу лишнего кода и из других сущностей. 2. Ф-ость пока убивать не будем, за место этого облегчим компл. ф-ть. Её функции возложим на ф-ти. А ком. ф-ость будет играть исключительно роль уровня. Можно будет даже запретить наследование. Она не будет иметь консумеров и собственных провайдеров. Это позволит выкинуть ещё приличную порцию кода, при этом не теряя никакой функциональности в целом. Хотя с наследованием я возможно погорячился, за счёт этого можно будет прятать не который код внутрь. 0 Т.е. картина будет примерно следующая: Создаем класс к примеру Game, унаследованный от компл. ф-ти, а в нутрии прячем код по созданию сцены(унаследованной от ф-ти), камеры и др.

Пока ещё это не реализовал, но постараюсь сделать на днях. А потом сравним с Вашим вариантом. Участник: -Sell-


  • "Подход с верху в низ, Вы мне пока не показали его преимущество перед с низу в верх" - ну, я пытался объясните выше. С низу вверх - он просто не найдет сущности, которые используют братья-сестры, и будет вынужденным пользоваться только тем, что есть у родителей ... А этого мало ! Более того это заставляет программиста выстраивать все сущности строго иерархично ! А это плохо, т.к. в ряде случаев это нельзя сделать, т.е. скажем подключили вы камеру объекту А уровня 3, а этим хочет пользоваться объект Б уровня 3 - а не может ... тут вы говорите - а помещай тогда камеру на уровень 2 - и все будет ок. А на уровне 2 она тоже долго не удержится, т.к. в какой-то мемент объект С на уровне 4 по совсем другой ветке от 1-го уровня зохочет иметь эту камеру - в итоге вы вынесете эту камеру вообще на самый вверх ... и такая текущесть с вынесением до самого вверха будет всегда и будет зависеть не от структурной организации объектов, а от того какими параметрами они хотят пользоваться ... в итоге объектная архитектура у вас будет подченена правилам передачи параметров, а не тому, какие объекты являются частью других ... Скажем вы добавляете машину из частей - колеса, двери, бампер, фары ... и тут оказывается, что грузовик из другой сцены хочет иметь такие же фары - вы берете варварски отбираете от машинки фары и засовываете их прямо в глобальную сцену, хоя фары то реализованны машиной, но добавить их грузовику вы не можете по другому ... привер конечно несколько не корректный но идея должна быть понятна ... кто его знает почему это грузовику понадобились не свои фары - может для синхронизации свечения :) но суть в другом - у вас будут связаны руки, чтобы организовать такую передачу параметров из разных веток ... именно поэтому я утверждаю, что между объектами нет четкой иерархии, а есть связи по типу графа (т.е. потенциально все со всеми, но в конкретном случае с определенной конструкцией - и она не иерархическая) ... S.J. 16:51, 2 апреля 2009 (UTC)
  • "На счёт переподключений, то их функция очень важна и если не придумаем как реализовать их проще" - придумаем :) ... только давайте это серьезно обговорим, какую функцию это должно играть ... К примеру создали мы сцену из нашей камеры и гор ... а вот собственно игра как такавая не создана (если вы в моем примере переставите местами опреаторы Add - то наверняка, все свалится по ошибки) ... вообще это действительно не очень логично в сцену добавлять камеру, а из нее трбовать парметр который еще не создан - но что мы здесь хотим ? надо наверное отключить данный компонент, пока не появится нужный зависимый параметр .. так ? И как часто проверять появился или нет параметр ? S.J. 17:07, 2 апреля 2009 (UTC)

По порядку:

  • Про братьев-сестер, теперь понятно :). Это можно реализовать и очень просто, хотя остаюсь при своём – большинство задач всё же легче решить с помощью иерархии.

Подход следующий создаём объект, абсолютно простой ни от чего не унаследованный – это будет объектом посредником. Этот объект будет создавать в себе две ф-ти. Одну мы кидаем в участок сцены для приёма каких-то данных, а вторую в другую часть сцены для предоставления. Хоть и звучит чудно, но тем не менее результата можно добиться ещё большего чем при подходе с верху в низ, т.к. мы в посреднике можем реализовать дополнительную логику поведения. Также можно будет наделать разные типы подобных узлов. Главное всё просто и управляемо. :)

  • Про переподключения:

Здесь Вы абсолютно верно заметили – всё развалится :(… Этого не должно произойти. Эту ошибку я уже тоже заметил. Поведение должно быть примерно следующим: Ф-ость попадает в сцену, она пытается подключиться, начинает с консумеров (здесь была ошибка в предыдущей версии ядра, тогда начиналось с добавления провайдеров на уровень). Если какой-то консумер не подключился, то ф-ость не активна(дальнейшее её подключение не происходит). Если хоть одна ф-ость на уровне не активна, то не активен весь уровень и все его дети. Здесь просьба не путать с подключением и отключением ф-тей, это происходит намеренно. А здесь речь о не достаточности данных. Что на счёт проверок на наличие провайдеров. Ни каких проверок не должно быть! Здесь речь идёт о подключении провайдеров. При подключении ф-ти, провайдеры проходят процедуру подключения как и консумеры, только с верху в низ (начиная с того уровня на который добавлена ф-ость). При этом мы сканируем все дочерние ветви и проверяем на каком уровне подключены соответствующие консумеры и если нужно переподключаем. Участник: -Sell-

  • "Подход следующий создаём объект... это будет объектом посредником." - ни чего не понял, можно на нашем примере - хотелось бы, чтобы камера и горы были бы на одном уровне и как этого добится ... ?
  • Развалится где ? В моей версии точно - тут к гадалке не ходи - я это получил сразу же ... и оставил пока не обсудим ... вы про это ? или в вашей версии тоже самое ? Касательно - "просьба не путать с подключением и отключением ф-тей, это происходит намеренно. А здесь речь о не достаточности данных." - причина то разная - но аппарат должен быть единым ... а вот это " Ни каких проверок не должно быть!" страно - что эта сцена так и останется отключенной - когда же она заработает ? S.J. 22:40, 2 апреля 2009 (UTC)
  • Касательно про иерархию - вот у нас маленький пример - сцена, горы, камеры, игра, время, ну и скажем небо, идущий человек - как вы все это иерархически разместите ? S.J. 22:43, 2 апреля 2009 (UTC)
  • Задача оказалось ещё проще чем я думал.."хотелось бы, чтобы камера и горы были бы на одном уровне и как этого добится" - в Вашем примере этого не сделать т.к. у Вас другой тип иерархии - там только голые уровни.. А здесь уровень + линейный список ф-тей, именно на него можно и даже нужно помещать объекты такого рода. А ф-ти будут подключаться с текущего уровня. По объект посредник забудьте, это я погрорячился, можно обойтись только двумя ф-тями, передав первую второй в конструкторе. Это можно использовать для связи различных веток.
  • Было почти тоже самое :), здесь была ошибка в подходе (не верный порядок действий). Отключение и подключение ф-тей будет вызывать переращёт активности на локольном уровне у объектов к которым она подключится(отключится). Сцена заработает тогда, когда в неё поступит достаточное количество ф-тей для её работы. Я имею ввиду не конкретно сцену, а любой уровень.
  • 1-й уровень - сцена(хотя это сценой уже не назовёшь, сцена - это скорее всё дерево, лучше объект Game[Игра, Время]), камеры...

2-й уровень: 1-я ветка - горы(набор ф-тей: физика, сетка и тд.); 2-я ветка - небо; 3-я ветка - человек;

  • Ещё одна идея, а что если мы разделим коллекцию консумеров на две(подключённые и неподключённые). При подключении консумеров будем подключать не по одному консумеру, а целый массив сразу. Зачем перебирать дерево для каждого консумера или провайдера?

Участник: -Sell-

  • "в Вашем примере этого не сделать т.к. у Вас другой тип иерархии - там только голые уровни" - прошу не путать ;) Уровней у меня нет - это компоненты - причем так-же двух видов (!) скажем так: конечный компоненты - Game, GameTime и сущности Камера, Горы и все они вложенны в другую сущность сцену. Так вот связи между братьями-сестрами одного уровня иерархии достаточно сильные и поиск сверху-вниз их находит ...

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

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

Кстати, переподключения я в частном примере реализовал на основе событий - очень даже просто получилось ... но это только для одного уровня ... вообще есть мысль, что нам надо найти некий компромис - моя логика хороша для двух-трех уровневой сущности (там много межэлементных связей и иерархия не уместна) - ваша же логика более подходит для мало связанных сущностей, которые разделенны более чем 3 уровнями ... но тут надо обдумать хороший пример, на котором можно провести отладку возможного компромисного решения ...S.J. 19:08, 3 апреля 2009 (UTC)


  • Ок. Буду смотреть ... а в двух словах в чем идея ? S.J. 19:29, 7 апреля 2009 (UTC)
  • В двух словах:

Консумера больше нет, а провайдер вообще не участвует в подключении. В место этого подключаемся к ф-тям. Т.е. ф-ость имеет коллекцию ссылок на др. ф-ти, для данной ф-ти они играют роль консумеров. Плюсы думаю очевидны... Вот к примеру, есть камера, у неё 2 консумера (матрица вида и проекции) нам придётся обойти сцену 2 раза. А если подключаться по целым ф-тям, то 1 раз :). А если консумеров 10-ть? А тут в любом случае обход делаем 1 раз. Заметьте уже в системе есть динамичность, хотя её ещё нужно дорабатывать.. Здесь ввёл несколько условий: 1. Если хоть одна ф-ость на уровне не подключена уровень не активен + не активны и дочерние уровни. 2. Если уровень не активен, то ф-ти добавленые на него не подключаются. Уровень не обрабатывается. 3. Если верхний уровень стал активным, это даёт возможность подключаться следующиму уровню. При этом происходит локальный Init(). Ну и в таком роде :). Участник: -Sell-

  • Ну, не знаю ... мне мой вариант больше по душе :) ... Наверное у Вас стало лучше ... но как вам сказать - вы как-то технично подходите к задаче - т.с. логика где ? Например, давайте начнем с функциональности и компл. функцинальности - зачем это ? Чем они отличаются, почем нельзя иметь только компл. функционльность и называть это сущностью ? т.е. любой объект, в который можно иерархически вложить другой объект ? Давайте оставим технику - и поговорим какую цель мы этим приследуем ? S.J. 21:19, 13 апреля 2009 (UTC)
  • Давайте оба варианта рассмотрим в деталях. :)

Представьте, себе дерево у него есть – корень, ветви и листья. Листья иерархии не имеют, а ветви образуют ту самую иерархию. Так вот к чему я веду, человек(условно) – лист (набор ф-тей). А ветви это так сказать группирующие узлы (компл. ф-ти), которые будут содержать общие данные для конечных листьев, к примеру, источники освещения, трансформации, камера и тп. Нет смысла делать иерархию для ф-тей, которые принадлежат конкретному объекту, хотя и такая возможность имеется. Участник: -Sell-

  • Т.е. здесь как палка имеет два конца.. Можно сделать одну сущность, но давайте посмотрим, допустим у нас есть группа листев, которые имеют общий источник света + общую трансформацию + ещё что-то.. Придётся делать 3 уровня, а на 4-том будут листья. Эти три уровня будут иметь излишний функционал, а тут берём ф-ть(куда более простой объект) делаем свет, ещё одну - трансформацию и кидаем всё на один уровень. Тот же вариант и с листом, он должен быть ввиде прямого списка ф-тей, а не как иерархия ф-тей. т.к это усложнит подключение.Участник: -Sell-
  • "будут иметь излишний функционал" Вы не правы - посмотрите на объекты Времени и Игры - это листья и они не имееют излишней функциональности. Камера и Горы - да, это сущность, а не листья ... потенциально камера состоит из частей, а горы из камней .. т.е. даже если они СЕЙЧАС не являются иерархическими, то они в ЛЮБОЙ момент ими могут стать, и в этот момент менять родителя совсем не правильно ... А вот дореализовать интерфейс IUpdate или IRender - вполне достаточно, чтобы аппарат понял, что объект стал не пассивным листом, а веткой ... Еще - чтобы окончательно снять вопрос лишнего кода (хоть это не так и заметно сейчас, т.к. логика подключений это минимальный код, т.е. нестрашно если листья его не используют) - то сам принцип встраивать управляющую логику в родителя неверен, т.к. по хорошему нужно выделять один объект менеджер - скажем так Менеджер подключений у нас, и только в нем заниматься подключениями, а вот любой объект (потенциально иерархический) должен обращаться к такому менеджеру - в итоге все становится на свои места иерархия сущностей просто существует, а их родители лишь обеспечиваю связь с менеджером, который управляет главным циклом в данном случае подключений, но потенциально и других системных вещей ... т.е. мы отделили наконец сами сущности от их управления (т.е. не только избавились от дублирования управления в объектах листьях, но и всюду, оставив лишь потенциальную возможность) ... S.J. 15:59, 14 апреля 2009 (UTC)

Анализ существующих игровых движков Править

Кандидаты:

  • RealmForge 0.6.2 Скачать - предшественик Visual3D.NET. Преимущества открытый код.
  • Visual3D.NET Game Engine for .NET/XNA Официальная страница - Недостатки - комерческий с закрытым кодом.

См. также Править

  • Кандидатов ищем отсюда, требования бесплатный, с исходниками, C# + DiretcX 10 и выше
(Варианты, наиболее подходящие по описанию: Agar 1.2, ArcEngine, Axiom, Brume, Endogine, FlatRedBall, Horde3D, Irrlicht, LightFire, Ovorp, Purple, ) - там же RealmForge который по описанию существенно опережает прочие. Поэтому базироваться можно на нем, а при необходимости комбинировать из описанного списка.

Обсуждение на чем остановится Править

  • Мне, кажется, что для начала можно остановится на RealmForge 0.6.2 (незнаю есть ли более новая версия). Т.к. открытый код для нас важнее - можно переделывать и перекраивать как душе угодно, чего не добьешься от комерческой версии, даже при том, что там могут быть интересные нововведения. S.J. 11:34, 2 марта 2009 (UTC)
  • Проблема - демо игры из RealmForge 0.6.2 не пошли у меня на Висте. Как у Вас ? В чем может быть проблема, смертельно ли это ... S.J. 12:03, 2 марта 2009 (UTC) (На XP - у меня тоже свалились, возможно проблема, что там чего то качается с сайта, который возможно уже не поддерживатеся :( )

UpReal 10:42, 3 марта 2009 (UTC)Пошел изучать RealmForge. Как разберусь, отпишусь.

UpReal 18:10, 3 марта 2009 (UTC) RealmForge - мертвый проект не лучше и не хуже других. Можно использовать только как набор алгоритмов и реализации. Проект умер как и умирает большинство других проектов графических движков. Не достаточная гибкость и сложность в использовании для простых пользователей. Поэтому чаще всего пишутся специализированные движки под конкрентный проект или задачу.

UpReal 06:00, 25 марта 2009 (UTC) RealmForge превратился в Visual3D. Visual3D основан на XNA 1.0, а текущая версия XNA 3.0.

Редактор сцены Править

  • Кто бы попробывал разобраться с Ox Game Engine а потом отписаться, что там хорошего ... заманчиво выглядит ... S.J. 22:43, 3 марта 2009 (UTC)

UpReal 17:56, 4 марта 2009 (UTC) Я пытаюсь разобраться. И хочу реализовать, для начала на XNA следующий класс:

class MyRenderControl : Control {
  }

Который можно вставлять в свою форму. Этот класс активизирует DirectX в области MyRenderControl, запускает процедуру рендеринга в новом потоке. Я передаю 3D модели, а класс их отображает. На SlimDX я делал такое окно. Очень удобно исследовать поведение отображения. В PropertyGrid меняешь свойства и сразу видишь результат.

UpReal 19:15, 5 марта 2009 (UTC) В XNA основной упор сделан на поддержку XBox. От сюда вытекают все достоинства и недостатки.

1. Основной класс исполнения программы Game вместо Application. Главный класс наследуется от Game. При этом создается окно графического вывода, инициализируется DirectX. Ни каких System.Windows.Form вставлять туда нельзя - это окно рендеринга. Решение: можно создать еще одно окно и там использовать формы интерактивного общения с программой или в окне рендеринга использовать графические GUI элементы.

2. Основной упор сделан на производительность рендеринга и поддерживаются только те файлы элементов сцены, которые доступны в XBox. Графический контент (полигоны, эффекты, текстуры) компилируется на стадии сборки проекта в бинарные файлы. В момент исполнения выводятся эти файлы. Тут как кому нравится, и это легко можно обойти.

3. Реализацию дополнительной функциональности рекомендуют наследовать от классов GameComponent и DrawingGameComponent. У объектов от этих классов будут вызываться методы Update (реализация логики) и Draw (реализация рисования).

Для реализации своей задачи я поступил следующим образом (подглядел у Ох):

Создал все как обычно по шаблону. После инициализации я получил самое главное - GraphicDevice для работы с DirectX. Больше от Game мне ни чего не надо. Делаю Hide окна рендеринга которое мне создал Game и создаю свои окна какие мне надо. Оконному элементу MyRenderControl передал ссылку на DirectX, а дальше уже делал все как раньше на SlimDX. Т.е. я получил managed DirectX, а весь XNA остался в стороне.

  • Ссылки как отучить XNA от класса Game [2] [3] S.J. 22:25, 19 марта 2009 (UTC)

Концепция проекта от UpReal (+ уточнения S.J.)Править

Прошу всех обратить внимание на данную концепцию, здесь изложен достаточно качественный подход, со временем я немного покорректирую текст, и попробуем взять отсюда за основу ряд пунктов. S.J. 16:12, 1 марта 2009 (UTC)

См. также Править

Обнаружено использование расширения AdBlock.


Викия — это свободный ресурс, который существует и развивается за счёт рекламы. Для блокирующих рекламу пользователей мы предоставляем модифицированную версию сайта.

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

Также на Фэндоме

Случайная вики