В настоящее время я пытаюсь реализовать систему сущностей, основанную на компонентах, где сущность - это в основном просто ID и несколько вспомогательных методов, связывающих кучу компонентов вместе для формирования игрового объекта. Некоторые цели этого включают:
- Компоненты содержат только состояние (например, положение, состояние, количество боеприпасов) => логика переходит в «системы», которые обрабатывают эти компоненты и их состояние (например, PhysicsSystem, RenderSystem и т. Д.)
- Я хочу реализовать компоненты и системы как на чистом C #, так и с помощью сценариев (Lua). По сути, я хочу иметь возможность определять совершенно новые компоненты и системы непосредственно в Lua без необходимости перекомпиляции моего источника C #.
Сейчас я ищу идеи о том, как эффективно и последовательно справляться с этим, поэтому мне не нужно использовать другой синтаксис для доступа, например, к компонентам C # или Lua.
Мой текущий подход заключается в реализации компонентов C # с использованием обычных, открытых свойств, вероятно, украшенных некоторыми атрибутами, сообщающими редактору о значениях по умолчанию и прочем. Тогда у меня был бы класс C # «ScriptComponent», который просто оборачивает таблицу Lua внутри, при этом эта таблица создается скриптом и содержит все состояния этого конкретного типа компонента. Я не очень хочу получать доступ к этому состоянию со стороны C #, так как я не знаю во время компиляции, какие ScriptComponents с какими свойствами будут доступны для меня. Тем не менее, редактору потребуется доступ к этому, но достаточно простого интерфейса, подобного следующему:
public ScriptComponent : IComponent
{
public T GetProperty<T>(string propertyName) {..}
public void SetProperty<T>(string propertyName, T value) {..}
}
Это просто получит доступ к таблице Lua, установит и получит эти свойства из Lua, и его также можно будет легко включить в чистые компоненты C # (но затем использовать обычные свойства C # через отражение или что-то в этом роде). Это будет использоваться только в редакторе, а не в обычном игровом коде, поэтому производительность здесь не так важна. Было бы необходимо сгенерировать или написать вручную некоторые описания компонентов, документирующие, какие свойства на самом деле предлагает определенный тип компонентов, но это не было бы большой проблемой и могло бы быть достаточно автоматизировано.
Однако как получить доступ к компонентам со стороны Lua? Если я сделаю вызов чего-то подобного, getComponentsFromEntity(ENTITY_ID)
я, вероятно, просто получу набор нативных компонентов C #, в том числе ScriptComponent, в качестве пользовательских данных. Доступ к значениям из свернутой таблицы Lua приведет к тому, что я вызову GetProperty<T>(..)
метод вместо прямого доступа к свойствам, как с другими компонентами C #.
Может быть, написать специальный getComponentsFromEntity()
метод, который будет вызываться только из Lua, который возвращает все нативные компоненты C # в качестве пользовательских данных, кроме «ScriptComponent», где вместо этого он будет возвращать упакованную таблицу. Но будут другие методы, связанные с компонентами, и я не хочу дублировать все эти методы как для вызова из кода C #, так и из сценария Lua.
Конечная цель состоит в том, чтобы обрабатывать все типы компонентов одинаково, без особого синтаксиса различий между нативными компонентами и компонентами Lua - особенно со стороны Lua. Например, я бы хотел написать сценарий Lua следующим образом:
entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")
nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3
Скрипт не должен заботиться о том, какой компонент он на самом деле получил, и я хотел бы использовать те же методы, которые я использовал бы на стороне C #, для извлечения, добавления или удаления компонентов.
Может быть, есть примеры реализации интеграции сценариев с такими системами сущностей?
Ответы:
Следствием ответа FXIII в том , что вы должны разработать все (что было бы moddable) на языке сценариев первого (или , по крайней мере, очень приличная часть) , чтобы гарантировать , что ваша логика интеграции на самом деле положения для моддинга. Когда вы уверены , что ваша интеграция сценариев является универсальным достаточно переписать необходимые биты в C #.
Я лично ненавижу эту
dynamic
функцию в C # 4.0 (я - наркоман из статического языка) - но это, без сомнения, сценарий, где его следует использовать и где он действительно сияет. Ваши компоненты C # будут просто сильными / расширенными поведенческими объектами .Ваши компоненты Lua будут полностью динамическими (та же самая статья выше должна дать вам представление о том, как это реализовать). Например:
Теперь, поскольку вы используете,
dynamic
вы можете использовать объекты Lua, как если бы они были реальными классами в C #.источник
Я бы предпочел сделать наоборот: написать все, используя динамический язык, а затем отследить узкие места (если есть). Найдя его, вы можете выборочно переопределить функции, задействованные с использованием C # или (точнее) C / C ++.
Я говорю вам это главным образом потому, что пытаюсь ограничить гибкость вашей системы в части C #; по мере усложнения системы ваш «движок» C # начнет выглядеть как динамический интерпретатор, вероятно, не самый лучший. Вопрос в том, готовы ли вы посвятить большую часть своего времени написанию универсального движка C # или расширению своей игры?
Если ваша цель - вторая, как я полагаю, вы, вероятно, будете тратить свое время на то, чтобы сосредоточиться на игровой механике и позволить опытному интерпретатору запускать динамический код.
источник