Наследование Angelscript от класса C ++

Я почесал голову над этим в течение нескольких дней, подумал, что у вас, ребята, может быть есть идея получше.

По сути, я хочу определить стандартный интерфейс, который затем можно унаследовать в классах Angelscript. Например, скажем, у меня есть карточная игра, такая как Magic The Gathering, мой базовый класс может выглядеть так:

class Card
{
public:
virtual void PreDrawPhase() = 0;
virtual void PostDrawPhase() = 0;
// etc....
};

Затем я хочу иметь возможность определять новые карты и их соответствующее поведение в Angelscript, в то же время имея возможность обрабатывать их в C ++ (путем обработки интерфейса). Как мне этого добиться?

0

Решение

Отказ от ответственности: я никогда не использовал 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();
}

Я считаю, что код довольно понятен (поправьте меня, если я ошибаюсь, и я попытаюсь уточнить), поэтому я просто опишу основную идею:

  • Каждый экземпляр Card содержит указатель на некоторый объект Angelscript, который имеет некоторый произвольный тип, реализующий желаемый интерфейс (единственный способ, которым это применяется в настоящее время, — сбой, если что-то пошло не так, что отчасти плохо).
  • По построению это создается (из переданных в engine, context и names) и указатели на его функции-члены накапливаются, при уничтожении оно освобождается.
  • Каждый раз, когда вызывается член, он пересылается соответствующему члену объекта Angelscript.

Как уже упоминалось в начале, я не очень разбираюсь в Angelscript, так что это действительно может быть очень неоптимальный метод, и вполне приемлемые лучшие решения существуют.

0

Другие решения