.五月雨.のブログ -3ページ目

.五月雨.のブログ

ゲームプログラムとか音楽とか

今回は実行中のスクリプトの更新への対応の実験をしてみました。

以下のプログラムを実行して
'v'を押すと「14」と表示されます。
そのまま実行しながら、myclass.nutの
inst.bar の値を3に変更して保存
'c'キーを押してコンパイルし直します。
そして、vキーを押すと「21」と表示されます。
こんな感じでビルドを挟まずにリアルタイムで反映していけると便利かな?


myclass.nut
local inst = MyClass();
inst._bar = 2;
printNum(inst.mul(inst._bar, 7)); // "num = 14\n"
C++
#include "stdafx.h"
#include <sqrat.h> // squirrel.h もインクルードされる
#include <sqstdaux.h> // sqstd_seterrorhandlers

#include <stdio.h>
#include <stdarg.h>
#include <Windows.h>

// 文字列出力
static void printfunc(HSQUIRRELVM vm, const SQChar* format, ...)
{
va_list args;
va_start(args, format);
#ifdef SQUNICODE
vwprintf(format, args);
#else
vprintf(format, args);
#endif
va_end(args);
}


// クラス
class MyClass
{
public:
int mul(int x, int y) { return (x * y); }
int _bar;
};

// 関数
void printNum(int n)
{
printf("num = %d\n", n);
}


void bindMyTable(HSQUIRRELVM vm)
{
using namespace Sqrat;

// テーブルを作成
Table myTable(vm);

// MyClass オブジェクトを作成
Class<MyClass> myClass(vm);

// MyClass オブジェクトにメンバをバインド
myClass.Func(_SC("mul"), &MyClass::mul); // メンバ関数
myClass.Var(_SC("_bar"), &MyClass::_bar); // メンバ変数

// ルートテーブルに myTable を "MyTable" としてバインド
RootTable(vm).Bind(_SC("MyClass"), myClass);
RootTable(vm).Func(_SC("printNum"), &printNum);
}


// メイン
int main(int argc, char** argv)
{
// Sqratの名前空間
using namespace Sqrat;

// VMの作成
HSQUIRRELVM vm = sq_open(1024);

// エラーハンドラを設定
sqstd_seterrorhandlers(vm);

// 文字列出力関数を設定
sq_setprintfunc(vm, printfunc);


// 標準で使うVMの設定
DefaultVM::Set(vm);

bindMyTable(vm);

{
Script scriptA;
scriptA.CompileFile("myclass.nut");

while( !::GetAsyncKeyState( 'Q' ) )
{
// コンパイル
if( ::GetAsyncKeyState( 'C' ) ) scriptA.CompileFile("myclass.nut");

// 実行
// if( ::GetAsyncKeyState( 'V' ) )
scriptA.Run();
}
}


// VMを解放
sq_close(vm);

return 0;
}

今回は、Squirrel側のインスタンや関数にC/C++からアクセスすることに挑戦。

まずは、インスタンスの生成、クラスや関数の宣言したSquirrelを実行。
ルートテーブル経由で取得、実行していきます。



ルーチェ's Homepage
さんのソースを元に
テスト用に変更しました。

test_class.nut
valInt <- 100;
valInt <- 100;
valFloat <- 2.5;
valStr <- "Hello, Sqrat World !!";
valTable <- { valT = 50 }

class FooClass
{
constructor(v)
{
valC = v;
}
valC = null;
}
valClass <- FooClass("test class");

test_function.nut
// 受け取った文字列を改行付きで出力する関数
function printLine(str)
{
print(str + "\n");
}

// 受け取った引数の合計値を返す関数
function calcTotal(...)
{
local ret = 0;

for (local i = 0; i < vargv.len(); ++i)
{
ret += vargv[i];
}
return ret;
}

c++
#include "stdafx.h"
#include // squirrel.h もインクルードされる
#include // sqstd_seterrorhandlers

#include
#include

// 文字列出力
static void printfunc(HSQUIRRELVM vm, const SQChar* format, ...)
{
va_list args;
va_start(args, format);
#ifdef SQUNICODE
vwprintf(format, args);
#else
vprintf(format, args);
#endif
va_end(args);
}


// メイン
int main(int argc, char** argv)
{
// Sqratの名前空間
using namespace Sqrat;

// VMの作成
HSQUIRRELVM vm = sq_open(1024);
// エラーハンドラを設定
sqstd_seterrorhandlers(vm);
// 文字列出力関数を設定
sq_setprintfunc(vm, printfunc);


// 標準で使うVMの設定
DefaultVM::Set(vm);

{
Script scriptA;
scriptA.CompileFile("test_class.nut");
scriptA.Run();

scriptA.CompileFile("test_function.nut");
scriptA.Run();

// vmから値の取得
// IsNullで値が存在するかチェック

// valInt <- 100;
Object objValInt = RootTable(vm).GetSlot(_SC("valInt"));
if( !objValInt.IsNull() )
{
int valInt = objValInt.Cast();
printf("valInt = %d\n",valInt);
}

// valFloat <- 2.5;
Object objValFloat = RootTable(vm).GetSlot(_SC("valFloat"));
if( !objValFloat.IsNull() )
{
float valFloat = objValFloat.Cast();
printf("valFloat = %.2f\n",valFloat);
}

// valStr <- "Hello, Sqrat World !!";
Object objValStr = RootTable(vm).GetSlot(_SC("valStr"));
if( !objValStr.IsNull() )
{
// 文字型にキャスト
Sqrat::string valStr = objValStr.Cast();
printf("valStr = %s\n",valStr.c_str());
}

// valTable <- { valT = 50 }
Object objValTable = RootTable(vm).GetSlot(_SC("valTable"));
if( !objValTable.IsNull() )
{
Object objValT = objValTable.GetSlot(_SC("valT"));
if( !objValT.IsNull() )
{
int valT = objValT.Cast();
printf("valT = %d\n",valT);
}
}
// valClass <- FooClass("test class");
Object objValClass = RootTable(vm).GetSlot(_SC("valClass"));
if( !objValClass.IsNull() )
{
/// メンバ変数へのアクセス
Object objValC = objValClass.GetSlot(_SC("valC"));
if( !objValC.IsNull() )
{
// 文字型にキャスト
Sqrat::string valC = objValC.Cast();
printf("valC = %s\n",valC.c_str());
}
}

// 関数を取得
Function funcPrintLine = RootTable(vm).GetFunction(_SC("printLine"));
Function funcCalcTotal(RootTable(vm), _SC("calcTotal"));

// 関数を実行する(結果不要な場合)
if( !funcPrintLine.IsNull() )
{
funcPrintLine.Execute(_SC("てすと1"));
funcPrintLine(_SC("てすと2"));
}

// 関数を実行して結果を得る
if( !funcCalcTotal.IsNull() )
{
int resI = funcCalcTotal.Evaluate(1, 2, 3, 4); // 10
float resF = funcCalcTotal.Evaluate(1.1F, 2.2F, 3.3F); // 6.6F

printf("%d\n", resI);
printf("%.2f\n", resF);
}
}
// VMを解放
sq_close(vm);

return 0;
}


また連絡がありました。
さすがにすぐに長期出張という話はなくなりましたが、
数日働いて、短期で出張がそうです(;・∀・)

うーむ、昨日の時点でいろいろ断っちゃったんだけどな・・・(;´Д`)
いつから出張なのかもわかんないし、予定立てにくいな・・・。