System4.0 の関数型
ゲーム性のあるゲームを作成しようとしたときの味方、関数型について説明したいと思います。
関数型とは、C言語で言う関数ポインタの事です。変数と同じように、関数を格納することで、後から好きな関数を呼び出せるという寸法です。
関数型のサンプルを拡張して書いてみました。
// 関数型定義 functype void ftFunc(int); // 関数型オブジェクト宣言 ftFunc g_Func; void game_main(void){ g_Func=&TestA; g_Func(0); g_Func=&TestB; g_Func(1); } void TestA(int nA) { //TestAの処理 } void TestB(int nA) { //TestBの処理 } |
TestAとTestBが動作することが分かると思います。これくらいなら普通に関数を呼び出した方が早いじゃないか、という指摘はもっともです。しかし、この関数型が強力なところは、次のような場合です。
//文字列型配列 array@string aStr; // 関数型定義 functype int ftFunc(void); void game_main(void){ //あらかじめデータが入っているものとする。 aStr.PushBack("佐藤"); aStr.PushBack("鈴木"); aStr.PushBack("山田"); //選択 int i,sel,res; for(i=0;i<aStr.Numof();i++) MENU_ADD(i,aStr[i]); sel=MENU_SELECT(); //選択された人によって違う処理をしたい ftFunc func; func="Event_" + aStr[sel]; if(func!=NULL){ res=func(); }else{ res=Event_誰でもない(); } system.Output("戻り値=%d\n" % res); } int Event_誰でもない(void){ //定義されていない return -1; } int Event_佐藤(void){ //佐藤のイベント return 100; } int Event_鈴木(void){ //鈴木のイベント return 200; } |
分かるでしょうか?
aStrに対して、名前を登録しておきます。この名前の登録は、本当なら別の関数で初期化時に行うなどします。下の方のEvent_~~という関数は、それぞれの人ごとに実行される別の関数で、この部分でそれぞれの人によって異なる処理をさせます。
もしも、新しくキャラクターを追加し、イベントも追加したい場合は、aStrに対して別の名前をPushBackで登録し、Event_~~で~~の部分をaStrに登録した名前として関数を作成するだけで、他の部分の変更は必要ないということです。
内部の処理を説明しますと、
int i,sel,res;
for(i=0;i<aStr.Numof();i++)
MENU_ADD(i,aStr[i]);
sel=MENU_SELECT();
の部分で、選択肢を表示。これにより、複数のキャラから選択していますが、実際はもっと別の方法によってイベントが起こるものを選択すると思います。
ftFunc func;
func="Event_" + aStr[sel];
により、関数ポインタに、選択されたキャラを設定しています。文字列の合成で、呼び出される関数を作成し、それを関数ポインタに入れます。文字列を関数ポインタに代入することによって、その関数名になっている関数を関数ポインタに登録します。
if(func!=NULL){
res=func();
}else{
res=Event_誰でもない();
}
の部分は、関数ポインタがNULLで無ければ、関数ポインタに格納された関数を実行しています。ここで重要な事は、もしも上の関数ポインタへの代入で、存在しない関数を指定していた場合は、関数ポインタにはNULLが代入されているということです。そのため、関数ポインタがNULLの場合のみ、別の処理を行ってあげれば、いかなる場合も実行されるという事になります。
さて、注意事項ですが、現在のSystem4.0では、関数ポインタを戻り値や引数で戻すことを禁止しています。そのため、そのような用途では、文字列を渡し、呼び出す側で文字列から関数ポインタに変換します。
また、クラス内のメンバ関数などは、呼び出しできません。