ページ 11

弾が当たると弾を消す

Posted: 2011年2月12日(土) 04:20
by
タイトル通りなのですが、的に弾が当たったら弾のグラフィックを消すという処理をしたいのですがどうすればよいのでしょうか?
開発環境:VisualC++2008
開発言語:C言語


色々試してみてDeleteGraphという関数を使って弾と的が接触したら削除というようにしました。
すると、正常に消えるのですがその後弾が出てきません。データを一度しか読み込んでないので、それっきり弾の画像が読み込まれなく
なってしまっているんだと思います。
画面上に表示されてある一部のグラフィックを削除するような関数は存在しますか?
一番上で書いたような処理をするには如何すればよいでしょうか?
質問ばかりですみません・・。

Re: 弾が当たると弾を消す

Posted: 2011年2月12日(土) 04:40
by 迷彩吹雪
「グラフィックを削除する」のではなく、「不要なグラフィックを描画しない」と考えた方が良いと思います。
的に接触した弾にフラグを持たせて、そのOn/Offで「描画するべきか否か」を判定し、「描画すべき」時だけ描画するのです。

具体的なことはコードが示されていないのでアドバイスしかねます。
差し支えなければ必要最低限でもコードを貼っていただけると、もっと的確な返答が期待できるかと思います。

Re: 弾が当たると弾を消す

Posted: 2011年2月12日(土) 15:26
by
返答・ご回答ありがとうございます。
ON/OFFで判定とは思いつきませんでした!まだまだ初心者ですね・・・。

コード:

#define Player_Burret_MAX  3 //連続で発射される弾の数
#define Graph_Counter_MAX 20 //何フレーム間グラフィックを表示するか
#define Burret_FPS         5 //なんフレーム目で2発目を出すか

//敵データ
extern int Enemis_X = 10;	//X座標
extern int Enemis_Y = 110;	//Y座標

//自機構造体
struct Player{
	int Graph;
};

//弾構造体
struct Burret{
	int X[Player_Burret_MAX];
	int Y[Player_Burret_MAX];
	int Flag[Player_Burret_MAX];
	int FPS;
	int Graph;
};
//弾データ
int damage_Graph;
	
//敵機データ

//敵機構造体
 struct Enemis{
	int Graph;
	int damage_Flag;
	int damage_FPS;
	bool direction;
};

//音データ
 struct Music{
	 int Graph;
	 int hassya;
 };

 //構造体宣言
 Player Player;
 Burret Burret;
 Enemis Enemis;
 Music  Music;

コード:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include "DxLib.h"
#include"data.h" 


//関数プロトタイプ宣言
void Load_Graph();		//ロード処理
void Player_Operation();//プレイヤーの操作、移動ルーチン
void Enemis_Operation();//敵の移動ルーチン
void Erorr_Message();	//エラーメッセージ処理
void Player_Burret();	//プレイヤー攻撃
void HitPoint_Burret( int Burret_x, int Burret_y, int Enemy_x, int Enemy_y );//当たり判定
void Sound_effects( int Sound_data, int flagORframe );

int Key[256];
int Color = GetColor( 255, 255, 255 ); //基本(黒) 
int SRand((unsigned)time(NULL));	  //乱数
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
	char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}
	//プレイヤーデータ
int X_Player = 100; //X座標
int Y_Player = 30; //Y座標
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
	// 画面モードの設定
	SetGraphMode( 640 , 480 , 16 ) ;
	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
		Load_Graph();
	while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
		//↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
Player_Operation();
Enemis_Operation();
Player_Burret();

        ScreenFlip();
 }   
 
    DxLib_End();
    return 0;
}

//プレイヤー操作
void Player_Operation(){

	//プレイヤーの移動ルーチン
	if( CheckHitKey(KEY_INPUT_RIGHT) == 1 ) X_Player += 3;
	if( CheckHitKey(KEY_INPUT_LEFT)  == 1 ) X_Player -= 3;
	if( CheckHitKey(KEY_INPUT_UP)    == 1 ) Y_Player -= 3;
	if( CheckHitKey(KEY_INPUT_DOWN)  == 1 ) Y_Player += 3;
	if( X_Player > 625 ) X_Player -= 3;
	if( X_Player < 0   ) X_Player += 3;
	if( Y_Player > 455 ) Y_Player -= 3;
	if( Y_Player < 0   ) Y_Player += 3; 

DrawGraph( X_Player, Y_Player, Player.Graph, TRUE ); //画像の表示
}


//プレイヤーの弾移動ルーチン
void Player_Burret(){
	int left_ans = 0;
	int right_ans= 0;

	if( CheckHitKey(KEY_INPUT_Z) == 1){
		if( Burret.FPS == 0 ){
	for(int i=0 ; i<Player_Burret_MAX ; i++){
		if( Burret.Flag[i] == 0 ){
	PlaySoundMem( Music.hassya, DX_PLAYTYPE_BACK ); //音の再生
	Burret.X[i] = X_Player;
	Burret.Y[i] = Y_Player;
		Burret.Flag[i] = 1;
		break;
         	}
   	   }
		Burret.FPS = Burret_FPS;
		}
	else 
		Burret.FPS -= 1;
	}

	for( int i=0 ; i< Player_Burret_MAX ; i++ ){
	if( Burret.Flag[i] == 1 ){
		Burret.Y[i] -= 16;
	if( Burret.Y[i] < -80 ) Burret.Flag[i] = 0;

	DrawGraph( Burret.X[i], Burret.Y[i], Burret.Graph, TRUE );	//左銃
	HitPoint_Burret( Burret.X[i], Burret.Y[i], Enemis_X, Enemis_Y );//左銃ダメージ判定	
	DrawGraph( Burret.X[i]+10, Burret.Y[i], Burret.Graph, TRUE );//右銃
	HitPoint_Burret( Burret.X[i]+10, Burret.Y[i], Enemis_X, Enemis_Y );//右銃ダメージ判定
			
		}
	}
}

//攻撃判定
void HitPoint_Burret(int Burret_x, int Burret_y, int Enemy_x, int Enemy_y ){
	
int Attack_hankei;
int damage_counter = 0;

Attack_hankei = ((5+9)*(5+9));
if( ((Burret_x - Enemy_x)*(Burret_x - Enemy_x))+((Burret_y+5 - Enemy_y+5)*(Burret_y+5 - Enemy_y+5)) <= Attack_hankei ){
	PlaySoundMem( Music.Graph, DX_PLAYTYPE_BACK ); 
			Enemis.damage_Flag = 1;
		}

		else if( Enemis.damage_Flag == 1 ){
			if( damage_counter == 0 ){
				DrawGraph( Enemy_x, Enemy_y, damage_Graph, TRUE );
				damage_counter = 1;
				Enemis.damage_FPS ++;
			}
			if( Enemis.damage_FPS == Graph_Counter_MAX ){
				Enemis.damage_FPS = 0;
				Enemis.damage_Flag= 0;
				damage_counter = 0;
			}
			
	}
//-----
#ifdef _DEBUG
DrawCircle( Enemy_x+8 , Enemy_y+5 , 9 , Color, FALSE ) ;
DrawCircle( Burret_x+3 , Burret_y+5 , 5 , Color, FALSE );
DrawLine(Enemy_x+8,Enemy_y+5,Burret_x+3,Burret_y+5,Color);
#endif
//-----

return 1;
}

//敵の移動ルーチン
void Enemis_Operation(){

	if( Enemis_X < 0   ) Enemis.direction = TRUE;
	if( Enemis.direction == TRUE ) Enemis_X  += 2;
	if( Enemis_X > 625 ) Enemis.direction = FALSE;
	if( Enemis.direction == FALSE ) Enemis_X -= 2;
	DrawGraph( Enemis_X, Enemis_Y, Enemis.Graph, TRUE );
	}

//画像の読み込み
void Load_Graph(){

	//プレイヤーグラフィックの読み込み
	Player.Graph = LoadGraph( "media\\jiki.png", 0 ); 
	//弾画像の読み込み
	Burret.Graph = LoadGraph( "media\\tama.png", 0 );
	//敵画像の読み込み
	Enemis.Graph = LoadGraph( "media\\enemy.png", 0 );
	//ダメージ画像読み込み
	damage_Graph = LoadGraph( "media\\damage.png", 0 );
	//音の読み込み
	Music.Graph  = LoadSoundMem("media\\crash18_f.wav");
	//音の読み込み
	Music.hassya = LoadSoundMem("media\\masingan.wav");
	if( Player.Graph == -1 || Enemis.Graph == -1 || Burret.Graph == -1 || damage_Graph == -1 || Music.Graph == -1 || Music.hassya == -1 ){//エラー表示
		Erorr_Message();
	}
	
}

//エラーメッセージ処理
void Erorr_Message(){
	MessageBox( NULL, "画像を読み込めません。プログラムを終了します。", "Graph error", MB_OK);
	exit(0);
}
どこにフラグを持たせればよいでしょうか?
DrawGraph( Burret.X, Burret.Y, Burret.Graph, TRUE ); //左銃
HitPoint_Burret( Burret.X, Burret.Y, Enemis_X, Enemis_Y );//左銃ダメージ判定
この部分に戻り値を使ってやってみたのですが、どうもうまくいきませんでした。(右左両方)
どんな感じでやれば良いのでしょうか?
本当に質問ばかりですみません・・・。

Re: 弾が当たると弾を消す

Posted: 2011年2月12日(土) 19:38
by 迷彩吹雪
Burret.Flagの構造体変数が弾の生死を示すフラグでしょうか。その前提で少しだけ書き換えてみました。

コード:

//プレイヤーの弾移動ルーチン
void Player_Burret(){
	
	//中略

	for( int i=0 ; i< Player_Burret_MAX ; i++ ){
		if( Burret.Flag[i] == 1 ){
			Burret.Y[i] -= 16;
			if( Burret.Y[i] < -80 ) Burret.Flag[i] = 0;

			if( Burret.Flag[i] == 1 ){		//<---------------------------------------------ここ
				//i番目の弾が生きているなら接触判定と描画処理を実行する
				//HitPoint_Burret()の引数が変わっています
				HitPoint_Burret( Burret.X[i], Burret.Y[i], i, Enemis_X, Enemis_Y );		//左銃ダメージ判定
				HitPoint_Burret( Burret.X[i]+10, Burret.Y[i], i, Enemis_X, Enemis_Y );	//右銃ダメージ判定
				DrawGraph( Burret.X[i], Burret.Y[i], Burret.Graph, TRUE );  //左銃
				DrawGraph( Burret.X[i]+10, Burret.Y[i], Burret.Graph, TRUE );//右銃
		}
	}
}


//攻撃判定
//void HitPoint_Burret(int Burret_x, int Burret_y, int Enemy_x, int Enemy_y ){
void HitPoint_Burret(int Burret_x, int Burret_y, int Burret_num, int Enemy_x, int Enemy_y ){//弾の座標だけでなく番号も渡してみる
	int Attack_hankei;
	int damage_counter = 0;

	Attack_hankei = ((5+9)*(5+9));
	if( ((Burret_x - Enemy_x)*(Burret_x - Enemy_x))+((Burret_y+5 - Enemy_y+5)*(Burret_y+5 - Enemy_y+5)) <= Attack_hankei ){
		//敵と弾が接触している
		PlaySoundMem( Music.Graph, DX_PLAYTYPE_BACK ); 
		Enemis.damage_Flag = 1;			//敵はダメージを喰らった
		Burret.Flag[Burret_num] = 0;	//接触した弾の発射フラグをオフにする	//<-------------ここ
	}

	//以下略

	return 1;
}
16,17行目が弾の描画部分ですね。ここをif文で囲み、Burret.Flagの値を見て描画するべきか否かを判定しています。
Burret.Flagは発射時に1になる処理がPlayer_Burret()中にありましたが、着弾時に0になる処理が見当たらなかったのでHitPoint_Burret()で着弾の判定が出た時にBurret.Flag=0しています。
が、そのためにはその弾が何番なのか知らなければならなかったのでHitPoint_Burret()の引数を一つ増やしました。(もし他の場所で処理しているのなら訂正してください)
こんな感じで、どうでしょう。

本題とは逸れますが、このコードだと左右の弾がどちらか一方でも的に当たれば両方とも消えませんか? 私の勘違いかそのような仕様なら構いませんが。
(あと、burretではなくbulletだったり……。)

(2/12 20:20 記述ミスがあったので修正しました)

Re: 弾が当たると弾を消す

Posted: 2011年2月13日(日) 13:18
by
詳しく教えていただきありがとうございます。
英語は苦手で・・・。
教えていただいたコードを参考にして作ってみたいと思います。
右銃左銃で処理をバラバラにしてみます。