C言語ゲームプログラミング 第13回講座




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



1.背景のあるウィンドウでのビットマップの移動


前回作成したマスクパターンを使用した描画プログラムを改造して、カーソルキーで上下左右に移動するようにします。 第8回講座を参考にして改造すると次のようなプログラムになると思います。
#include <graph.h>

main()
{
	HBITMAP	hbmp_base, hbmp_square, hbmp_squaremask;
	int	b_xx, b_yy, bold_xx, bold_yy;
	unsigned long
		tick;

	//hbmp_base = gl_loadbitmap("c:\\windows\\雲.bmp");
	hbmp_base = gl_loadbitmap("c:\\windows\\シャボン.bmp");
	hbmp_square = gl_loadbitmap("square.bmp");
	hbmp_squaremask = gl_loadbitmap("square_bw.bmp");
	if(hbmp_base == NULL || hbmp_square == NULL || hbmp_squaremask == NULL){
		printf("ビットマップファイルが見つかりません.\n");
		exit(0);
	}
	gl_openwin(-1, -1, 256, 256, 0);
	gl_drawbitmap(hbmp_base, 0, 0, 256, 256, 0, 0);

	bold_xx = bold_yy = -1;
	b_xx = 128-32;
	b_yy = 128-32;
	tick = GetTickCount();

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

		if(gl_getkeystate(VK_ESCAPE) < 0)
			break;

		if(gl_getkeystate(VK_LEFT) < 0){
			b_xx -= 10;
			if(b_xx < 0)
				b_xx = 0;
		}
		if(gl_getkeystate(VK_RIGHT) < 0){
			b_xx += 10;
			if(b_xx > 256 - 64)
				b_xx = 256 - 64;
		}
		if(gl_getkeystate(VK_UP) < 0){
			b_yy -= 10;
			if(b_yy < 0)
				b_yy = 0;
		}
		if(gl_getkeystate(VK_DOWN) < 0){
			b_yy += 10;
			if(b_yy > 256 - 64)
				b_yy = 256 - 64;
		}

		if(bold_xx != b_xx || bold_yy != b_yy){
			if(bold_xx != -1 && bold_yy != -1){
				gl_fillrect(bold_xx, bold_yy, bold_xx + 64, bold_yy + 64, RGB(0, 0, 0));
			}
			bold_xx = b_xx;
			bold_yy = b_yy;
			gl_maskdrawbitmap(hbmp_square, hbmp_squaremask, b_xx, b_yy, 64, 64, 0, 0);
		}
		gl_refresh();
	}
}

このプログラムを実行すると画面の一部が次のように黒く抜けてしまうようになると思います。

今までのプログラムでは、背景が黒だったためビットマップを移動しても問題がありませんでした。 しかし、今回のプログラムのように背景自体がビットマップの場合では、このような問題が発生します。


2.背景の再描画


この問題は簡単に解決することができます。 移動直後にgl_fillrect()関数で移動前のビットマップを消去していますが、この部分を背景ビットマップで再描画することで解決されます。
再描画も通常の描画と同じく、gl_drawbitmap()関数で行うことができます。 ただし、ビットマップ全体を描画するのではなく必要最小限の範囲を再描画するようにします。
#include <graph.h>

main()
{
	HBITMAP	hbmp_base, hbmp_square, hbmp_squaremask;
	int	b_xx, b_yy, bold_xx, bold_yy;
	unsigned long
		tick;

	//hbmp_base = gl_loadbitmap("c:\\windows\\雲.bmp");
	hbmp_base = gl_loadbitmap("c:\\windows\\シャボン.bmp");
	hbmp_square = gl_loadbitmap("square.bmp");
	hbmp_squaremask = gl_loadbitmap("square_bw.bmp");
	if(hbmp_base == NULL || hbmp_square == NULL || hbmp_squaremask == NULL){
		printf("ビットマップファイルが見つかりません.\n");
		exit(0);
	}
	gl_openwin(-1, -1, 256, 256, 0);
	gl_drawbitmap(hbmp_base, 0, 0, 256, 256, 0, 0);

	bold_xx = bold_yy = -1;
	b_xx = 128-32;
	b_yy = 128-32;
	tick = GetTickCount();

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

		if(gl_getkeystate(VK_ESCAPE) < 0)
			break;

		if(gl_getkeystate(VK_LEFT) < 0){
			b_xx -= 10;
			if(b_xx < 0)
				b_xx = 0;
		}
		if(gl_getkeystate(VK_RIGHT) < 0){
			b_xx += 10;
			if(b_xx > 256 - 64)
				b_xx = 256 - 64;
		}
		if(gl_getkeystate(VK_UP) < 0){
			b_yy -= 10;
			if(b_yy < 0)
				b_yy = 0;
		}
		if(gl_getkeystate(VK_DOWN) < 0){
			b_yy += 10;
			if(b_yy > 256 - 64)
				b_yy = 256 - 64;
		}

		if(bold_xx != b_xx || bold_yy != b_yy){
			if(bold_xx != -1 && bold_yy != -1){
				gl_drawbitmap(hbmp_base, bold_xx, bold_yy, 64, 64, bold_xx, bold_yy);
			}
			bold_xx = b_xx;
			bold_yy = b_yy;
			gl_maskdrawbitmap(hbmp_square, hbmp_squaremask, b_xx, b_yy, 64, 64, 0, 0);
		}
		gl_refresh();
	}
}

これで四角を移動しても黒く抜けるようなことはなくなります。