Я почесал голову над этим в течение нескольких дней, подумал, что у вас, ребята, может быть есть идея получше.
По сути, я хочу определить стандартный интерфейс, который затем можно унаследовать в классах Angelscript. Например, скажем, у меня есть карточная игра, такая как Magic The Gathering, мой базовый класс может выглядеть так:
class Card
{
public:
virtual void PreDrawPhase() = 0;
virtual void PostDrawPhase() = 0;
// etc....
};
Затем я хочу иметь возможность определять новые карты и их соответствующее поведение в Angelscript, в то же время имея возможность обрабатывать их в C ++ (путем обработки интерфейса). Как мне этого добиться?
Отказ от ответственности: я никогда не использовал Angelscript ни в одном «реальном» проекте, поэтому следующий ответ должен быть взят с крошкой соли. Он работал в небольшом тестовом коде, который я настроил для него, и большинство фрагментов кода были подробно объяснены в официальное руководство, но это абсолютно не гарантирует, что это продуманный дизайн и его можно разумно использовать в вашей игре.
Я полагаю, что соответствующие части для достижения вашей цели довольно хорошо описаны в официальное руководство:
это описывает, как определить и использовать интерфейс.
это описывает, как создать и использовать «Классы сценариев» из C ++.
Используя эту информацию, мы могли бы потенциально написать упрощенный класс-обертку, который при создании создает экземпляр определенного класса и освобождает его при уничтожении, одновременно предоставляя функции-члены, которые вызывают соответствующие члены класса сценария:
(Примечание: для краткости я опустил всю обработку ошибок и некоторые другие важные практики, такие как Правило Дерева(Класс ниже не может быть скопирован, не ломая много …))
Заголовок:
class Card
{
public:
Card(asIScriptEngine *engine, asIScriptContext *ctx, const std::string &module_name, const std::string &class_name);
~Card();
void PreDrawPhase();
void PostDrawPhase();
private:
asIScriptContext *ctx;
asIScriptObject *obj;
asIScriptFunction *PreDrawPhaseFunc, *PostDrawPhaseFunc;
};
Реализация:
Card::Card(asIScriptEngine *engine, asIScriptContext *ctx, const std::string &module_name, const std::string &class_name):
ctx(ctx)
{
asIScriptModule *module = engine->GetModule(module_name.c_str());
auto type_id=module->GetTypeIdByDecl(class_name.c_str());
asIObjectType *type = engine->GetObjectTypeById(type_id);
PreDrawPhaseFunc=type->GetMethodByDecl("void PreDrawPhase()");
PostDrawPhaseFunc=type->GetMethodByDecl("void PostDrawPhase()");
asIScriptFunction *factory = type->GetFactoryByDecl((class_name+" @"+class_name+"()").c_str());
ctx->Prepare(factory);
ctx->Execute();
obj=*(asIScriptObject**)ctx->GetAddressOfReturnValue();
obj->AddRef();
}
Card::~Card()
{
obj->Release();
}
void Card::PreDrawPhase()
{
ctx->Prepare(PreDrawPhaseFunc);
ctx->SetObject(obj);
ctx->Execute();
}
void Card::PostDrawPhase()
{
ctx->Prepare(PostDrawPhaseFunc);
ctx->SetObject(obj);
ctx->Execute();
}
Я считаю, что код довольно понятен (поправьте меня, если я ошибаюсь, и я попытаюсь уточнить), поэтому я просто опишу основную идею:
Как уже упоминалось в начале, я не очень разбираюсь в Angelscript, так что это действительно может быть очень неоптимальный метод, и вполне приемлемые лучшие решения существуют.