graph_bullet

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ft

graph_bullet

#1

投稿記事 by ft » 15年前

DXライブラリPを使ってPSPにて龍神録を再現しようしております。
大量の弾の描画を速くしたいのですが、graph_bulletにて気になる箇所がありましたので質問させていただきます。
色々とコメントアウトしちゃってますが、以下のgraph_bullet中の2つのfor文がどうもネックになっているように思いました。それぞれSHOT_MAX=30とSHOT_BULLET_MAX=1000とサンプルのままですが、実際に合計1000個発射しない弾幕でも1000個分の処理をしているので、どうもここの箇所が重くする原因の一つになっているような気がします(解釈を間違っていたらすみません;)。実際にSHOT_BULLET_MAX=300としたらある程度軽くなるのですが、これは根本的な解決ではないですよね。。。
//弾丸の描画
void graph_bullet(){
        int i,j;
//SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//線形補完描画
for(i=0;i<SHOT_MAX;i++){//敵の弾幕数分ループ
    if(shot.flag>0){//弾幕データがオンなら
           for(j=0;j<SHOT_BULLET_MAX;j++){//その弾幕が持つ弾の最大数分ループ
                 if(shot.bullet[j].flag!=0){//弾データがオンなら
                 //if(shot.bullet[j].eff==1)
				 //SetDrawBlendMode( DX_BLENDMODE_ADD, 255) ;
                 DrawRotaGraphF(
                               shot.bullet[j].x, shot.bullet[j].y+FIELD_Y,
                               0.567, 0,
                               img_bullet[shot.bullet[j].knd][shot.bullet[j].co[/url],TRUE,0);
				//if(shot.bullet[j].eff==1)
				//SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0) ;
                                }
                        }
                }
        }
       //	SetDrawMode(DX_DRAWMODE_NEAREST);//描画形式を戻す 
}

そこで、この管理方法ではなく、他に効率の良い処理をする方法はあるのでしょうか?

Justy

Re:graph_bullet

#2

投稿記事 by Justy » 15年前


> 他に効率の良い処理をする方法はあるのでしょうか

・ SHOT_BULLET_MAXや SHOT_MAXといった最大値まで .flagを調べないで、
事前にその時点で使用している最大のインデックス番号を覚えておいて、
そのインデックスまでを調べるようにします。

 余裕があれば、何かのタイミングで使用してるところの情報を
先頭の方に集めなおせば、無駄はさらに無くなります。


・ 配列をやめて、リンクリストにする
 存在している情報しか見ないので、SHOT_BULLET_MAXや SHOT_MAXが
大きければ大きいほど有効です。

 要素を追加するときに毎回アロケートするのはどうか、というのであれば
 
連結リスト - Wikipedia (ノードの配列を使った連結リスト)
http://ja.wikipedia.org/wiki/%E9%80%A3% ... 9.E3.83.88

のような手法を使えばそれなりに高速かな、と。

ft

Re:graph_bullet

#3

投稿記事 by ft » 15年前

返信遅れてすみません。
ご回答ありがとうございます。
>事前にその時点で使用している最大のインデックス番号を覚えておいて
これは弾幕毎のデータ内にSHOT_BULLET_MAXやSHOT_MAXの数値をあらかじめ作っておいて、
弾幕を読み込むごとにSHOT_BULLET_MAXとSHOT_MAXを読み込ませていくということでしょうか?

Justy

Re:graph_bullet

#4

投稿記事 by Justy » 15年前


>>事前にその時点で使用している最大のインデックス番号を覚えておいて
>これは弾幕毎のデータ内にSHOT_BULLET_MAXやSHOT_MAXの数値をあらかじめ作っておいて、
>弾幕を読み込むごとにSHOT_BULLET_MAXとSHOT_MAXを読み込ませていくということでしょうか

 じゃなくてですね、配列内の flagが 1になっている最大のインデックス番号を
常に更新し覚えておく、ということです。
 
 例えば maxUsedShotBulletという変数を作ります。
 まだ弾が1つもない状態のときは -1を入れておきます。

 弾が1つ登録されるとき、flagメンバを 1にすると思いますが、その配列のインデックス番号と
maxUsedShotBulletを比較して maxUsedShotBulletの方が小さければ maxUsedShotBulletに
そのインデックス番号を代入します。

 反対に弾が削除され flagメンバを 0にするとき、その削除される配列のインデックス番号と
maxUsedShotBulletが等しければ、そのインデックス番号から遡って1つ前に使われている
ところを見つけ出し、そのインデックス番号を maxUsedShotBulletを更新します。
(見つからなければ -1を入れます)


 こうして、弾の探索を行うときは
[color=#d0d0ff" face="monospace]
for(j=0;j<=maxUsedShotBullet;j++)
[/color]

のように maxUsedShotBulletの値を使えば、SHOT_BULLET_MAXなどが大きな値
だっだとしても配列の全探索することはなくなりますので、それなりに速くなるはずです。

ft

Re:graph_bullet

#5

投稿記事 by ft » 15年前

>弾が1つ登録されるとき、flagメンバを 1にすると思いますが、その配列のインデックス番号と
maxUsedShotBulletを比較して maxUsedShotBulletの方が小さければ maxUsedShotBulletに
そのインデックス番号を代入します。

例えば常に自機狙い弾ですと以下のようになっているんですが、この場合maxUsedShotBulletとshot[n].bullet[k].flag =1;のkを比較すれば良いよいうことでしょうか?
//100カウント中に10発、自機に向かって直線発射(常に自機狙い)
void shot_bullet_H001(int n){
	int t=shot[n].cnt;
	int k;
	if(t>=0 && t<100 && t%10==0){
		if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
			shot[n].bullet[k].knd	=enemy[shot[n].num].blknd2;
			shot[n].bullet[k].angle	=shotatan2(n);
			shot[n].bullet[k].flag	=1;
			shot[n].bullet[k].x		=enemy[shot[n].num].x;
			shot[n].bullet[k].y		=enemy[shot[n].num].y;
			shot[n].bullet[k].col	=enemy[shot[n].num].col;
			shot[n].bullet[k].cnt	=0;
			shot[n].bullet[k].spd	=3;
			se_flag[0]=1;
		}
	}
}

Justy

Re:graph_bullet

#6

投稿記事 by Justy » 15年前


> この場合maxUsedShotBulletとshot[n].bullet[k].flag =1;のkを
> 比較すれば良いよいうことでしょうか?

 そうです。

ねこ

Re:graph_bullet

#7

投稿記事 by ねこ » 15年前

Justyさんの意見に加えてフレーム単位でのインデックス保持方式というのはどうでしょうか?
shotとかbulletの構造体定義が分からないので「shot配列」は弾構造体の意味で読んでください。
int ArrShotIdx[ SHOT_MAX ];	// 配列中のインデックスを覚える配列
int iShotIdxCnt = 0;		// インデックス配列の要素数

// 処理の最初の方に実行する
iShotIdxCnt = 0;
for( int ii = 0; ii < maxUsedShotBullet; ii++ )
{
	// ショットの存在フラグを調べ、存在したらその配列添え字を保持
	if( shot[ ii ].flag )
		ArrShotIdx[ iShotIdxCnt++ ] = ii;
}

// ショットのループ
for( ii = 0; ii <= iShotIdxCnt ; ii++ ) 
{
	int idx = ArrShotIdx[ ii ];
	if( shot[ idx ].flag )
	{
		// 弾処理
	}
}
メリットは存在しない弾にはほぼアクセスしないで良い点。
デメリットとしてそのフレームで発生した弾はそのフレームでは処理されない点。

あと気になったのはループを1000⇒300にしただけで実行速度に影響が出るって事は
使ってない玉の構造体を探す処理もそれなりにコストになるんじゃないでしょうか。
0~200全部埋めた状態で24wayショットを打つとそれだけで4800ループとかになりますから。

ft

Re:graph_bullet

#8

投稿記事 by ft » 15年前

まず順番に解決していこうかと思うのですが、
私自身が言った
> この場合maxUsedShotBulletとshot[n].bullet[k].flag =1;のkを
> 比較すれば良いよいうことでしょうか?
なのですが、どのようにすればよいのでしょうか?
void shot_bullet_H001(int n){
	int t=shot[n].cnt;
	int k,maxUsedShotBullet;
	if(t>=0 && t<100 && t%5==0){
		if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
			shot[n].bullet[k].flag	=1;
                        maxUsedShotBullet=k;
		}
	}
}
のようにして、
for(j=0;j<=maxUsedShotBullet;j++)
と書き変えたらmaxUsedShotBulletは宣言していないということでエラーしてしまいました。
ほんと初心者な質問ですみません;

Justy

Re:graph_bullet

#9

投稿記事 by Justy » 15年前


>なのですが、どのようにすればよいのでしょうか?

 どうすればいいのか、については No:40905でそれなりに細かく説明している通りなのですが、
そのコードでは比較することなくmaxUsedShotBulletに配列のインデックス番号である
kを代入していますので、まず比較を行って条件を満たしているかどうかを調べてください。

 kと maxUsedShotBulletの比較は

比較のための演算子
ttp://homepage3.nifty.com/mmgames/c_guide/07-02.html#S2

の大小比較の演算子を使います。



>と書き変えたらmaxUsedShotBulletは宣言していないということでエラーしてしまいました

 そりゃまぁそうでしょうね。まだ存在しない架空の変数ですから。

「例えば maxUsedShotBulletという変数を作ります」と書いたとおり、
適当なところに変数を作ってください。

ft

Re:graph_bullet

#10

投稿記事 by ft » 15年前

なんとか実現できました。
長らく付き合っていただき、どうもありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る