■ 新・ゲーム開発講座




■ へっぽこプログラミング入門♪


■第47夜:ファイル名キャッシュ

SAVE機構の実装前に、これまで「読みっぱなし」になっていた画像ファイル名をキャッシュするようにソースを書き換えておきましょう。MIDI/MP3/WAVについては読んだファイル名のキャッシュを行っていたのですが、いまごろになって画像ファイルをキャッシュしていなかったことに気がつきました(汗 ^^;)

■キャッシュとは?

一般には、一度読み込んだデータをメモリ内に保存しておき、次回アクセスの際にはDISKではなく高速なメモリからデータを読む機構…とされています。が、本稿でいうキャッシュとは、データをまるごとバッファリングするような高尚なものではありません。単に「一度読んだファイル名を覚えておく」だけです(あのなー ^0^;)
とはいえ、これが出来ないとSAVE処理で画面情報が保存できませんので泣き言をいわずにしこしこ追加しましょう。

本稿のソースを見渡してみると、画像を読み込んでいるのは

1)初期化
main.cpp void init_Back_Surface()
main.cpp void init_Parts_Surface()
main.cpp void init_BG_Surface()


2)#g_load コマンド (BMP読み込み)
Text_Com_01.cpp int Com_g_load()



であり、それに準じるもの(背景画面からバックサーフェイスへのフルコピー)として、

3)#g_change コマンド(画面切り替え)
sub_Com_g_change_task_1()
sub_Com_g_change_task_2()
sub_Com_g_change_task_3()
sub_Com_g_change_task_4()


4)#page コマンド(改ページ)
Text_Com_01.cpp int Com_page()


5)テキスト表示がページ端に達した場合の改ページ処理
Text_Com_01.cpp int Com_page2()


が挙げられます。画面 to 画面のフルコピーについてはキャッシュファイル名をコピーしてやれば管理はできますので対応することに致しましょう。

キャッシュの方法は単純です。char型配列を画面分用意して、キャッシュしたいタイミングで strcpy() でファイル名をコピーするだけです。難易度的にはほとんどゼロに近い操作ですが、漏れがあってはいけない、という点で注意が必要です。とにかく1箇所でもキャッシュミスがあるとLOAD時に画面を正しく再現できなくなってしまいますので…。

え?なんだか面倒…ですか?(^^;)
たしかにそのとおりです。ゲームの規模が大きくなるとこの種のチェックはもっと面倒になるかもしれません。だからこそ
主人公の部屋とかキャンプモードが重宝されるともいえます。しかしこれって、ノベルというジャンルを選んだからには、いずれ避けては通れない内容なんですよね。難易度は低くて根性でカバーできる内容なのですから、ここは努力いたしましょうよ(^^;)

そんな訳で、ここでは改変箇所だけ列挙しておしまいにします。↓うわーリストだらけだ。はわわわ…



main.cpp

//ファイル名キャッシュ用
char BK_bmp_fname[512]; //バック画面(裏画面)のファイル名
char BG_bmp_fname[512]; //背景画面のファイル名
char PT_bmp_fname[512]; //パーツ画面のファイル名

//-----------------------------------
// バックサーフェイス初期化
//-----------------------------------

void init_Back_Surface()
{

HDC work_hdc; //作業用のDC

//■ バック画面の初期化
work_hdc=GetDC(hwnd); //主(表)画面のDCの内容を取得
Back_DC=CreateCompatibleDC(work_hdc); //同じ設定でバック画面用のDCを生成
hBack_Bitmap=CreateCompatibleBitmap(work_hdc,640,480);//主(表)画面と同じ属性で画面生成
SelectObject(Back_DC,hBack_Bitmap); //DCと画面本体を関連付ける

Load_Bmp( BG_DC,".\\gdat\\Back00.bmp"); //デフォルト背景BMPを読み込んでおく
strcpy( BG_bmp_fname,".\\gdat\\Back00.bmp"); //読み込んだファイル名をキャッシュ

ReleaseDC(hwnd,work_hdc); //作業用DCを開放


}

//-----------------------------------
// パーツ用サーフェイス初期化
//-----------------------------------

void init_Parts_Surface()
{

HDC work_hdc; //作業用のDC

//■ バック画面の初期化
work_hdc=GetDC(hwnd); //主(表)画面のDCの内容を取得
Parts_DC=CreateCompatibleDC(work_hdc); //同じ設定でバック画面用のDCを生成
hParts_Bitmap=CreateCompatibleBitmap(work_hdc,75,25);//主(表)画面と同じ属性で画面生成
SelectObject(Parts_DC,hParts_Bitmap); //DCと画面本体を関連付ける

Load_Bmp( Parts_DC,".\\gdat\\Parts.bmp"); //パーツ用BMPを読み込んでおく
strcpy( PT_bmp_fname,".\\gdat\\Parts.bmp"); //読み込んだファイル名をキャッシュ

ReleaseDC(hwnd,work_hdc); //作業用DCを開放

}

//-----------------------------------
// 背景画像用サーフェイス初期化
//-----------------------------------

void init_BG_Surface()
{

HDC work_hdc; //作業用のDC

//■ バック画面の初期化
work_hdc=GetDC(hwnd); //主(表)画面のDCの内容を取得
BG_DC=CreateCompatibleDC(work_hdc); //同じ設定でバック画面用のDCを生成
hBG_Bitmap=CreateCompatibleBitmap(work_hdc,640,480); //主(表)画面と同じ属性で画面生成
SelectObject(BG_DC,hBG_Bitmap); //DCと画面本体を関連付ける

Load_Bmp( BG_DC,".\\gdat\\Back00.bmp"); //デフォルト背景BMPを読み込んでおく
strcpy( BG_bmp_fname,".\\gdat\\Back00.bmp"); //読み込んだファイル名をキャッシュ

ReleaseDC(hwnd,work_hdc); //作業用DCを開放

}



Text_Com_01.cpp

int Com_g_load()
{

char vram[32];
char f_name[256];

//画面指定の解釈
TEXT++;
strcpy( vram, Kaiseki_TextStr() ); //画面指定切り出し
while( *TEXT==',' || *TEXT==' ' || *TEXT==0x0a )TEXT++;

//ファイル名の解釈
strcpy( f_name, G_PATH ); //Path
strcat( f_name, Kaiseki_TextStr() );

Load_Bmp( Get_game_DC(vram), f_name );

//背景画面情報のキャッシュ(SAVE対策)
if( strcmp( "BS" , vram )==0 ) strcpy(BK_bmp_fname,f_name) ; //バックサーフェイス
if( strcmp( "BK" , vram )==0 ) strcpy(BK_bmp_fname,f_name) ; //「BK」の表記も許容しよう…(^^;)
if( strcmp( "BG" , vram )==0 ) strcpy(BG_bmp_fname,f_name) ; //背景画面
if( strcmp( "PT" , vram )==0 ) strcpy(PT_bmp_fname,f_name) ; //パーツ画面

return 0;

}

Text_Com_01.cpp

/------------------------------------------------------------
// 改ページ@ スクリプトコマンドとしての改ページ
//
// 書式:#page
//
// 画面を背景画像で上書きしてテキストを消し、文字表示位置を
// リセットする。
//------------------------------------------------------------

int Com_page()
{

//背景データでバックサーフェイスを書き換える
BitBlt(Back_DC,0,0,640,480,BG_DC,0,0,SRCCOPY);
strcpy(BK_bmp_fname,BG_bmp_fname) ; //ファイル名をBG面のものでキャッシュ

//文字表示位置をテキストエリアの左肩にリセットする
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

return 0;



}

//------------------------------------------------------------
// 改ページA ページ端に達してしまった場合の禁則処理
//------------------------------------------------------------

int Com_page2_end()
{

//テキスト表示フラグを戻す
Mode_stat.flag_text = ON;

//改ページ用フラグを解除
Mode_stat.flag_page2 = OFF;

//背景データでバックサーフェイスを書き換える
BitBlt(Back_DC,0,0,640,480,BG_DC,0,0,SRCCOPY);
strcpy(BK_bmp_fname,BG_bmp_fname) ; //ファイル名をBG面のものでキャッシュ

//文字表示位置をテキストエリアの左肩にリセットする
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

return 0;

}

Text_Com_02.cpp

//----------------------------
// カーテン型
//----------------------------

int sub_Com_g_change_task_1()
{

int pitch = 10;

//タイマーチェック
if( HLS_timer_check( g_change_timer,g_change_wait )==false )return 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

BitBlt( Back_DC,g_change_frame_counter ,0,pitch-9,480,
BG_DC, g_change_frame_counter ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -10 ,0,pitch-8,480,
BG_DC, g_change_frame_counter -10 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -20 ,0,pitch-7,480,
BG_DC, g_change_frame_counter -20 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -30 ,0,pitch-6,480,
BG_DC, g_change_frame_counter -30 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -40 ,0,pitch-5 ,480,
BG_DC, g_change_frame_counter -40 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -50 ,0,pitch-4 ,480,
BG_DC, g_change_frame_counter -50 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -60 ,0,pitch-3 ,480,
BG_DC, g_change_frame_counter -60 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -70 ,0,pitch-2 ,480,
BG_DC, g_change_frame_counter -70 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -80 ,0,pitch-1 ,480,
BG_DC, g_change_frame_counter -80 ,0,SRCCOPY);


BitBlt( Back_DC,g_change_frame_counter -90 ,0,pitch ,480,
BG_DC, g_change_frame_counter -90 ,0,SRCCOPY);


if( g_change_frame_counter - 100 < 640 ){
g_change_frame_counter += pitch;
}else{

//終了条件

//テキスト表示を再開する
Mode_stat.flag_text = ON;

//画面切替えのフラグをクリア
Mode_stat.flag_g_change = OFF;

//文字表示位置を初期化しておく
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

strcpy( BK_bmp_fname,BG_bmp_fname ); //画面キャッシュの操作(BG→BK全面コピーに相当するので)

}

return 0;

}

//----------------------------
// 放射型
//----------------------------

int sub_Com_g_change_task_2()
{


static int A[]={
34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34, //00
33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, //01
32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, //02
31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, //03
30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, //04
29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29, //05
28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, //06
27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, //07
26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24,25, //08
25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24, //09
24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23, //10
23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22, //11
22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21, //12
21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20, //13
20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19, //14
19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18, //15
19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18, //16
20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19, //17
21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20, //18
22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21, //19
23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22, //20
24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23, //21
25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 6, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24, //22
26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 7, 8, 9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24,25, //23
27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, //24
28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, 9, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, //25
29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29, //26
30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, //27
31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, //28
32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, //29
33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33, //30
34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34, //31

};
int x,y;

//タイマーチェック
if( HLS_timer_check( g_change_timer,g_change_wait )==false )return 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

for( y=0;y<32;y++ ){
for( x=0;x<40;x++ ) {
if( A[y*40+x] == g_change_frame_counter ){
StretchBlt( Back_DC,x*16+7,y*16+7, 2, 2,BG_DC,x*16+4,y*16+4,2,2,SRCCOPY);
}
if( A[y*40+x] == g_change_frame_counter-2 ){
StretchBlt( Back_DC,x*16+6,y*16+6, 4, 4,BG_DC,x*16+6,y*16+6,4,4,SRCCOPY);

}
if( A[y*40+x] == g_change_frame_counter-4 ){
StretchBlt( Back_DC,x*16+4,y*16+4, 6, 6,BG_DC,x*16+4,y*16+4,6,6,SRCCOPY);
}
if( A[y*40+x] == g_change_frame_counter-6 ){
StretchBlt( Back_DC,x*16+3,y*16+3, 8, 8,BG_DC,x*16+3,y*16+3,8,8,SRCCOPY);
}
if( A[y*40+x] == g_change_frame_counter-8 ){
StretchBlt( Back_DC,x*16+2,y*16+2,12,12,BG_DC,x*16+2,y*16+2,12,12,SRCCOPY);
}
if( A[y*40+x] == g_change_frame_counter-10 ){
StretchBlt( Back_DC,x*16 ,y*16 ,16,16,BG_DC,x*16,y*16,16,16,SRCCOPY);
}
}
}

if( g_change_frame_counter < 45 ){
g_change_frame_counter++;
}else{

//終了条件

//テキスト表示を再開する
Mode_stat.flag_text = ON;

//画面切替えのフラグをクリア
Mode_stat.flag_g_change = OFF;

//文字表示位置を初期化しておく
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

strcpy( BK_bmp_fname,BG_bmp_fname ); //画面キャッシュの操作(BG→BK全面コピーに相当するので)

}

return 0;

}

//----------------------------
// 伸縮型(X)
//----------------------------

int sub_Com_g_change_task_3()
{

int pitch = 20;

//タイマーチェック
if( HLS_timer_check( g_change_timer,g_change_wait )==false )return 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

StretchBlt( Back_DC, 640/2-g_change_frame_counter,0,g_change_frame_counter*2,480,BG_DC,0,0,640,480,SRCCOPY);

if( g_change_frame_counter < 640/2 ){
g_change_frame_counter += pitch;
}else{

//終了条件

//テキスト表示を再開する
Mode_stat.flag_text = ON;

//画面切替えのフラグをクリア
Mode_stat.flag_g_change = OFF;

//文字表示位置を初期化しておく
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

strcpy( BK_bmp_fname,BG_bmp_fname ); //画面キャッシュの操作(BG→BK全面コピーに相当するので)

}

return 0;

}

//----------------------------
// 伸縮型(Y)
//----------------------------

int sub_Com_g_change_task_4()
{

int pitch = 20;

//タイマーチェック
if( HLS_timer_check( g_change_timer,g_change_wait )==false )return 0;

//タイマーショット
HLS_timer_start(&g_change_timer);

StretchBlt(Back_DC, 0,480/2-g_change_frame_counter,640,g_change_frame_counter*2,BG_DC,0,0,640,480,SRCCOPY);

if( g_change_frame_counter < 480/2 ) {
g_change_frame_counter += pitch;

}else{

//終了条件

//テキスト表示を再開する
Mode_stat.flag_text = ON;

//画面切替えのフラグをクリア
Mode_stat.flag_g_change = OFF;

//文字表示位置を初期化しておく
TEXT_X = TEXT_AREA.left;
TEXT_Y = TEXT_AREA.top;

strcpy( BK_bmp_fname,BG_bmp_fname ); //画面キャッシュの操作(BG→BK全面コピーに相当するので)

}

return 0;

}