C言語ゲームプログラミング  ブロック崩し編 第3回




2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を協力にサポートします。
ブロック崩しゲーム 3Dツリー クリスマスツリー
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する
Study C無料利用についての詳細は、このページを参照してください。



1.スコア表示


今回は、ブロック崩し編 第2回で作成したプログラムを課題2に相当になるように改造していきたいと思います。 まず、下記のコードで右側にスコア表示を行う部分を作成します(単に矩形表示で左右に分けるだけです)。

gl_fillrect(560, 0, 560+5, 480, RGB(200, 200, 0));

スコアの表示はテキスト描画用の関数を使用して次のように初期表示を行います。 テキストの描画については、第11回講座を参照してください。
gl_textout("MSゴシック", 90, 0, 0, 580, 30, "SCORE", RGB(255,255,255), RGB(0,0,0), 0);
gl_textout("MSゴシック", 90, 0, 0, 580, 50, "00000", RGB(255,255,255), RGB(0,0,0), 0);

その後は、ラケットに当たるたびに変数scoreの値を増やしながらスコアを表示していきます。
score++;
sprintf(buff, "%05d", score);
gl_textout("MSゴシック", 90, 0, 0, 580, 50, buff, RGB(255,255,255), RGB(0,0,0), 0);

これらのコードと必要な変数定義をブロック崩し編 第2回で作成したプログラムに追加していきます。 また、右側の反射位置などを640から580に変更します。

#include <graph.h>

main()
{
	HBITMAP	hbmp_ball;
	//ボール用の変数
	int	b_xx = 0, bd_xx = 10,
		b_yy = 0, bd_yy = 10;
	int	bold_xx = -1, bold_yy = -1;

	//ラケット用の変数
	int	r_xx = 320, rold_xx = -1;

	int	score = 0;
	char	buff[100];

	unsigned long
		tick;

	hbmp_ball = gl_loadbitmap("ball.bmp");
	if(hbmp_ball == NULL){
		printf("ビットマップファイルが見つかりません.\n");
		exit(0);
	}
	gl_openwin(-1, -1, 640, 480, 0);

	//縦の黄色線を描画
	gl_fillrect(560, 0, 560+5, 480, RGB(200, 200, 0));

	//スコアの初期値を描画
	gl_textout("MSゴシック", 90, 0, 0, 580, 30, "SCORE", RGB(255,255,255), RGB(0,0,0), 0);
	gl_textout("MSゴシック", 90, 0, 0, 580, 50, "00000", RGB(255,255,255), RGB(0,0,0), 0);

	tick = GetTickCount();
	for( ; ; ){
		if(GetTickCount() >= tick && GetTickCount() < tick + 50)
			continue;
		tick = GetTickCount();

		//ESCキーを押したらプログラムが終了する処理も追加
		if(gl_getkeystate(VK_ESCAPE) < 0)
			break;

		//カーソル左右キーでラケットの位置(r_xx)を変化させます
		//カーソル左キーが押されているときの処理
		if(gl_getkeystate(VK_LEFT) < 0){
			r_xx = r_xx - 20;
			if(r_xx < 0){
				r_xx = 0;
			}
		}
		//カーソル右キーが押されているときの処理
		if(gl_getkeystate(VK_RIGHT) < 0){
			r_xx = r_xx + 20;
			if(r_xx > 560 - 80){
				r_xx = 560 - 80;
			}
		}

		//横方向の処理
		b_xx += bd_xx;
		if(b_xx >= 560-16 || b_xx <= 0){
			//壁に当たったら効果音を鳴らす
			gl_playsound("c:\\windows\\media\\ding.wav");
			bd_xx = -bd_xx;
		}
		if(b_xx < 0){
			b_xx = 0;
		}
		if(b_xx > 560-16){
			b_xx = 560-16;
		}

		//縦方向の処理
		b_yy += bd_yy;
		if(b_yy >= 440-16 || b_yy <= 0){
			bd_yy = -bd_yy;
		}
		if(b_yy <= 0){
			gl_playsound("c:\\windows\\media\\ding.wav");
			b_yy = 0;
		}

		//ボールがウィンドウ下部に来たときの処理
		if(b_yy > 440-16){
			//if文にはボールのサイズを加味した方が良いですが
			//ここでは省略します。
			if(b_xx < r_xx - 16 || b_xx > r_xx + 80 + 16){
				break;
			}
			MessageBeep(0);
			b_yy = 440-16;
			//スコアを描画する

			score++;
			sprintf(buff, "%05d", score);
			gl_textout("MSゴシック", 90, 0, 0, 580, 50, buff,
				RGB(255,255,255), RGB(0,0,0), 0);
		}

		//ボールの消去・描画処理
		if(bold_xx != b_xx || bold_yy != b_yy){
			//前に描画したボールを消去
			if(bold_xx != -1 && bold_yy != -1){
				gl_fillrect(bold_xx, bold_yy,
					bold_xx + 16, bold_yy + 16, RGB(0, 0, 0));
			}
			//ボールの旧位置(bold_xx、bold_yy)を更新
			bold_xx = b_xx;
			bold_yy = b_yy;
			//新しい位置にボールを描画
			gl_drawbitmap(hbmp_ball, b_xx, b_yy, 16, 16, 0, 0);
		}

		//ラケットの消去・描画処理
		if(rold_xx != r_xx){
			//前に描画したラケットを消去
			if(rold_xx != -1){
				gl_fillrect(rold_xx, 440, rold_xx + 80, 440 + 10, RGB(0, 0, 0));
			}
			//ラケットの旧位置(rold_xx)を更新
			rold_xx = r_xx;
			//新しい位置にラケットを描画
			gl_fillrect(r_xx, 440, r_xx + 80, 440 + 10, RGB(255, 255, 255));
		}

		gl_refresh();
	}
}
スコア表示追加

右上部にスコアが表示されるようになります。 また、ボールにラケットが当たるとスコアが一点ずつ増えていきます。

2.マウスでラケット移動


前プログラムでは、カーソルキーでラケットを動かしていました。 キーを押している間、同じ速度でラケットが動くのでゲームとしては操作しずらい作りになっています。 このカーソルでの操作を、マウスでラケットを動かせるように変更します。 マウスカーソル位置の取得については、第9回講座を参照してください。

	gl_getmousepos(&xx, &yy);
	r_xx = xx;
	if(r_xx < 0)
		r_xx = 0;
	if(r_xx > 560 - 80)
		r_xx = 560 - 80;
このようにマウスカーソルの座標を取得しラケットの位置に置き換えます。 Y軸方向の座標は使用していません。 その他、ボールが壁や天井に当たったときに効果音を鳴らします。
	gl_playsound("c:\\windows\\media\\ding.wav");
Windows下のmediaディレクトリにいくつかの音データが格納されています。 Windowsのバージョンによっても用意されているファイルが違うと思いますので、このファイルは使っている環境に合わせて修正してください。
	if(b_yy <= 0){
		gl_playsound("c:\\windows\\media\\ding.wav");
		b_yy = 0;
	}
天井に当たったときは、上記のようにif文で等号がないと音が鳴らないので注意してください。

#include <graph.h>

main()
{
	HBITMAP	hbmp_ball;
	//ボール用の変数
	int	b_xx = 0, bd_xx = 10,
		b_yy = 0, bd_yy = 10;
	int	bold_xx = -1, bold_yy = -1;

	//ラケット用の変数
	int	r_xx = 320, rold_xx = -1;
	long	xx, yy;

	int	score = 0;
	char	buff[100];

	unsigned long
		tick;

	hbmp_ball = gl_loadbitmap("ball.bmp");
	if(hbmp_ball == NULL){
		printf("ビットマップファイルが見つかりません.\n");
		exit(0);
	}
	gl_openwin(-1, -1, 640, 480, 0);

	//縦の黄色線を描画
	gl_fillrect(560, 0, 560+5, 480, RGB(200, 200, 0));

	//スコアの初期値を描画
	gl_textout("MSゴシック", 90, 0, 0, 580, 30, "SCORE", RGB(255,255,255), RGB(0,0,0), 0);
	gl_textout("MSゴシック", 90, 0, 0, 580, 50, "00000", RGB(255,255,255), RGB(0,0,0), 0);

	tick = GetTickCount();
	for( ; ; ){
		if(GetTickCount() >= tick && GetTickCount() < tick + 50)
			continue;
		tick = GetTickCount();

		//ESCキーを押したらプログラムが終了する処理も追加
		if(gl_getkeystate(VK_ESCAPE) < 0)
			break;

		//ラケットをマウスで動かす
		gl_getmousepos(&xx, &yy);
		r_xx = xx;
		if(r_xx < 0)
			r_xx = 0;
		if(r_xx > 560 - 80)
			r_xx = 560 - 80;

		//横方向の処理
		b_xx += bd_xx;
		if(b_xx >= 560-16 || b_xx <= 0){
			//壁に当たったら効果音を鳴らす
			gl_playsound("c:\\windows\\media\\ding.wav");
			bd_xx = -bd_xx;
		}
		if(b_xx < 0){
			b_xx = 0;
		}
		if(b_xx > 560-16){
			b_xx = 560-16;
		}

		//縦方向の処理
		b_yy += bd_yy;
		if(b_yy >= 440-16 || b_yy <= 0){
			bd_yy = -bd_yy;
		}
		if(b_yy <= 0){
			gl_playsound("c:\\windows\\media\\ding.wav");
			b_yy = 0;
		}

		//ボールがウィンドウ下部に来たときの処理
		if(b_yy > 440-16){
			//if文にはボールのサイズを加味した方が良いですが
			//ここでは省略します。
			if(b_xx < r_xx - 16 || b_xx > r_xx + 80 + 16){
				break;
			}
			MessageBeep(0);
			b_yy = 440-16;
			//スコアを描画する

			score++;
			sprintf(buff, "%05d", score);
			gl_textout("MSゴシック", 90, 0, 0, 580, 50, buff,
				RGB(255,255,255), RGB(0,0,0), 0);
		}

		//ボールの消去・描画処理
		if(bold_xx != b_xx || bold_yy != b_yy){
			//前に描画したボールを消去
			if(bold_xx != -1 && bold_yy != -1){
				gl_fillrect(bold_xx, bold_yy,
					bold_xx + 16, bold_yy + 16, RGB(0, 0, 0));
			}
			//ボールの旧位置(bold_xx、bold_yy)を更新
			bold_xx = b_xx;
			bold_yy = b_yy;
			//新しい位置にボールを描画
			gl_drawbitmap(hbmp_ball, b_xx, b_yy, 16, 16, 0, 0);
		}

		//ラケットの消去・描画処理
		if(rold_xx != r_xx){
			//前に描画したラケットを消去
			if(rold_xx != -1){
				gl_fillrect(rold_xx, 440, rold_xx + 80, 440 + 10, RGB(0, 0, 0));
			}
			//ラケットの旧位置(rold_xx)を更新
			rold_xx = r_xx;
			//新しい位置にラケットを描画
			gl_fillrect(r_xx, 440, r_xx + 80, 440 + 10, RGB(255, 255, 255));
		}

		gl_refresh();
	}
}
課題2のプログラムが完成、前の画像と同じでした

これで課題2のプログラムが完成です。