Задав два вопроса о системах сущностей ( 1 , 2 ) и прочитав некоторые статьи о них, я думаю, что понимаю их гораздо лучше, чем раньше. У меня все еще есть некоторые неопределенности, в основном в отношении создания эмиттера частиц, системы ввода и камеры. У меня, очевидно, все еще есть некоторые проблемы с пониманием систем сущностей, и они могут относиться к целому ряду объектов, но я выбрал эти три, потому что они представляют собой очень разные понятия, должны охватывать довольно широкий круг вопросов и помочь мне понять системы сущностей и как справляюсь с такими проблемами, как я сам, по мере их появления.
Я создаю движок на JavaScript, и я реализовал большинство основных функций, которые включают в себя: обработку ввода, гибкую систему анимации, эмиттер частиц, математические классы и функции, обработку сцены, камеру и рендер, и целую кучу других вещей, которые обычно поддерживают двигатели. Я прочитал ответ Byte56, который заинтересовал меня в превращении движка в систему сущностей. Он по-прежнему останется игровым движком HTML5 с базовой философией сцены, но он должен поддерживать динамическое создание объектов из компонентов.
Теперь у меня проблема в том, чтобы вписать мою старую концепцию движка в эту новую парадигму программирования. Вот некоторые определения из предыдущих вопросов, обновленные:
Сущность является идентификатором. У него нет никаких данных, это не объект, это простой идентификатор, который представляет индекс в списке сцен всех сущностей (который я на самом деле планирую реализовать в виде матрицы компонентов).
Компонент является держателем данных, но с помощью методов , которые могут работать с этими данными. Лучший пример -
Vector2D
компонент «Позиция». Он имеет данные:x
иy
, а также некоторые методы , которые делают работающие на данных немного проще:add()
,normalize()
и так далее.Системы является то , что может работать на множестве субъектов, отвечающих определенным требованиям; как правило, сущности должны иметь определенный набор компонентов для работы. Система является частью «логики», частью «алгоритма», все функциональные возможности, предоставляемые компонентами, предназначены исключительно для упрощения управления данными.
камера
Камера имеет Vector2D
свойство положения, свойство поворота и некоторые методы для центрирования ее вокруг точки. Каждый кадр, он подается на рендерер вместе со сценой, и все объекты переводятся в соответствии с его положением. Сцена затем отображается.
Как я мог представить этот вид объекта в системе сущностей? Будет ли камера объектом, компонентом или комбинацией (согласно моему ответу )?
Излучатель частиц
Проблема с моим эмиттером частиц, опять же, то, что должно быть чем. Я почти уверен, что частицы сами по себе не должны быть сущностями, поскольку я хочу поддерживать более 10 000 из них, и я считаю, что создание такого количества сущностей нанесло бы серьезный удар по моей производительности.
Как я мог представить этот вид объекта в системе сущностей?
Менеджер ввода
Последнее, о чем я хочу поговорить, - как обрабатывать ввод. В моей текущей версии движка есть класс с именем Input
. Это обработчик, который подписывается на события браузера, такие как нажатия клавиш и изменения положения мыши, а также поддерживает внутреннее состояние. Затем у класса проигрывателя есть react()
метод, который принимает входной объект в качестве аргумента. Преимущество этого состоит в том, что входной объект может быть сериализован в .JSON, а затем распространен по сети, что обеспечивает плавное многопользовательское моделирование.
Как это переводится в систему сущностей?
Вот как я подошел к этому:
камера
Моя камера, как и любая другая, является объектом, к которому прикреплены компоненты:
Transform
имеетTranslation
,Rotation
иScale
свойства, в дополнение к другим , для скорости и т.д.Pov
(Точка зрения) имеетFieldOfView
,AspectRatio
,Near
,Far
, и все остальное , требуется , чтобы произвести матрицу проекции, в дополнении кIsOrtho
флагу используется для переключения между перспективой и ортогональной проекцией.Pov
также предоставляетProjectionMatrix
свойство lazy-load, используемое системой рендеринга, которое внутренне рассчитывается при чтении и кэшируется до изменения любых других свойств.Там нет выделенной системы камеры. Система рендеринга поддерживает список
Pov
и содержит логику для определения того, какой из них использовать при рендеринге.вход
InputReceiver
Компонент может быть присоединен к любому объекту. У него есть прикрепленный обработчик событий (или лямбда, если ваш язык поддерживает его), который используется для проведения обработки ввода, зависящей от объекта, которая принимает параметры для текущего и предыдущего состояния ключа, текущего и предыдущего положения мыши, состояния кнопки и т. Д. (На самом деле, есть отдельные обработчики для мышки и клавиатуры).Например, в тестовой игре, похожей на астероиды, которую я создал, когда привыкал к сущности / компоненту, у меня есть два лямбда-метода ввода. Один управляет навигацией корабля, обрабатывая клавиши со стрелками и пробел (для стрельбы). Другой обрабатывает общий ввод с клавиатуры - клавиши для выхода, паузы и т. Д., Уровня перезапуска и т. Д. Я создаю два компонента, прикрепляю каждую лямбду к своему собственному компоненту, затем назначаю компонент приемника навигации объекту корабля, а другой - невидимый объект командного процессора.
Вот обработчик событий для обработки ключей, которые хранятся между кадрами, которые прикрепляются к
InputReceiver
компоненту корабля (C #):Если ваша камера мобильна, предоставьте ей свою собственную
InputReceiver
иTransform
компонентную, подключите лямбду или обработчик, который реализует любой вид управления, который вы хотите, и все готово.Это довольно удобно, поскольку вы можете переместить
InputReceiver
компонент с навигационным обработчиком, прикрепленным с корабля к астероиду, или что-нибудь еще в этом отношении, и вместо этого летать вокруг него. Или, назначивPov
компонент чему-либо еще в вашей сцене - астероиду, уличному фонарю и т. Д. - вы можете просматривать свою сцену с точки зрения этой сущности.InputSystem
Класс , который поддерживает внутреннее состояние для клавиатуры, мыши и т.д.InputSystem
фильтрует его внутреннюю коллекцию сущностей для лиц , которые имеютInputReceiver
компонент. В своемUpdate()
методе он выполняет итерацию по этой коллекции и вызывает обработчики ввода, связанные с каждым из этих компонентов, так же, как система рендеринга рисует каждый объект сRenderable
компонентом.Частицы
Это действительно зависит от того, как вы планируете взаимодействовать с частицами. Если вам просто нужна система частиц, которая ведет себя как один объект - скажем, фейерверк, показывающий, что игрок не может коснуться или ударить - тогда я создам одну сущность и
ParticleRenderGroup
компонент, который содержит любую информацию, необходимую вам для частиц - распад и т. д. - это не распространяется на вашRenderable
компонент. При рендеринге система рендеринга увидит, имеет ли объектRenderParticleGroup
присоединенный объект, и обработает его соответствующим образом.Если вам нужны отдельные частицы для участия в обнаружении столкновений, реагирования на ввод и т. Д., Но вы просто хотите отобразить их как пакет, я бы создал
Particle
компонент, который содержит эту информацию для каждой частицы, и создал бы их как отдельные лица. Система рендеринга все еще может пакетировать их, но другие системы будут обрабатывать их как отдельные объекты. (Это очень хорошо работает с экземплярами.)Затем, либо в вашем
MotionSystem
(или в любом другом использовании, которое обрабатывает обновление позиции объекта и т. Д.) , Либо в выделенном режимеParticleSystem
, выполняйте любую обработку, необходимую для каждой частицы на кадр. ОнRenderSystem
будет отвечать за создание / пакетирование и кэширование коллекций частиц по мере их создания и уничтожения и отображать их по мере необходимости.Хорошая особенность этого подхода заключается в том, что вам не нужно иметь никаких особых случаев для столкновения, отбраковки и т. Д. Для частиц; код, который вы пишете для любого другого типа объекта, все еще может быть использован.
Вывод
Если вы планируете переходить кроссплатформенно - не супер-применимо к JavaScript - весь ваш специфичный для платформы код (а именно рендеринг и ввод) разделен на две системы. Логика вашей игры остается в классах, не зависящих от платформы (движение, столкновение и т. Д.), Поэтому вам не нужно прикасаться к ним при портировании.
Я понимаю и согласен с позицией Шона, что подсовывать вещи в шаблон, чтобы строго придерживаться шаблона, а не настраивать шаблон для удовлетворения потребностей вашего приложения, плохо. Я просто не вижу ничего во вводе, камере или частицах, которые требуют такого рода обработки.
источник
Ввод и игровая логика, скорее всего, будут обрабатываться в выделенном фрагменте кода вне системы компонентов. Технически возможно внедрить его в дизайн, но есть небольшая выгода - игровая логика и пользовательский интерфейс являются хакерскими и полными неплотных абстракций, независимо от того, что вы делаете, и попытка загнать квадратный колышек в круглое отверстие просто для архитектурной чистоты - пустая трата времени.
Аналогично, излучатели частиц - это особые звери, особенно если вам небезразлична производительность. Компонент эмиттера имеет смысл, но графика будет создавать особую магию с этими компонентами, смешанную с магией для остальной части рендеринга.
Что касается вашей камеры, просто установите для камер активный флаг и, возможно, индекс «глубины», и позвольте графической системе отобразить все из них, которые включены. Это на самом деле удобно для многих хитростей, включая GUI (хотите, чтобы ваш GUI отображался в орфографическом режиме на вершине игрового мира? Нет проблем, это всего лишь две камеры с разными масками объектов и GUI с более высоким уровнем). Это также полезно для слоев со спецэффектами и тому подобного.
источник
Я не уверен, что этот вопрос действительно задает. Если в игре есть только объекты, то камеры должны быть объектами. Функциональность камеры реализована через какой-то компонент камеры. Не используйте отдельные компоненты «Положение» и «Вращение» - это слишком низкий уровень. Они должны быть объединены в какой-то компонент WorldPosition, который будет применяться к любому объекту, расположенному в мире. Что касается того, что использовать ... вы должны каким-то образом ввести логику в систему. Либо вы жестко запрограммировали его в систему обработки камер, либо вложили сценарии, либо что-то еще. Вы можете иметь флаг включения / выключения на компоненте камеры, если это помогает.
Я тоже. Излучатель частиц будет сущностью, а система частиц будет отслеживать частицы, связанные с данной сущностью. Такие вещи, когда вы понимаете, что «все является сущностью» абсурдно непрактичны. На практике единственными объектами являются относительно сложные объекты, которые выигрывают от сочетаний компонентов.
Что касается ввода: ввод не существует в игровом мире как таковой, поэтому он обрабатывается системой. Не обязательно «система компонентов», потому что не все в вашей игре будет вращаться вокруг компонентов. Но будет система ввода. Возможно, вы захотите пометить сущность, которая реагирует на ввод, каким-то компонентом Player, но ввод будет сложным и полностью специфичным для игры, поэтому нет смысла пытаться создать компоненты для этого.
источник
Вот некоторые из моих идей по решению этих проблем. Возможно, у них что-то не так, и, возможно, будет лучший подход, поэтому, пожалуйста, направьте меня к тем, кто ответит!
Камера :
Существует компонент «Камера», который можно добавить к любому объекту. Однако я не могу понять, какие данные мне следует поместить в этот компонент: у меня могут быть отдельные компоненты «Положение» и «Поворот»! Этот
follow
метод не нуждается в реализации, потому что он уже следует сущности, к которой он присоединен! И я могу свободно перемещать это. Проблема с этой системой будет заключаться в большом количестве различных объектов камеры: какRendererSystem
узнать, какие из них использовать? Кроме того, раньше я просто передавал объект камеры, но теперь кажется, чтоRendererSystem
нужно будет выполнить итерацию дважды по всем объектам: во-первых, чтобы найти те, которые действуют как камеры, и, во-вторых, чтобы фактически отобразить все.ParticleEmitter :
Там будет
ParticleSystem
обновление, которое обновляло бы все сущности, которые имели компонент Emitter. Частицы - это тупые объекты в относительном координатном пространстве внутри этого компонента. Здесь возникает проблема рендеринга: мне нужно либо создатьParticleRenderer
систему, либо расширить функциональность существующей.Система ввода :
Главной заботой для меня здесь была логика или
react()
метод. Единственное решение, которое я придумал, - это отдельная система для этого и компонент для каждой системы, который бы указывал, какую из них использовать. Это действительно кажется слишком глупым, и я не знаю, как с этим справиться. Одна вещь заключается в том, что, насколько мне известно, реализацияInput
может быть реализована как класс, но я не понимаю, как я могу интегрировать ее в остальную часть игры.источник