gooブログはじめました!

写真付きで日記や趣味を書くならgooブログ

angelscriptを使用しているアプリやツール調査

2012-08-16 20:02:20 | angelscript
このブログを始めたころはangelscriptの情報がほどんどなく、スクリプトを学習するためであったが、スマホとくにandroidのプログラムの方が面白くてangelscriptのことがおろそかになっていたので、再度、情報収集してみた。


1.angelscript 本家
http://www.angelcode.com/angelscript/
AngelScript 2.24.1 (August 7th, 2012)
2012/8/7 version2.24.1がリリース







2.angelscript日本語訳
http://dl.dropbox.com/u/91791736/manual/index.html
ついに日本語訳が、書いている人はつかわないけど面白そうということで日本語訳を公開してくれているようです。
また、zipでローカルで参照できます。感謝。


3.angelscirptJIT
https://github.com/BlindMindStudios/AngelScript-JIT-Compiler
luaJITもでていたけど、ついにangelscriptもJust-In-Time(ネイティブに変換して実行)のプロジェクトがスタートしていた。
海外の人はすごいね。



4.ethanon engine
http://www.asantee.net/ethanon/
http://sourceforge.net/projects/ethanon/files/
http://www.asantee.net/ethanon/doc/ (英語マニュアル)
2Dゲームツール(エフェクト)でangelscirptを使用(本家は中国語だが、英語マニュアルあり)




5.Siv3D
https://sites.google.com/site/siv3dgameengine/
早稲田大学の学生さんが作成しているゲームエンジンの一般公開版(アルファ)。
動作環境:Windows Vista SP2, または Windows 7
Direct3D 10 対応の GPU ( GeForce 8400- , Radeon HD 2400-, Intel HD Graphics ) を搭載
ライセンス:MIT
日本人が作成しているゲームエンジンなので、いじってみたいが、自宅のpcがxpのためいじれない。
ブログを読んだところ、angelscriptでいろいろ関数をコールできるようにしてあるらしい。
日本人が開発して、現在もメンテされているエンジンが少なくなってきているので、できれば末長く開発を続けてもらいたい
プロジェクトです。





使えそう、および使ってみたいものをピックアップしてみたが、angelscriptを使用するプロジェクトが増えてきて嬉しい。
当初luaを学習するつもりであったが、あまりにも独特の文法なため挫折。学習しているときに発見したangelscriptの
ほうが使用しやすいと感じたためそちらを学習しようと決断したことが間違いではなかったと、言える日がくるといいな。





関数ポインタのサンプル

2010-04-03 15:39:47 | angelscript

関数ポインタのサンプル

angelscriptのconcurrentのsampleに関数ポインタを追加してみる。 *script3に関数ポインタを追加。
angelscriptのスクリプト内でfuncdefの後に戻り値、関数名、引数を定義して関数ポインタを宣言する。
funcdef int CALLBACK(int, int);
宣言した関数ポインタの変数に実際の関数を登録する。
CALLBACK @func=@add;
関数ポインタに各関数を設定する。
@funcに足し算用の関数ポインタを設定
@func=@add;
@funcに引き算用の関数ポインタを設定
@func=@sub;
@funcにかけ算用の関数ポインタを設定
@func=@mul;
@funcに割り算用の関数ポインタを設定
@func=@div;

<form>

関数ポインタのサンプル


<textarea rows="8" cols="75" readonly="readonly">#include <iostream>  // cout #include <assert.h>  // assert() #include <string.h>  // strstr() #include <angelscript.h> #include "../../../add_on/scriptstring/scriptstring.h" #include "../../../add_on/contextmgr/contextmgr.h" #if defined(_MSC_VER) #include <crtdbg.h> #endif #ifdef _LINUX_ #include <sys/time.h> #include <stdio.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #elif defined(__APPLE__) #include <curses.h> #else #include <conio.h>   // kbhit(), getch() #include <windows.h> // timeGetTime() #endif using namespace std; #ifdef _LINUX_ #define UINT unsigned int typedef unsigned int DWORD; // Linux doesn't have timeGetTime(), this essintially does the same // thing, except this is milliseconds since Epoch (Jan 1st 1970) instead // of system start. It will work the same though... DWORD timeGetTime() { timeval time; gettimeofday(&time, NULL); return time.tv_sec*1000 + time.tv_usec/1000; } // kbhit() for linux int kbhit() { struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF) { ungetc(ch, stdin); return 1; } return 0; } #elif defined(__APPLE__) #define UINT unsigned int typedef unsigned int DWORD; // Linux doesn't have timeGetTime(), this essintially does the same // thing, except this is milliseconds since Epoch (Jan 1st 1970) instead // of system start. It will work the same though... DWORD timeGetTime() { timeval time; gettimeofday(&time, NULL); return time.tv_sec*1000 + time.tv_usec/1000; } int kbhit() { if( getch() == ERR ) return 0; return 1; } #endif // Function prototypes void ConfigureEngine(asIScriptEngine *engine); int  CompileScript(asIScriptEngine *engine); void PrintString(string &str); void PrintNumber(int num); void MessageCallback(const asSMessageInfo *msg, void *param) { const char *type = "ERR "; if( msg->type == asMSGTYPE_WARNING ) type = "WARN"; else if( msg->type == asMSGTYPE_INFORMATION ) type = "INFO"; printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); } CContextMgr contextManager; asIScriptEngine *engine = 0; int main(int argc, char **argv) { #if defined(_MSC_VER) _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); _CrtSetReportMode(_CRT_ASSERT,_CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ASSERT,_CRTDBG_FILE_STDERR); // Use _CrtSetBreakAlloc(n) to find a specific memory leak //_CrtSetBreakAlloc(924); #endif int r; // Setup the context manager contextManager.SetGetTimeCallback((TIMEFUNC_t)&timeGetTime); // Create the script engine engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); //add shis engine->SetEngineProperty(asEP_SCRIPT_SCANNER ,0); if( engine == 0 ) { cout << "Failed to create script engine." << endl; return -1; } // The script compiler will send any compiler messages to the callback function engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL); // Configure the script engine with all the functions, // and variables that the script should be able to use. ConfigureEngine(engine); // Compile the script code r = CompileScript(engine); if( r < 0 ) return -1; //contextManager.AddContext(engine, engine->GetModule("script1")->GetFunctionIdByDecl("void main()")); //contextManager.AddContext(engine, engine->GetModule("script2")->GetFunctionIdByDecl("void main()")); //script func pointer check start contextManager.AddContext(engine, engine->GetModule("script3")->GetFunctionIdByDecl("void main()")); //script func pointer check end // Print some useful information and start the input loop cout << "This sample shows how two scripts can be executed concurrently." << endl; cout << "Both scripts voluntarily give up the control by calling sleep()." << endl; cout << "Press any key to terminate the application." << endl; for(;;) { // Check if any key was pressed if( kbhit() ) { contextManager.AbortAll(); break; } // Allow the contextManager to determine which script to execute next contextManager.ExecuteScripts(); } // Release the engine engine->Release(); return 0; } void ConfigureEngine(asIScriptEngine *engine) { int r; // Register the script string type // Look at the implementation for this function for more information  // on how to register a custom string type, and other object types. // The implementation is in "/add_on/scriptstring/scriptstring.cpp" RegisterScriptString(engine); // Register the functions that the scripts will be allowed to use r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void Print(int)", asFUNCTION(PrintNumber), asCALL_CDECL); assert( r >= 0 ); // Register the functions for controlling the script threads, e.g. sleep contextManager.RegisterThreadSupport(engine); } int CompileScript(asIScriptEngine *engine) { int r; // This script prints a message 3 times per second const char *script1 = "int count = 0;                     " "void main()                        " "{                                  "     "  for(;;)                          " "  {                                " "    Print(\"script1 methjod beign\\n \");                " "    Print(\"A 日本語 カタカナ ひらがな sjis:\");                " "    Print(count++);                " "    Print(\"\\n\");                " "    Print(\"script1 methjod end\\n \");                " "    sleep(333);                    " "  }                                " "}                                  "; // This script prints a message once per second const char *script2 = "int count = 0;                     " "void main()                        " "{                                  " "  for(;;)                          " "  {                                " "    Print(\"script2 methjod beign\\n \");                " "    Print(\" B:\");                " "    Print(count++);                " "    Print(\"\\n\");                " "    Print(\"script2 methjod end\\n \");                " "    sleep(1000);                   " "  }                                " "}                                  "; //script func pointer check start const char *script3 = "funcdef int CALLBACK(int, int); \n" "CALLBACK @func=@add; \n" "int count = 0; \n" "int testcase = 0; \n" "void main() \n" "{ \n" "int ret; \n" "  for(;;) \n" "  { \n" "    Print(\" script3 method begin \\n\"); \n" " count++; \n" " testcase = count % 4; \n" "    Print(testcase); \n" "    Print(\"\\n\"); \n" "    switch( testcase ) \n" "    { \n" "      case 0: \n" "          @func=@add; \n" "    Print(\" func is add function.\");   \n" "          break; \n" "      case 1: \n" "          @func=@sub; \n" "    Print(\" func is sub function.\");   \n" "          break; \n" "      case 2: \n" "          @func=@mul; \n" "    Print(\" func is mul function.\");   \n" "          break;     \n" "      case 3: \n" "          @func=@div; \n" "    Print(\" func is div function.\");   \n" "          break;     \n" "      default: \n" "          @func=@add; \n" "    Print(\" func is add function.\");   \n" "          break; \n" "    }                              \n" "    ret = func(1,count);         \n" "    Print(\"ret:\");               \n" "    Print(ret);                    \n" "    Print(\"\\n\");                \n" "    Print(\" script3 method end \\n\");                \n" "    sleep(1000);                   \n" "  }                                \n" "}                                  \n" "int add(int a, int b)              \n" "{                                  \n" "  return a + b;                    \n" "}                                  \n" "int sub(int a, int b)              \n" "{                                  \n" "  return a - b;                    \n" "}                                  \n" "int mul(int a, int b)              \n" "{                                  \n" "  return a * b;                    \n" "}                                  \n" "int div(int a, int b)              \n" "{                                  \n" "  return a / b;                    \n" "}                                  \n"; //script func pointer check end // Build the two script into separate modules. This will make them have // separate namespaces, which allows them to use the same name for functions // and global variables. asIScriptModule *mod = engine->GetModule("script1", asGM_ALWAYS_CREATE); r = mod->AddScriptSection("script1", script1, strlen(script1)); if( r < 0 ) { cout << "AddScriptSection() failed" << endl; return -1; } r = mod->Build(); if( r < 0 ) { cout << "Build() failed" << endl; return -1; } mod = engine->GetModule("script2", asGM_ALWAYS_CREATE); r = mod->AddScriptSection("script2", script2, strlen(script2)); if( r < 0 ) { cout << "AddScriptSection() failed" << endl; return -1; } r = mod->Build(); if( r < 0 ) { cout << "Build() failed" << endl; return -1; } //script func pointer check start mod = engine->GetModule("script3", asGM_ALWAYS_CREATE); r = mod->AddScriptSection("script3", script3, strlen(script3)); if( r < 0 ) { cout << "AddScriptSection() failed" << endl; return -1; } r = mod->Build(); if( r < 0 ) { cout << "Build() failed" << endl; return -1; } //script func pointer check end return 0; } void PrintString(string &str) { cout << str; } void PrintNumber(int num) { cout << num; } </textarea>

</form>

angelscript2.18.2リリース

2010-03-21 13:47:16 | angelscript
anglescript2.18.2がリリースされました。
変更点はscriptでグローバル関数に関しては、関数ポインタを使用可能に、keywordにが追加されたみたいです。
doxgenのマニュアルに使い方が追加されています。
2.18.2のchange listをみるとbuf fixのところに日本人「Thanks Hideaki Imaizumi」が指摘したと思われるバグがあります。日本では使用している人がまだ少ないので、すこし嬉しかったです。
http://www.angelcode.com/angelscript/sdk/docs/articles/changes2.html
[shift-jis対応]
shift-jisを使用するためには、以前と同じ場所の修正だけでいいみたいです。
[sampleプログラムコンパイルエラー]
2.18.0からSample プログラムでExecuteString関数を使っている場合、コンパイルエラーになります。こちらも、直してほしかった。

angelscriptにハンドルを登録する

2010-03-07 15:23:53 | angelscript

c++からanglewcriptに配列を渡す手段がないため、DxlibやSeleneでイメージや曲の再生のハンドル値をangelscript側に渡す手段を変更する。手順としては以下のようになる

1.ゲームエンジン(Dxlib,Selene)を初期化する。
2.イメージと音楽をファイルから読み込みハンドル値を保持しておく。
3.angelscriptで配列を使えるように設定しておく。
"add_on/scriptarray/scriptarray.h"のヘッダとscriptarray.cppをプロジェクトに設定しておく。 
4.グローバル変数にasIScriptArrayを宣言しておく。
asIScriptArray *floatArray = 0;
asIScriptArray *stringArray = 0;
5.配列を使えるようにしておく。
iRet = g_pasengine->RegisterGlobalProperty("float[] @floatArray", &floatArray); assert( iRet >= 0 );
iRet = g_pasengine->RegisterGlobalProperty("string[] @stringArray",&stringArray); assert( iRet >= 0 );
6.angelscript側にグローバルな配列(ハンドル値を保持するために使用)を宣言しておく。
angelscript側に配列の長さを変更する関数および、配列のインデックス値にハンドル値を代入するための関数 を用意しておく。 7.c++からそれらの関数を呼び出し、ハンドルをangelscript側でも使えるようにする。

とりあえずはダミーのハンドルをangelscriptに登録する方法は下記のようになる。



<form>

angelscriptで用意する関数

<textarea rows="8" cols="75" readonly="readonly"> int[] g_a(3); string[] g_arstr(3); void SetGlobalArrayLength( int num ) { g_a.resize( num ); print("g_a size");     } void SetMusicHandle( int index, int ihandle ) { if( g_a.length() > index ) { g_a[index] = ihandle; } } void ShowGlobalArray() { for( uint i = 0; i < g_a.length(); i++ ) { print(g_a[i]); } } </textarea>

</form> <form>

c++ ダミーハンドルをangelscript側に登録する処理

<textarea rows="8" cols="75" readonly="readonly">#include <iostream>  // cout #include <assert.h>  // assert() #include <angelscript.h> #include "../../angel_incluce_lib/angel_include/add_on/scriptstring/scriptstring.h" #include "../../angel_incluce_lib/angel_include/add_on/contextmgr/contextmgr.h" #include "../../angel_incluce_lib/angel_include/add_on/scriptstdstring/scriptstdstring.h" #include "../../angel_incluce_lib/angel_include/add_on/scriptbuilder/scriptbuilder.h" #include "../../angel_incluce_lib/angel_include/add_on/scriptany/scriptany.h" #include "../../angel_incluce_lib/angel_include/add_on/scriptarray/scriptarray.h" #include <crtdbg.h> #include <conio.h>   // kbhit(), getch() #include <windows.h> // timeGetTime() #include "AngelFuncMap.h" #include "CAngelScriptMgr.h" using namespace std; #define OK 0 #define NG -1 // Some global variables that the script can access // c++の関数だがscriptからもアクセス可能 asUINT         g_ans; //global cpp asIScriptEngine *g_pasengine; asIScriptModule *g_pasmod; asIScriptContext *g_pasctx; CContextMgr g_contextMgr; //CAngelFuncMap g_angelmap; //angelscript内で配列を使うため asIScriptArray *floatArray = 0; asIScriptArray *stringArray = 0; //prototype int LoadScript( char *ScriptName); void MessageCallback(const asSMessageInfo *msg, void *param); void print(string &msg); void print(int num); void print(asUINT num); void print(float num); void print(double num); int RegisterProperty(); int InitializeAngelEngine(); int ExcuteAngelFunction( char *chFuncID,long &lret,int arg1 = -1,int arg2 = -1); int BuildAngelScript(); //読み込むファイルリスト char *AngleScriptNameList[] = { {"test1.as"}, {"test2.as"}, {"test3.as"}, }; //読み込むangelscriptのファイル数 #define AS_SCRIPT_NUM (sizeof(AngleScriptNameList)/sizeof(AngleScriptNameList[0]) ) //angle scritptないで使用するmethodがふえたらここに追加 //別々のanglescriptにある関数でもここにはすべて記述する。 chDescriptionにはどのファイル名で定義してあるかも記述しておく //asIScriptContextのmethodでangelscriptから戻り値を受け取ることができるのは以下の型のみ //chFuncIDは戻り値の型が違う場合c++側で再コンパイルが必要 //GetReturnAddress(),GetReturnByte(),GetReturnDouble() //GetReturnDWord(),GetReturnFloat(),GetReturnObject() //GetReturnQWord(),GetReturnWord() struct _as_FuncList { int iID; //index、for,while 用途 char *chFuncID; //angle scriptのasIScriptContext->Prepare(funcId); のfuncIdに指定する文字列 char *chDescription; //angle script用の関数説明用 }as_FuncList[] = { {0,"float test1()","print test file:test1.as"}, //{1,"void SetHandle(float farg1 )","print test file:test1.as compile:ok"}, // {1,"void SetImgHandle(int[] &inout a,int iLen )","print test file:test1.as"}, {1,"void SetImgHandle1(int[] &inout a)","print test file:test1.as"}, //{1,"void SetImgHandle2(int[] &inout a,int Len )","print test file:test1.as"}, {2,"float TestSetArgAddressInt( int a, int b)","print test file:test1.as"}, {3,"float TestSetArgAddressFloat( float a, float b)","print test file:test1.as"}, {4,"void TestSetArgAddress(float &out outValue)","print test file:test1.as"}, {5,"float test2()"," file:test2.as"}, {6,"float TestCorutine()","corotine test file::test3.as"}, {7,"void SetGlobalArrayLength( int num )"," test file::test1.as"}, {8,"void SetMusicHandle( int index, int ihandle )"," test file::test1.as"}, {9,"void ShowGlobalArray()"," test file::test1.as"}, }; //anglesciprtで使用する関数の数 #define AS_FUNC_NUM  (sizeof(as_FuncList)/sizeof(as_FuncList[0]) ) // C++ code class CMyObject { public:   int property; }; // -----------------Main class declaration array test ------------------------------- class MyClass { public: int variable[128]; }; // C++ class instance MyClass mc; // Getter proxy int Proxy_get_variable(const MyClass * myclass, int index) { if ((index) > sizeof(myclass->variable) / sizeof(myclass->variable[0])) asGetActiveContext()->SetException("Index out of bounds!"); return myclass->variable[index]; } // Setter proxy void Proxy_set_variable(MyClass * myclass, const int& newint, int index) { if ((index) > sizeof(myclass->variable) / sizeof(myclass->variable[0])) asGetActiveContext()->SetException("Index out of bounds!"); myclass->variable[index] = newint; } // -----------------Main class declaration array test ------------------------------- //------------------other  array------------------------------------------ // Struct definition struct MyStruct {     int health;     char name[32]; //int handle[10]; }; // Struct instance MyStruct mystruct; // Getter proxy function static string Proxy_get_name(const MyStruct * ms) {     int len = strnlen(ms->name, 32);     string name(ms->name, len);     return name; } // Setter proxy function void Proxy_set_name(MyStruct * ms, const string& new_name) {     memset(ms->name, 0, 32);     int len = new_name.length();     if (len > 32) len = 32;     if (len > 0) memcpy(ms->name, new_name.c_str(), len); } //// Getter proxy classでint[]の型を持つhandleは登録できない。 //static int Proxy_get_handle(const MyStruct * myclass, int index) //{ // if ((index) > sizeof(myclass->handle) / sizeof(myclass->handle[0])) // asGetActiveContext()->SetException("Index out of bounds!"); // return myclass->handle[index]; //} // //// Setter proxy //void Proxy_set_handle(MyStruct * myclass, const int& newint, int index) //{ // if ((index) > sizeof(myclass->handle) / sizeof(myclass->handle[0])) // asGetActiveContext()->SetException("Index out of bounds!"); // myclass->handle[index] = newint; //} //------------------other  array------------------------------------------ //angel script用のファイルを読み込む //使用するスクリプトはここですべてよみこんでおく int LoadScript( char *ScriptName) { int iRet = OK; FILE *f = fopen(ScriptName, "rb"); if ( f == NULL ) { printf(" file not found\n"); return NG; } fseek(f, 0, SEEK_END); //file sizeを取得する int len = ftell(f); fseek(f, 0, SEEK_SET); std::string script; script.resize(len); size_t c = fread(&script[0], len, 1, f); fclose(f); //asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); iRet = g_pasmod->AddScriptSection( ScriptName, &script[0], len); return iRet; } void MessageCallback(const asSMessageInfo *msg, void *param) { const char *type = "ERR "; if( msg->type == asMSGTYPE_WARNING ) type = "WARN"; else if( msg->type == asMSGTYPE_INFORMATION ) type = "INFO"; printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); } // Print the script string to the standard output stream //scriptで使用するprint系関数のcpp側の定義 void print(string &msg) {   //printf("%s", msg.c_str()); std::cout << msg << std::endl; } void print(int num) { std::cout << num << std::endl; } void print(asUINT num) { std::cout << num << std::endl; } void print(float num) { std::cout << num << std::endl; } void print(double num) { std::cout << num << std::endl; } //c++,angelscriptない両方で使える関数を登録する(c++側はグローバル変数にする) //用途としてangelscriptでの計算結果をc++側で受け取る、必要な設定値をC++からangelscriptにわたす // int RegisterProperty() { int iRet = OK; iRet = g_pasengine->RegisterGlobalProperty("int g_ans", &g_ans); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalProperty("float[] @floatArray", &floatArray); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalProperty("string[] @stringArray",&stringArray); assert( iRet >= 0 ); return iRet; } //angelscript側で使用するクラス定義をする //classメンバの登録はクラスを登録後にRegisterObjectPropertyを呼びだす int RegisterMyClass() { int iRet = OK; //CMyObject test; iRet = g_pasengine->RegisterObjectType("object", sizeof(CMyObject), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); assert( iRet >= 0 ); if( iRet < 0 ) { return iRet; } iRet = g_pasengine->RegisterObjectProperty("object", "int property", offsetof(CMyObject, property)); assert( iRet >= 0 ); // -----------------Main class declaration array test ng------------------------------- //iRet = g_pasengine->RegisterObjectType("MyClass", sizeof(CMyObject), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); assert( iRet >= 0 ); //iRet = g_pasengine->RegisterObjectProperty("MyClass", "int variable[128]", offsetof(MyClass,variable)); assert( iRet >= 0 ); iRet = g_pasengine->RegisterObjectType("MyClass", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( iRet >= 0 ); // errorになる //iRet = g_pasengine->RegisterObjectProperty("MyClass", "int[] variable", offsetof(MyClass,variable)); assert( iRet >= 0 ); //[variable is not a member of MyClass]となる iRet = g_pasengine->RegisterObjectMethod("MyClass", "int get_variable(int index)", asFUNCTION(Proxy_get_variable), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); //iRet = g_pasengine->RegisterObjectMethod("MyClass", "void set_variable(const string &in, int index)", asFUNCTION(Proxy_set_variable), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); iRet = g_pasengine->RegisterObjectMethod("MyClass", "void set_variable(const int &in, int index)", asFUNCTION(Proxy_set_variable), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalProperty("MyClass mc", &mc); assert( iRet >= 0 ); // -----------------Main class declaration array test ng------------------------------- //------------------other  array ok------------------------------------------ //memcpy(mystruct.name, "IT WORKS!!!\x00", 12); iRet = g_pasengine->RegisterObjectType("MyObject", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( iRet >= 0 ); iRet = g_pasengine->RegisterObjectProperty("MyObject", "int health", offsetof(MyStruct, health)); assert( iRet >= 0 ); iRet = g_pasengine->RegisterObjectMethod("MyObject", "string get_name()", asFUNCTION(Proxy_get_name), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); iRet = g_pasengine->RegisterObjectMethod("MyObject", "void set_name(const string &in)", asFUNCTION(Proxy_set_name), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); // int handle[10]がangelscript側で使えない 何かが違う get_handle,set_handle(const string &in,int index)も // ためしたけど無理だったなんでcharの場合だけできるか理由がわからない。 //iRet = g_pasengine->RegisterObjectProperty("MyObject", "int[] handle", offsetof(MyStruct, handle)); assert( iRet >= 0 ); //iRet = g_pasengine->RegisterObjectMethod("MyObject", "int get_handle(int index)", asFUNCTION(Proxy_get_handle), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); //iRet = g_pasengine->RegisterObjectMethod("MyObject", "void set_handle(const int &in, int index)", asFUNCTION(Proxy_set_handle), asCALL_CDECL_OBJFIRST); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalProperty("MyObject Obj2", &mystruct); assert( iRet >= 0 ); //------------------other  array ok------------------------------------------ return iRet; } //angelscriptengineの初期化 int InitializeAngelEngine() { int iRet = OK; // Create the script engine g_pasengine = asCreateScriptEngine(ANGELSCRIPT_VERSION); // Set the message callback to receive information on errors in human readable form. // It's recommended to do this right after the creation of the engine, because if // some registration fails the engine may send valuable information to the message // stream. //shift-jisを使えるようにEnginePropertyを設定する。 g_pasengine->SetEngineProperty(asEP_SCRIPT_SCANNER ,0); iRet = g_pasengine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL); assert( iRet >= 0 ); if( iRet < 0 ) { printf("failed Message Callback\n" ); return NG; } g_pasmod = g_pasengine->GetModule(0, asGM_ALWAYS_CREATE); if( iRet < 0 ) { printf("failed GetModule\n" ); return NG; } // AngelScript doesn't have a built-in string type, as there is no definite standard // string type for C++ applications. Every developer is free to register it's own string type. // The SDK do however provide a standard add-on for registering a string type, so it's not // necessary to implement the registration yourself if you don't want to. RegisterStdString(g_pasengine); //anglescript側でprint(string,int,float,int,uint)でそれぞれの値を表示できるようにする。print系は複数 //iRet = g_pasengine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalFunction("void print(const string &in)", asFUNCTIONPR(print, (string &in), void), asCALL_CDECL); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalFunction("void print(int)", asFUNCTIONPR(print, (int), void), asCALL_CDECL); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalFunction("void print(float)", asFUNCTIONPR(print, (float), void), asCALL_CDECL); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalFunction("void print(uint)", asFUNCTIONPR(print, (asUINT), void), asCALL_CDECL); assert( iRet >= 0 ); iRet = g_pasengine->RegisterGlobalFunction("void print(double)", asFUNCTIONPR(print, (double), void), asCALL_CDECL); assert( iRet >= 0 ); // Add the support for co-routines ContextMgr test //g_contextMgr.RegisterCoRoutineSupport( g_pasengine ); //g_contextMgr.RegisterThreadSupport( g_pasengine ); //RegisterScriptString( g_pasengine ); RegisterScriptAny( g_pasengine ); // Add the support for co-routines g_contextMgr.RegisterCoRoutineSupport(g_pasengine); return iRet; } //これだとLoadScriptに成功しても、どのangelscriptでエラーになったかわからない //scriptのロード、ビルドは一緒にした方がいい int BuildAngelScript() { int iRet = OK; iRet = g_pasmod->Build(); if( iRet < 0 ) { printf("angel script build failed\n" ); return NG; } return iRet; } //angelscript内の関数に時間がかかる場合はabortを投げて例外終了させる void LineCallback(asIScriptContext *ctx, DWORD *timeOut) { // If the time out is reached we abort the script if( *timeOut < timeGetTime() ) ctx->Abort(); // It would also be possible to only suspend the script, // instead of aborting it. That would allow the application // to resume the execution where it left of at a later // time, by simply calling Execute() again. } int PrepareExcute( char *chFuncID ) { int iRet = OK; int funcId = g_pasmod->GetFunctionIdByDecl(chFuncID); if( funcId < 0 ) {   // The function couldn't be found. Instruct the script writer   // to include the expected function in the script.   printf("The script must have the function %s. Please add it and try again.\n",chFuncID);   return NG; } // Create our context, prepare it, and then execute g_pasctx = g_pasengine->CreateContext(); //anglescriptの関数を実行するための準備 iRet = g_pasctx->Prepare(funcId);  assert( iRet >= 0 ); return iRet; } void ShowErrorMsg( int iRet ) { //angelscript内の関数に実行した場合、エラー表示を行う if(iRet != asEXECUTION_FINISHED ) { // The execution didn't finish as we had planned. Determine why. if( iRet== asEXECUTION_ABORTED ) { cout << "The script was aborted before it could finish. Probably it timed out." << endl; } else if( iRet == asEXECUTION_EXCEPTION ) { cout << "The script ended with an exception." << endl; // Write some information about the script exception int funcID = g_pasctx->GetExceptionFunction(); asIScriptFunction *func = g_pasengine->GetFunctionDescriptorById(funcID); cout << "func: " << func->GetDeclaration() << endl; cout << "modl: " << func->GetModuleName() << endl; cout << "sect: " << func->GetScriptSectionName() << endl; cout << "line: " << g_pasctx->GetExceptionLineNumber() << endl; cout << "desc: " << g_pasctx->GetExceptionString() << endl; func->Release(); } else { cout << "The script ended for some unforeseen reason (" << iRet << ")." << endl; } } } int ExcuteAngelFunction( char *chFuncID,float &fretscript) { int iRet = OK; int iTypeID = -1; float fRet = -1; int iReturn = -1; iRet = PrepareExcute( chFuncID ); assert( iRet >= 0 ); // We don't want to allow the script to hang the application, e.g. with an // infinite loop, so we'll use the line callback function to set a timeout // that will abort the script after a certain time. Before executing the // script the timeOut variable will be set to the time when the script must // stop executing. DWORD timeOut; iRet = g_pasctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL); if( iRet < 0 ) { cout << "Failed to set the line callback function." << endl; return NG; } // Set the timeout before executing the function. Give the function 1 sec // to return before we'll abort it. timeOut = timeGetTime() + 1000; //angel scriptの実行 iRet = g_pasctx->Execute(); if( iRet == asEXECUTION_FINISHED ) { // Retrieve the return value from the context //script側ではfloat を返す時は末尾にf(10.12f,3.14f)をつける。(double,floatかを区別させるため) //angelscript側ではこの形でintの戻り値をかえせないので、g_ansを使って取得する。 float returnValue = g_pasctx->GetReturnFloat(); fretscript = returnValue; cout << "The script function returned: " << returnValue << endl; cout << "The script function calc: " << g_ans << endl; } else { ShowErrorMsg( iRet ); } return iRet; } //agelscriptの関数の引数のセットテスト用関数 int ExcuteAngelFunction2( char *chFuncID,float &fretscript) { int iRet = OK; int iTypeID = -1; float fRet = -1; int iReturn = -1; iRet = PrepareExcute( chFuncID ); assert( iRet >= 0 ); // We don't want to allow the script to hang the application, e.g. with an // infinite loop, so we'll use the line callback function to set a timeout // that will abort the script after a certain time. Before executing the // script the timeOut variable will be set to the time when the script must // stop executing. DWORD timeOut; iRet = g_pasctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL); if( iRet < 0 ) { cout << "Failed to set the line callback function." << endl; return -1; } // Add the support for co-routines //g_pasctx->RegisterCoRoutineSupport(g_pasengine); //contextMgr.RegisterCoRoutineSupport(engine) //これはできる。 //float f = 1.3f; //iRet = g_pasctx->SetArgFloat( 0,f ); assert( iRet >= 0 ); //asDWORD len = 3; //こちらができない //iRet = g_pasctx->SetArgAddress(0,&artest); assert( iRet >= 0 ); //iRet = g_pasctx->SetArgAddress(1,(void*)len );     assert( iRet >= 0 ); //NG assert occure //iRet = g_pasctx->SetArgAddress(1,(void*)len );     assert( iRet >= 0 ); //NG assert occure //c++ からangelscriptの関数の引数に値を設定する 引数intの場合  ここから compile ok //2,"float TestSetArgAddressInt( int a, int b)" //angel script内で下記のように 定義 floatでキャストしないとエラーが発生する // // float TestSetArgAddressInt( int a, int b) //{ // print("a"); // print("b"); // return float(a + b); //} //int a = 100; //int b = 200; //iRet = g_pasctx->SetArgDWord(0,a); assert( iRet >= 0 ); //iRet = g_pasctx->SetArgDWord(1,b); assert( iRet >= 0 ); //c++ からangelscriptの関数の引数に値を設定する 引数intの場合  ここから compile ok //c++ からangelscriptの関数の引数に値を設定する 引数floatの場合  ここから compile ok //3,"float TestSetArgAddressFloat( float a, float b)" //float a = 10.5f; //float b = 21.5f; //iRet = g_pasctx->SetArgFloat(0,a); assert( iRet >= 0 ); //iRet = g_pasctx->SetArgFloat(1,b); assert( iRet >= 0 ); //c++ からangelscriptの関数の引数に値を設定する 引数floattの場合  ここから compile ok //angelscriptの関数で引数が[in,out]参照のとき引数の戻り値を取得する。 ここから compile ok //{4,"float TestSetArgAddress(float &out outValue)" float fvalue = 0.0f; iRet = g_pasctx->SetArgAddress(0,&fvalue); assert( iRet >= 0 ); // Set the timeout before executing the function. Give the function 1 sec // to return before we'll abort it. timeOut = timeGetTime() + 1000; //angel scriptの実行 iRet = g_pasctx->Execute(); if( iRet == asEXECUTION_FINISHED ) { // Retrieve the return value from the context //script側ではfloat を返す時は末尾にf(10.12f,3.14f)をつける。(double,floatかを区別させるため) //angelscript側ではこの形でintの戻り値をかえせないので、g_ansを使って取得する。 float returnValue = g_pasctx->GetReturnFloat(); fretscript = returnValue; cout << "The script function returned: " << returnValue << endl; cout << "The script function calc: " << g_ans << endl; } else { ShowErrorMsg( iRet ); } return iRet; } //angelscriptの関数の引数に値を設定する場合この関数を使う、指定できる引数の数は1 or 2まで、また戻り値はlongの範囲に収まるようにする int ExcuteAngelFunction( char *chFuncID,long &lret,int arg1,int arg2) { int iRet = OK; int iTypeID = -1; float fRet = -1; int iReturn = -1; iRet = PrepareExcute( chFuncID ); assert( iRet >= 0 ); // We don't want to allow the script to hang the application, e.g. with an // infinite loop, so we'll use the line callback function to set a timeout // that will abort the script after a certain time. Before executing the // script the timeOut variable will be set to the time when the script must // stop executing. DWORD timeOut; iRet = g_pasctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL); if( iRet < 0 ) { cout << "Failed to set the line callback function." << endl; return NG; } //引数が設定されている場合を登録(-1であればなにも設定していない。) if( arg1  != -1 ) { iRet = g_pasctx->SetArgDWord( 0,arg1 ); assert( iRet >= 0 ); } if( arg2 != -1 ) { iRet = g_pasctx->SetArgDWord( 1,arg2 ); assert( iRet >= 0 ); } // Set the timeout before executing the function. Give the function 1 sec // to return before we'll abort it. timeOut = timeGetTime() + 1000; //angel scriptの実行 iRet = g_pasctx->Execute(); if( iRet == asEXECUTION_FINISHED ) { // Retrieve the return value from the context //script側ではfloat を返す時は末尾にf(10.12f,3.14f)をつける。(double,floatかを区別させるため) //angelscript側ではこの形でintの戻り値をかえせないので、g_ansを使って取得する。 //float returnValue = g_pasctx->GetReturnFloat(); lret = g_pasctx->GetReturnDWord(); //fretscript = returnValue; cout << "The script function returned: " << lret << endl; cout << "The script function calc: " << g_ans << endl; } else { ShowErrorMsg( iRet ); } return iRet; } //angelscriptで登録できた関数のみCAngelFuncMapで管理する //0だとすべての定義した関数は登録できた、それ以外は登録に失敗した関数数が返却される int CreateAngelFuncMap( CAngelFuncMap &angelfuncmap) { int ifailregister = 0; for( int i = 0; i < AS_FUNC_NUM;i++) { //int funcId = g_pasmod->GetFunctionIdByDecl(chFuncID); int iFuncID = g_pasmod->GetFunctionIdByDecl( as_FuncList[i].chFuncID ); if( iFuncID < 0 ) { ifailregister++; } angelfuncmap.SetFuncID( as_FuncList[i].chFuncID,iFuncID ); } return ifailregister; } int main( int argc,char *argv[]) { int iRet = NG; float fret = 0.0f; CContextMgr *pcMgr = new CContextMgr(); int iNum = AS_FUNC_NUM; CAngelFuncMap angelmap; g_ans = 0; //printf("c++,angle global property g_ans:%d\n",g_ans ); //printf("as_func_num:%d\n",iNum ); //printf("script num:%d\n",AS_SCRIPT_NUM ); iRet = InitializeAngelEngine(); if( iRet < 0 ) { printf("angel script initialize failed\n" ); return NG; } iRet = RegisterProperty(); if( iRet < 0 ) { printf("angel script register property failed\n" ); return NG; } iRet = RegisterMyClass(); if( iRet < 0) { return iRet; } for( int i = 0; i < AS_SCRIPT_NUM;i++ ) { iRet = LoadScript( AngleScriptNameList[i] ); if( iRet < 0 ) { printf("load failed angel script %s\n",AngleScriptNameList[i] ); } } //読み込んだangelscriptをbuildする iRet = BuildAngelScript(); if( iRet < 0 ) { return NG; } ExcuteAngelFunction( as_FuncList[0].chFuncID,fret ); //ExcuteAngelFunction2( as_FuncList[1].chFuncID,fret );  //ng 配列をangelscript側に渡せない //ExcuteAngelFunction2( as_FuncList[2].chFuncID,fret );  //ok //ExcuteAngelFunction2( as_FuncList[3].chFuncID,fret );  //ok ExcuteAngelFunction2( as_FuncList[4].chFuncID,fret ); //{7,"void SetGlobalArrayLength( int num )"," test file::test1.as"}, //{8,"void SetMusicHandle( int index, int ihandle )"," test file::test1.as"}, //{9,"void ShowGlobalArray()"," test file::test1.as"}, long lret = -1; int itest[5] = {100,101,102,103,104}; ExcuteAngelFunction( as_FuncList[7].chFuncID,lret,5 ); for( int i = 0; i < 5; i++ ) { ExcuteAngelFunction( as_FuncList[8].chFuncID,lret,i,itest[i] ); } ExcuteAngelFunction( as_FuncList[9].chFuncID,lret ); //printf("check property g_ans:%d\n",g_ans ); ////printf("check mystruct.name:%s\n",mystruct.name ); //ExcuteAngelFunction( as_FuncList[1].chFuncID,fret ); ////contestmgr check //int test = CreateAngelFuncMap(angelmap ); //int id1 = angelmap.GetFuncID( as_FuncList[0].chFuncID ); //int id2 = angelmap.GetFuncID( as_FuncList[1].chFuncID ); //int inum = angelmap.GetFuncNum(); //angelmap.DisplayAllFuncMap(); // // //g_contextMgr.AddContext(g_pasengine,angelmap.GetFuncID( as_FuncList[2].chFuncID )); //for(;;) //{ // // Check if any key was pressed // if( kbhit() ) // { // g_contextMgr.AbortAll(); // break; // } // // Allow the contextManager to determine which script to execute next // g_contextMgr.ExecuteScripts(); // // Slow it down a little so that we can see what is happening // Sleep(100); //}     //angle scriptのcontext,engineの解放 //g_pasctx->Release(); //g_pasengine->Release(); CAngelScriptMgr *ptest = new CAngelScriptMgr(); int num = ptest->GetAngelFuncNum(); ptest->Excute( 0, fret ); printf("%f\n", fret ); //delete ptest; CMoveObject *pobj = new CMoveObject(); float ret; //第1引数関数番号(CAngelScriptMgr.ccpのAngelFuncListのインデックス)、第2引数 angelscriptの戻り値 //登録した関数は基本的にすべてコンパイルできるようにするので0~登録した関数数 ptest->Excute( 0, ret ); ptest->Excute( 0, ret ); ptest->Excute( 2, pobj ); ptest->Excute( 2, pobj ); ptest->Excute( 2, pobj ); if( pobj != NULL ) { delete pobj; pobj = NULL; } if( ptest != NULL ) { delete ptest; ptest = NULL; } return 0; } </textarea>

</form>


ダミーハンドルを設定いるのは下記の部分
long lret = -1;
int itest[5] = {100,101,102,103,104};
ExcuteAngelFunction( as_FuncList[7].chFuncID,lret,5 );

for( int i = 0; i < 5; i++ )
{
ExcuteAngelFunction( as_FuncList[8].chFuncID,lret,i,itest[i] );
}

ExcuteAngelFunction( as_FuncList[9].chFuncID,lret );


cppからangelscriptの関数の引数を登録する

2010-02-28 17:08:06 | angelscript

いろいろ試してみたけどcppで定義した配列をそのままangelscriptには登録できないみたいです。
公式サイトのフォーラムにも同様な質問があったのでそのURLを載せておきます。日付は2009年7月
http://www.gamedev.net/community/forums/topic.asp?topic_id=552351
angelscript.hで定義されている以下の型のみcppからanglescriptで定義されている関数の引数として設定できるので SetArgAddressで配列を登録できると思っていましたが、どうやら引数が[in,out](参照 &value)の時の戻り値を受け取るためにあるみたいです。(以下のように使う)


・cppからangelscriptで定義された関数の引数を登録するために使用される関数。argは関数の何番目の引数か指定する。 第1引数の場合argには0を設定する。
int   SetArgByte(asUINT arg, asBYTE value) = 0;
int   SetArgWord(asUINT arg, asWORD value) = 0;
int   SetArgDWord(asUINT arg, asDWORD value) = 0;
int   SetArgQWord(asUINT arg, asQWORD value) = 0;
int   SetArgFloat(asUINT arg, float value) = 0;
int   SetArgDouble(asUINT arg, double value) = 0;
int   SetArgAddress(asUINT arg, void *addr) = 0;
int   SetArgObject(asUINT arg, void *obj) = 0;

・angelscriptから受け取れる戻り値の型

asBYTE  GetReturnByte() = 0;
asWORD  GetReturnWord() = 0;
asDWORD GetReturnDWord() = 0;
asQWORD GetReturnQWord() = 0;
float   GetReturnFloat() = 0;
double  GetReturnDouble() = 0;



<form>

angelscriptの関数

<textarea readonly="readonly" cols="75" rows="8">void TestSetArgAddress(float &out outValue) {   outValue = 3.14f; } </textarea>

c++でangelscriptで定義してある関数に引数を登録する。valueの値にangelscriptで変更された戻り値が,Excute後に設定される。c++のvalueの値がangelscriptで設定した3.14の値になる。

<textarea readonly="readonly" cols="75" rows="8">        int funcId = g_pasmod->GetFunctionIdByDecl(chFuncID); //anglescriptの関数を実行するための準備 iRet = g_pasctx->Prepare(funcId); float fvalue = 0.0f; int iRet = g_pasctx->SetArgAddress(0,&fvalue); assert( iRet >= 0 ); // Set the timeout before executing the function. Give the function 1 sec // to return before we'll abort it. DWORD timeOut = timeGetTime() + 1000; //angel scriptの実行 iRet = g_pasctx->Execute(); </textarea>

</form>