弾幕の作成について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
クラバック
記事: 26
登録日時: 12年前
住所: 関東

弾幕の作成について

#1

投稿記事 by クラバック » 12年前

いつもお世話になっております。弾幕を作っていたのですが、行き詰ってしまったので、質問させて頂きます。
大弾を一つ自機の方に打ち、ゆっくりと減速し、自機のすぐ近くで小弾が広範囲で表示され始めると同時に大玉が消え、10フレーム後に小弾が消えるような弾幕を作成しています。
ですが、弾のフラグを0にする(弾を消す)コードがうまく描き表せません。また、自身で組んだプログラムですが、どうもスッキリしない書き方、という感じがします。大弾のカウント数でif文分岐してますが、理解しにくいような印象を受けます。もっとスマートな書き方はないでしょうか。
getBulletCircle()は中心座標、半径を渡すと円内の座標をランダムで返す関数です。
getDistance()は点と点の距離を返す関数です。
getRand_2()は渡されたc1~c2までのランダムな数を返す関数です。
35行目のエフェクト.eff=2の指定はgraph.cppの通りです。

宜しくお願い致します。

boss_shotH.cpp

コード:

void boss_shot_bulletH010(){
#define H010 360
	int i,k,l,t=boss_shot.cnt%H010;//t=0~359
	int t2=boss_shot.cnt;
	double d;
	double spd;
	double GetX;
	double GetY;
	static	double BulletX;
	static  double BulletY;
	void getBulletCircle(double x0, double y0, double r, double *xx, double *yy);
if(t2==20){
			d = getDistance_boss_ch();
			spd = d/110;
			if((k=search_boss_shot())!=-1){
				boss_shot.bullet[k].x = boss.x;
				boss_shot.bullet[k].y = boss.y;
				boss_shot.bullet[k].angle = bossatan2();
				boss_shot.bullet[k].cnt = -20;
				boss_shot.bullet[k].col = 0;
				boss_shot.bullet[k].knd = 0;
				boss_shot.bullet[k].flag = 1;
				boss_shot.bullet[k].state = 10;
				boss_shot.bullet[k].till = 0;
				boss_shot.bullet[k].spd = spd;
			}
	}
	for(i=0;i<BOSS_BULLET_MAX;i++){
		if(boss_shot.bullet[i].flag==1){
			if(boss_shot.bullet[i].state == 10){
				if(boss_shot.bullet[i].cnt<220){
					boss_shot.bullet[i].spd -= boss_shot.bullet[i].spd/(220-boss_shot.bullet[i].cnt);
				}
				if(boss_shot.bullet[i].cnt>=80 && boss_shot.bullet[i].cnt < 140){
					boss_shot.bullet[i].eff = 2;
				}
				if(boss_shot.bullet[i].cnt>=140 && boss_shot.bullet[i].cnt < 220){
					boss_shot.bullet[i].eff_detail = 1;
				}
				if(boss_shot.bullet[i].cnt == 220){
					BulletX = boss_shot.bullet[i].x;
					BulletY = boss_shot.bullet[i].y;
				}
				if(boss_shot.bullet[i].cnt>220 && boss_shot.bullet[i].cnt<230){
					for(l=0;l<150;l++){
					getBulletCircle(BulletX, BulletY, 120, &GetX, &GetY);
						if((k=search_boss_shot())!=-1){
							boss_shot.bullet[k].x = GetX;
							boss_shot.bullet[k].y = GetY;
							boss_shot.bullet[k].angle = 0;
							boss_shot.bullet[k].cnt = 0;
							boss_shot.bullet[k].knd = 7;
							boss_shot.bullet[k].col = 9;							
							boss_shot.bullet[k].flag = 1;
							boss_shot.bullet[k].spd = 0;
							boss_shot.bullet[k].state = 100;
						}
					}
				}
				if(boss_shot.bullet[i].cnt>230){
					if(boss_shot.bullet[k].state==100 || boss_shot.bullet[i].state==10){
						boss_shot.bullet[k].flag=0;
						boss_shot.bullet[i].flag=0;
					}
				}
			}
		}
	}
}
void getBulletCircle(double x0, double y0, double r, double *xx, double *yy){
	int judge = 1;
	while(judge){
	double x = getRand_2(x0-r, x0+r);
		double y = getRand_2(y0-r, y0+r);
		if(getDistance(x, y, x0, y0)<=r){
			*xx = x;
			*yy = y;
			judge =!judge;
		}
	}
}

コード:

//点と点の距離を返す
double getDistance(double x1, double y1, double x2, double y2){
	return sqrt((y2-y1)*(y2-y1) + (x2-x1)*(x2-x1));
}

コード:

//渡されたc1~c2までのランダムな数を返す(c1<c2)
int getRand_2(int c1, int c2){
	return (c1+GetRand(c2-c1));
}
graph.cpp

コード:

#include "../include/GV.h"

extern void graph_back_main();

void graph_effect(int knd){
	for(int i=0;i<EFFECT_MAX;i++){
		if(effect[i].flag>0 && effect[i].knd==knd){
			if(effect[i].eff==1)//エフェクトが光エフェクトなら
				SetDrawBlendMode( DX_BLENDMODE_ADD, effect[i].brt) ;
			if(effect[i].eff==2)//エフェクトがαエフェクトなら
				SetDrawBlendMode( DX_BLENDMODE_ALPHA, effect[i].brt) ;
			DrawRotaGraphF(effect[i].x+FX+dn.x,effect[i].y+FY+dn.y,effect[i].r,effect[i].ang,effect[i].img,TRUE);
			if(effect[i].eff==1 || effect[i].eff==2)
				SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0) ;
		}
	}
}

//敵描画
void graph_enemy(){
	int i;
	for(i=0;i<ENEMY_MAX;i++){
		if(enemy[i].flag==1){
			DrawRotaGraphF(enemy[i].x+FX+dn.x,enemy[i].y+FY+dn.y,1.0f,0.0f,img_enemy[0][enemy[i].img],TRUE);
		}
	}
}

void graph_boss_effect(){
	SetDrawBlendMode( DX_BLENDMODE_ALPHA, 150) ;
	DrawRotaGraphF(boss.dx+FX,   boss.dy+FY,
				   (0.4+0.05*sin(PI2/360*(count%360)))*3,
				   2*PI*(count%580)/580,
				   img_etc[5], TRUE);
	DrawRotaGraphF(boss.dx+FX,   boss.dy+FY,
				   (0.5+0.1*sin(PI2/360*(count%360)))*2,
				   2*PI*(count%340)/340,img_etc[2],	TRUE);
	DrawRotaGraphF(boss.dx+60*sin(PI2/153*(count%153))+FX,
				   boss.dy+80*sin(PI2/120*(count%120))+FY,
				   0.4+0.05*sin(PI2/120*(count%120)),
				   2*PI*(count%30)/30,img_etc[6],	TRUE);
	DrawRotaGraphF(boss.dx+60*sin(PI2/200*((count+20)%200))+FX,
				   boss.dy+80*sin(PI2/177*((count+20)%177))+FY,
				   0.3+0.05*sin(PI2/120*(count%120)), 
				   2*PI*(count%35)/35,img_etc[6],	TRUE);
	SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0) ;
	DrawRotaGraphF(boss.dx+60*sin(PI2/230*((count+40)%230))+FX,
				   boss.dy+80*sin(PI2/189*((count+40)%189))+FY,
				   0.6+0.05*sin(PI2/120*(count%120)),
				   2*PI*(count%40)/40,img_etc[6],	TRUE);
}

void graph_boss(){
	int i;
	if(boss.flag==0)return;
	graph_boss_effect();
	/*DrawRotaGraphF(boss.dx+FX+dn.x,boss.dy+FY+dn.y,
		1.0f,0.0f,img_dot_riria[0],TRUE);*/
	DrawRotaGraphF(boss.dx+FX+dn.x,boss.dy+FY+dn.y,
		0.35f,0.0f,img_dot_murakami,TRUE);
	if(boss.hp_max==0){printfDx("graph_boss内0割り\n");return;}
	for(i=0;i<FMX*0.98*boss.hp/boss.hp_max;i++){
		if(boss.back_knd[boss.knd]==1)
			DrawGraph(3+FX+i+dn.x,2+FY+dn.y,img_etc[7],FALSE);
		else
			DrawGraph(3+FX+i+dn.x,2+FY+dn.y,img_etc[1],FALSE);
	}
}

//自機描画
void graph_ch(){
	double sx,sy,ny=(sin(2.0*PI*(count%50)/50)*3),ang=2.0*PI*(count%120)/120;

	if(CheckStatePad(configpad.slow)>0)//低速移動中なら
		sx=15,sy=15+ny;//引き寄せる
	else
		sx=30,sy=30+ny;//普通の位置に

	DrawRotaGraphF( ch.x-sx+FX, ch.y+sy+FY, 1.0f,  ang, img_chetc[2], TRUE );
	DrawRotaGraphF( ch.x+sx+FX, ch.y+sy+FY, 1.0f, -ang, img_chetc[2], TRUE );

	if(ch.mutekicnt%2==0){//無敵中なら点滅
		//自機表示
		DrawRotaGraphF(ch.x+FX+dn.x,ch.y+FY+dn.y,1.0f,0.0f,img_ch[0][ch.img],TRUE);
		if(CheckStatePad(configpad.slow)>0)//低速移動中なら当たり判定表示
			DrawRotaGraphF( ch.x+FX, ch.y+FY, 1.0f, 2.0*PI*(count%120)/120, img_chetc[0], TRUE );
	}
}

//自機ショット描画
void graph_cshot(){
	for(int i=0;i<CSHOT_MAX;i++){
		if(cshot[i].flag>0){
			DrawRotaGraphF(cshot[i].x+FX+dn.x,cshot[i].y+FY+dn.y,1,0,img_cshot[cshot[i].knd],TRUE);
		}
	}
}

//弾丸の描画
void graph_bullet(){
	int i,j,k,eff;
	double disp_angle;
	SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//線形補完描画
	for(i=0;i<SHOT_MAX;i++){//敵の弾幕数分ループ
		if(shot[i].flag>0){//弾幕データがオンなら
			for(j=0;j<SHOT_BULLET_MAX;j++){//その弾幕が持つ弾の最大数分ループ
				if(shot[i].bullet[j].flag!=0){//弾データがオンなら
					if(shot[i].bullet[j].eff==1)
						SetDrawBlendMode( DX_BLENDMODE_ADD, 255) ;
					if(bullet_info[shot[i].bullet[j].knd].kaiten==1)
						disp_angle=PI2*(shot[i].bullet[j].cnt%120)/120;
					else
						disp_angle=shot[i].bullet[j].angle+PI/2;
					DrawRotaGraphF(
						shot[i].bullet[j].x+FX+dn.x, shot[i].bullet[j].y+FY+dn.y,
						1.0, disp_angle,
						img_bullet[shot[i].bullet[j].knd][shot[i].bullet[j].col],TRUE);

					if(shot[i].bullet[j].eff==1)
						SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0) ;
				}
			}
		}
	}
	//ボス
	if(boss_shot.flag>0){//弾幕データがオンなら
		for(j=0;j<BOSS_BULLET_MAX;j++){//その弾幕が持つ弾の最大数分ループ
			if(boss_shot.bullet[j].flag!=0){//弾データがオンなら
				if(boss_shot.bullet[j].cnt<0 && boss_shot.bullet[j].cnt >= -20){
					SetDrawBlendMode(DX_BLENDMODE_ALPHA, 255+255*boss_shot.bullet[j].cnt/20);
					DrawRotaGraph(boss_shot.bullet[j].x+FX+dn.x, boss_shot.bullet[j].y+FY+dn.y,
						(1.0-boss_shot.bullet[j].cnt/20.0),
						boss_shot.bullet[j].angle+PI/2,
						img_bullet[boss_shot.bullet[j].knd][boss_shot.bullet[j].col],
						TRUE, 0);
					SetDrawBlendMode(DX_BLENDMODE_ALPHA,255);
				}
				else if(boss_shot.bullet[j].cnt>=0){
					eff=0;
					if(boss_shot.bullet[j].kaiten==1){
						disp_angle=PI2*(boss_shot.bullet[j].cnt%120)/120;
					}else{
						disp_angle=boss_shot.bullet[j].angle+PI/2;
					}
					if(boss_shot.bullet[j].eff_detail==1){//雨にもまけず用エフェクト
						SetDrawBlendMode(DX_BLENDMODE_ADD, 100+GetRand(155));
						eff=1;
						DrawRotaGraphF(boss_shot.bullet[j].x+FX+dn.x, boss_shot.bullet[j].y+FY+dn.y, 1.3, disp_angle, img_bullet[boss_shot.bullet[j].knd][boss_shot.bullet[j].col],TRUE,0);
					}
					if(boss_shot.bullet[j].eff_detail==2){
						SetDrawBlendMode( DX_BLENDMODE_ADD, 255);
						eff=1;
						DrawRotaGraphF(boss_shot.bullet[j].x+FX+dn.x, boss_shot.bullet[j].y+FY+dn.y, 5.0, disp_angle, img_bullet[boss_shot.bullet[j].knd][boss_shot.bullet[j].col],TRUE,0);
					}
					if(boss_shot.bullet[j].eff_detail==3){
						SetDrawBlendMode( DX_BLENDMODE_NOBLEND,250);
						eff=1;
						DrawRotaGraphF(boss_shot.bullet[j].x+FX+dn.x, boss_shot.bullet[j].y+FY+dn.y, 0.14f, disp_angle, img_kani[3], TRUE, 0);
						
					}
					if(boss_shot.bullet[j].eff==1){
						SetDrawBlendMode( DX_BLENDMODE_ADD, 255);
						eff=1;
					}
					if(boss_shot.bullet[j].eff==2){//boss_shot_bulletH010用
						SetDrawBlendMode( DX_BLENDMODE_ADD, 255-GetRand(100));
						eff=1;
					}
					DrawRotaGraphF(boss_shot.bullet[j].x+FX+dn.x, boss_shot.bullet[j].y+FY+dn.y, 1.0, disp_angle, img_bullet[boss_shot.bullet[j].knd][boss_shot.bullet[j].col], TRUE);
					if(eff==1){
						SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0);
					}
				}
			}
		}
	}
	SetDrawMode(DX_DRAWMODE_NEAREST);//描画形式を戻す
}

//ボード描画
void graph_board(){
	DrawGraph(	0,	0,img_board[10],FALSE);
	DrawGraph(	0, 18,img_board[11],FALSE);
	DrawGraph(	0,463,img_board[12],FALSE);
	DrawGraph(414,	0,img_board[20],FALSE);
}

void graph_develop(){
	DrawFormatString(0,0,GetColor(255,255,255),"%d",stage_count);
}

void graph_main(){
	if(bright_set.brt!=255)SetDrawBright(bright_set.brt,bright_set.brt,bright_set.brt);

	graph_back_main();//背景描画メイン
	graph_effect(0);//敵が死ぬエフェクト

	if(bright_set.brt!=255)SetDrawBright(255,255,255);

	graph_effect(4);//喰らいボムのエフェクト

	if(bright_set.brt!=255)SetDrawBright(bright_set.brt,bright_set.brt,bright_set.brt);

	graph_boss();
	graph_enemy();//敵の描画
	graph_cshot();//自機ショットの描画

	if(bright_set.brt!=255)SetDrawBright(255,255,255);

	graph_ch();//自機の描画

	if(bright_set.brt!=255)SetDrawBright(bright_set.brt,bright_set.brt,bright_set.brt);
	
	graph_bullet();//弾の描画

	if(bright_set.brt!=255)SetDrawBright(255,255,255);

	graph_effect(1);//ボムのエフェクト
	graph_effect(2);//ボム線のエフェクト
	graph_effect(3);//ボムキャラのエフェクト
	graph_board();//ボードの描画

	graph_develop();
}

アバター
Tatu
記事: 445
登録日時: 13年前
住所: 北海道

Re: 弾幕の作成について

#2

投稿記事 by Tatu » 12年前

大玉の位置を記憶して消去した後、
小弾の発生を大玉のcntではなく、boss_shot.cntによって行い、
boss_shot.cntがある値になったときにすべての小弾を消す、
もしくは小弾のcntが10になると消えるというようにしたらどうでしょうか。

アバター
Tatu
記事: 445
登録日時: 13年前
住所: 北海道

Re: 弾幕の作成について

#3

投稿記事 by Tatu » 12年前

弾幕を作成しました。

[nico]http://www.nicovideo.jp/watch/sm15713555[/nico]

複数の大玉が出てきてもうまくいくように
大玉が止まるタイミングで大玉の使用していない変数に位置を記憶させ、
画面下(ボムや撃破時にアイテムが発生してもその場で消えるため)にとばす、
その後、大玉のフラグを0にするまで記憶した場所周辺に小弾を出させる。
というようにしました。

弾幕関数
► スポイラーを表示

アバター
クラバック
記事: 26
登録日時: 12年前
住所: 関東

Re: 弾幕の作成について

#4

投稿記事 by クラバック » 12年前

有り難うございます・・・!
座標の保存の仕方ですが、構造体の使ってない変数に保存しておく、という方法があるんですね・・・!
そして弾を移動領域外の外に送ってやる、という方法も盲点でした・・・。
有り難うございます。助かりました。

閉鎖

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