ページ 11

関数のポインタの多数使用

Posted: 2009年9月28日(月) 20:03
by yussanstar
ゲームプログラミングの館の「s1.関数ポインタの基本」に関して、
サンプルプログラムのように、

void (*ShotFunction[/url])( void ) =
{
ShotType2, //この順番で配列に格納される
ShotType1, //[0],[1],[2]の順番で使用すると
ShotType3, //2,1,3の順番で処理される。
} ;

と、関数名をすべて列挙していたのでは、関数の数が何百個と存在するとき(たとえばRPGで、何百個とあるアイテムの効果を関数にする時)にいちいち面倒です。
何かうまい方法はありませんか?

Re:関数のポインタの多数使用

Posted: 2009年9月28日(月) 22:25
by ひよこ
何百個とあるアイテムの効果を関数にする時
>>スイッチ文がシンプルでいいと思います。
こんな感じでいいと思います。
void get_item(int アイテムの種類){//引数のアイテムの効果を使う。
   switch(アイテムの種類){
	   case 回復1:
		   ..........;
			break;	
	   case 回復2:
		   ..........;
			break;
	   case 回復3:
		   ..........;
			break;
   }
}

Re:関数のポインタの多数使用

Posted: 2009年9月28日(月) 22:57
by yussanstar
ひよこさん、すいませんけど、RPGの話はあくまで例であって、自分が本当に知りたいのはアイテムに効果を持たせる方法ではありません。
どうぞ、引き続きよろしくお願いします。

Re:関数のポインタの多数使用

Posted: 2009年9月28日(月) 23:17
by 御津凪
使い方によりますが、たとえば次に移動する関数を指定していくというような設計はどうでしょうか?
#include <stdio.h>

// 関数型定義
typedef void* (*TASKFUNC)( void );

// 終了を示す値
#define TERMFUNC ((void*)0xffffffff)

// 関数宣言
void* step1( void );
void* step2( void );
void* step3( void );

// グローバル変数
int gData = 0;

// 関数定義
void* step1( void ){
	++gData;
	printf("step1:%d\n", gData);
	if(gData >= 3) return step2;
	return NULL;
}
void* step2( void ){
	++gData;
	printf("step2:%d\n", gData);
	if(gData >= 6) return step3;
	return NULL;
}
void* step3( void ){
	++gData;
	printf("step3:%d\n", gData);
	if(gData >= 9) return TERMFUNC;
	return NULL;
}

// メイン関数
int main( void ){
	TASKFUNC func = step1; // 開始関数の指定

	while(func != TERMFUNC){ // func が TERMFUNC になるまで
		TASKFUNC f = (TASKFUNC)func();
		if(f != NULL) func = f;
		// ここに更新処理とか入れる
	}
	printf("end:%d\n", gData);
	getchar(); // 表示の確認用
	return 0;
}
関数名の列挙の方法(yussanstar さんの提示している方法)も一般的にも使用される方法なので、状況に応じて使い分けるのがいいでしょうね。

Re:関数のポインタの多数使用

Posted: 2009年9月29日(火) 08:06
by zwi
>関数名をすべて列挙していたのでは、関数の数が何百個と存在するとき(たとえばRPGで、何百個とあるアイテムの効果を関数にする時)にいちいち面倒です。

基本的にRPGのアイテムでもシューティングの弾幕でも関数が何百個になることは無いわけですが(あるとしたら設計がまずいです)。理由はメンテナンス性が悪くなるからです。
どんなプログラムでもですが、少し動作内容が違うだけ関数を幾つも作るのは間違っています。
私なら使う関数の種類と与えるパラメータをセットにしてテーブル化しますが、それではダメなのでしょうか?

Re:関数のポインタの多数使用

Posted: 2009年9月29日(火) 10:20
by conio
まず、関数が何百、何千とあるような状況を
改善できないかを考えた方が良いと思います。

例えば、
--------------------------------------------------
【1】敵と、主人公との当たり判定をする関数
【2】敵の弾と、主人公との当たり判定をする関数
【3】敵と、主人公の弾との当たり判定をする関数
【4】敵の弾と、主人公の弾との当たり判定をする関数
【5】敵と、敵との当たり判定をする関数
--------------------------------------------------
これらの関数があった場合、無駄が多いと分かると思います。

しかし、
「オブジェクトAとオブジェクトBの当たり判定をする関数」というものを作れば、上記の全てに対応できます。
関数がひとつになる訳です。

あとアイテムの例ですが、関数を何個も作るのではなく、「アイテム関連の処理をする関数」を作っておいて、
その中で内容に応じて処理を分岐させたりすれば良いと思います。

他にも 敵Aを作る関数、敵Bを作る関数、敵Cを作る関数・・・という構造があった場合、
敵のデータは全部 テキストファイルやcsvファイルなんかに書いてしまっておいて、
「パラメータを読み込みセットする」という関数を一つだけ作っておけばOK、とか。

Re:関数のポインタの多数使用

Posted: 2009年9月29日(火) 11:41
by toyo
必要があれば面倒でも列挙しますね
添付のはCPUのエミュレータの一部ですがオペコード=>関数を256個の関数ポインタの配列にしています
これをこれ以上うまく処理する方法は思いつきません(if や switch に比べるとかなりうまい処理ではあると思います)

Re:関数のポインタの多数使用

Posted: 2009年10月02日(金) 00:17
by yussanstar
色々とありがとうございました。
いわゆる「ベストアンサー」は、ひよこさんにしたいと思います。