Я знаю, что этот вопрос задавался несколько раз, но я все еще не уверен, как реализовать обработку ввода в компонентном движке.
Основанный на компонентах дизайн, который я использовал, был основан на серии блогов T = Machine и на Artemis, в которых сущности - это просто идентификаторы.
У меня есть три основные идеи по реализации обработки ввода:
- Компонент ввода будет содержать интересующие его события. Система ввода преобразует события клавиш и мыши в игровые события и проходит по объектам с компонентом ввода, и, если они заинтересованы в событии, система ввода предпримет соответствующее действие. Это действие будет жестко закодировано в системе ввода.
- Нет входного компонента. Вы должны зарегистрировать объекты с конкретными событиями в системе ввода. Затем система ввода будет отправлять сообщения (с идентификатором объекта и типом события) в другие системы, чтобы они могли предпринять соответствующие действия. Или, как в первом случае, действия будут жестко закодированы в системе ввода.
- Аналогично первому методу, но вместо жесткого кодирования действия для системы ввода компонент будет содержать карту событий для функций (то есть
std::map<std::function>
), которые будут вызываться системой ввода. Это дает дополнительный эффект возможности связывать одно и то же событие с разными действиями.
Вы бы порекомендовали какой-либо из вышеперечисленных методов или у вас есть предложения, которые помогли бы мне внедрить гибкую систему обработки ввода? Кроме того, я еще не знаком с многопоточностью, но любые предложения, которые сделают реализацию ориентированной на многопоточность, также приветствуются.
Примечание. Одно дополнительное требование, которое я хотел бы выполнить для реализации, заключается в том, чтобы я мог передавать один и тот же вход многим объектам, например, перемещая объект камеры и проигрыватель одновременно.
источник
Ответы:
Я думаю, что, так же как и мой ответ относительно материалов в системе компонентов , вы столкнулись с проблемой, когда вы пытаетесь засунуть все в «компонент». Вам не нужно этого делать, и при этом вы, вероятно, создаете действительно громоздкий интерфейс, пытаясь вставить несколько квадратных колышков в круглые отверстия.
Похоже, у вас уже есть система, которая обрабатывает ввод данных от игрока. Я бы выбрал подход, который затем переводит этот вклад в действия («двигаться вперед» или «двигаться назад») или события и рассылает их заинтересованным сторонам. В прошлом я запрещал компонентам регистрировать себя для этих событий, предпочитая подход, в котором система более высокого уровня явно выбирала «контролируемую сущность». Но это может работать иначе, если вы предпочитаете, особенно если вы собираетесь повторно использовать одни и те же сообщения для выполнения действий, которые не были стимулированы непосредственно вводом.
Однако я не обязательно предлагал бы реализовать поведение следования за камерой, если бы и объект камеры, и объект игрока отвечали на сообщение «двигаться вперед» (и так далее). Это создает чрезвычайно жесткую связь между двумя объектами, которая, вероятно, не будет хорошо восприниматься игроком, а также усложняет управление такими вещами, как вращение камеры вокруг игрока, когда игрок вращается влево или вправо: у вас есть объект реагируя на «повернуть налево», предполагая, что он подчинен игроку, но это означает, что он не может правильно реагировать, если он когда-либо не был ведомым ... если вы не представите эту концепцию как некое состояние, которое вы можете проверить. И если вы собираетесь это сделать, вы также можете реализовать правильную систему для подчинения двух физических объектов вместе с соответствующими настройками эластичности и так далее.
Что касается многопоточности, я на самом деле не вижу необходимости использовать его здесь, так как это, вероятно, вызовет больше сложностей, чем оно того стоит, и вы имеете дело с по своей сути последовательной проблемой, так что вам просто нужно задействовать много потоков примитивы синхронизации.
источник
Мой опыт может быть предвзятым, но в мультиплатформенных проектах устройства ввода напрямую не связаны с системой сущностей.
Устройства ввода обрабатываются системой более низкого уровня, которая получает события от клавиш, кнопок, оси, мыши, сенсорных поверхностей, акселерометров ...
Эти события затем отправляются через слой контекстно-зависимых генераторов намерений.
Каждый генератор регистрирует изменения состояния компонентов, объектов и систем, которые имеют отношение к его функциям.
Затем эти генераторы отправляют сообщения / намерения для маршрутизации в систему намерений, где у сущностей есть компонент, или напрямую в нужные компоненты.
Таким образом, вы можете просто полагаться на «всегда», имеющее один и тот же вход, то есть JUMP_INTENT (1), JUMP_INTENT (0), AIM_INTENT (1) ...
И «вся» грязная работа, зависящая от платформы, остается за пределами вашей системы сущностей.
Что касается камеры, если вы хотите перемещать ее по проигрывателю, она может зарегистрировать свой собственный компонент намерений и прослушать намерения, которые вы отправите.
В противном случае, если он следует за игроком, он никогда не должен слушать входы, предназначенные для игрока. Он должен слушать изменения состояния, испускаемые игроком (ENTITY_MOVED (transform)) ... и двигаться соответственно. Если вы используете физическую систему, вы можете даже прикрепить камеру к плееру с помощью одного из различных соединений.
источник
Какую пользу приносит InputComponent? Конечно, прерогативой входной команды является определение того, над какими объектами она выполняет действие. Классический пример - прыжок игрока. Вместо того чтобы иметь InputComponent на каждом объекте, прослушивающем события «Jump», почему бы не выполнить команду перехода для поиска объекта, помеченного как «player», и выполнить саму необходимую логику?
Еще один пример из ОП:
источник