AngelScript

в 13:00, , рубрики: AngelScript, c++, scripts, впечатления, Программирование, метки: , , ,

Введение

В процессе рассмотрения LUA и Python я выделил для себя, что LUA является достаточно быстрым, но с немного непривычным синтаксисом. Python же обладает очень простым синтаксисом и массой полезных библиотек, но, к сожалению, он оказался довольно медленным, и его довольно тяжело привязывать к С++. И тут на работе мне подсказали использовать AngelScript, мол, он удобный для связки, быстрее LUA и имеет С-подобный синтаксис. Как только я начал его изучать, я понял, что это тот самый скриптовый язык моей мечты.

Превью

Вот что можно прочитать про этот язык на Википедии:

AngelScript представляет собой движок, в котором приложение может регистрировать функции, свойства и типы, которые могут использоваться в скриптах. Скрипты компилируются в модули. Количество используемых модулей варьрируется в зависимости от нужд. Приложение может также использовать различные интерфейсы для каждого модуля с помощью групп конфигурации. Это особенно полезно, когда приложение работает с несколькими типами скриптов, например, GUI, AI и т.д.

Программа «Hello, world» в простейшем случае выглядит так:


void main()
{
print("Hello worldn");
}


Да, синтаксис языка радует с самого начала. Язык поддерживает как методы функционального программирования, так и ООП. С самого начала он подкупает своей простотой регистрации функций, переменных, типов.

Например, регистрация глобальной переменной:

g_Engine->RegisterGlobalProperty("int SomeVal",&SomeVal);

где SomeVal — это переменная типа int.

Регистрация глобальной функции:

g_Engine->RegisterGlobalFunction("void Print(string val)",
asFUNCTION(Print), asCALL_CDECL);

void Print(string val)
{
cout<<val.data();
}

Да, для AngelScript не нужно писать функции биндинга, что является огроменным плюсом в сравнении с другими языками. Для регистрации своих типов придётся написать парочку функций. Фабрику для создания экземпляров и счётчик ссылок, для типа Тип-ссылка, и вызовы конструктора и деструктора, для объекта типа Тип-значение.

Например, у нас есть класс float3, который мы хотели бы зарегистрировать.

// класс счётчик ссылок
class RefC
{
private:
int refC;
public:
RefC(){refC=1;}
void AddRef(){refC++;}
void Release()
{
if(!--refC)
delete this;
}
};

// Класс, который мы хотим зарегистрировать
class float3:public RefC
{
public:
float x;
float y;
float z;

float3(){x=y=z=0;}

void Normalize()
{
float Len=sqrt(x*x+y*y+z*z);
Len=Len?Len:1;
x/=Len;
y/=Len;
z/=Len;
}
}

// Фабрика
float3* Float3FactoryE()
{
return new float3();
}

// Функция вывода на экран
void PrintF3(float3* val)
{
cout<<"x="<<val->x<<",y="<<val->y<<",z="<<val->z;
}

Для этого мы регистрируем объект как Тип-ссылка и указываем ему фабрику, счётчик ссылок, метод и функцию вывода данных на экран, и вот как это выглядит.

g_Engine->RegisterObjectType("float3",0,asOBJ_REF);

g_Engine->RegisterObjectMethod("float3"," void Normalize()",asMETHOD(float3, Normalize),asCALL_THISCALL);
g_Engine->RegisterObjectBehaviour("float3",asBEHAVE_FACTORY,"float3@ new_float3()",asFUNCTION(Float3FactoryE),asCALL_CDECL);
g_Engine->RegisterObjectBehaviour("float3",asBEHAVE_ADDREF,"void AddRef()",asMETHOD(float3,AddRef),asCALL_THISCALL);
g_Engine->RegisterObjectBehaviour("float3",asBEHAVE_RELEASE,"void Release()",asMETHOD(float3,Release),asCALL_THISCALL);

g_Engine->RegisterGlobalFunction("void Print(float3@ val)",asFUNCTION(PrintF3),asCALL_CDECL);

Мы на этом конечно же не остановимся, так как нам нужен доступ к значениям xyz, поэтому их мы тоже должны зарегистрировать, что мы и делаем написав.

g_Engine->RegisterObjectProperty("float3","float x",offsetof(float3,x));
g_Engine->RegisterObjectProperty("float3","float y",offsetof(float3,y));
g_Engine->RegisterObjectProperty("float3","float z",offsetof(float3,z));

Всё предельно просто и понятно. Теперь в скрипте можно написать

float3@ ObjPos;
ObjPos.x=1;
ObjPos.y=2;
ObjPos.z=3;

ObjPos.Normalize();
Print( ObjPos );

Выполнив этот скрипт, мы увидим на экране значение нормализованного вектора.

Особенности

Меня очень порадовала возможность перегрузки операторов в AngelScript. В С++ для это существует ключевое слово operator и символ оператора. AngelScript для этого использует определённые функции.

♦ – opNeg
♦ ~ opCom
♦ ++ opPreInc
♦ — opPreDec
♦ ++ opPostInc
♦ — opPostDec
♦ == opEquals
♦ != opEquals
♦ < opCmp
♦ <= opCmp
♦ > opCmp
♦ >= opCmp
♦ = opAssign
♦ += opAddAssign
♦ -= opSubAssign
♦ *= opMulAssign
♦ /= opDivAssign
♦ &= opAndAssign
♦ |= opOrAssign
♦ ^= opXorAssign
♦ %= opModAssign
♦ <<= opShlAssign
♦ >>= opShrAssign
♦ >>>= opUShrAssign
♦ + opAdd opAdd_r
♦ — opSub opSub_r
♦ * opMul opMul_r
♦ / opDiv opDiv_r
♦ % opMod opMod_r
♦ & opAnd opAnd_r
♦ | opOr opOr_r
♦ ^ opXor opXor_r
♦ << opShl opShl_r
♦ >> opShr opShr_r
♦ >>> opUShr opUShr_r
♦ [] opIndex

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

class float3:public RefC
{
public:
float x;
float y;
float z;

float3(){x=y=z=0;}

void Normalize()
{
float Len=sqrt(x*x+y*y+z*z);
Len=Len?Len:1;
x/=Len;
y/=Len;
z/=Len;
}

float3* operator+=(float3* _rval)
{
x+=_rval->x;
y+=_rval->y;
z+=_rval->z;
this->AddRef();
return this;
}
};


Осталось только зарегистрированный новый метод.

g_Engine->RegisterObjectMethod("float3", "float3@ opAddAssign(float3@ _rval)",
asMETHOD(float3, operator+=), asCALL_THISCALL);

И теперь можно спокойно писать так:

float3@ ObjPos;
ObjPos.x=1;
ObjPos.y=2;
ObjPos.z=3;

float3@ ObjOffset;
ObjOffset .x=3;
ObjOffset .y=1;
ObjOffset .z=5;

ObjPos+=ObjOffset ;
Print( ObjPos );

и мы увидим на экране x=4, y=3, z=8.

AngelScript поддерживает свойства. Выглядит это так:

class MyObj
{
type get_ValueName();
type set_ValueName(type Val);
}
MyObj a;
type tmp=a.ValueName;// вызовется get_ValueName
a.ValueName = tmp; // вызовется set_ValueName

Также свойства поддерживаются для оператора индекса:

class MyObj
{
float get_opIndex(int idx) ;
void set_opIndex(int idx, float value);
}
MyObj a;
float val=a[1];// вызовется get_opIndex
a[2]=val;// вызовется set_opIndex

Полезные ссылки

Сайт разработчиков www.angelcode.com/
SVN Репозиторий на WIP angelscript.svn.sourceforge.net/svnroot/angelscript/trunk
Русский мануал 13d-labs.com/angelscript_manual/main.html
Мануал на английском www.angelcode.com/angelscript/sdk/docs/manual/index.html
JIT Компилятор github.com/BlindMindStudios/AngelScript-JIT-Compiler

Автор: Chaos_Optima

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js