敵の基本的な行動も、ボスも弾幕も出来たので早く一つステージを完成させてみたいですね。
これからはステージを一つ完成させるための細かな作業を色々していこうとおもいます。
龍神録も東方も、ステージの始まりにちょろっと敵が出てきて、タイトルが表示され、
本格的にそのステージがはじまりますね。そのステージタイトルを表示させてみます。
今回の作業も前回までと同様、ステージタイトル用の構造体と変数を用意し、
表示すべきタイミングになったらそのflagをオンにすれば、
後は自動的に計算してくれるようなプログラムを書きます。
登録・計算・描画の3本柱はいつもの基本スタイルですね。
では今回、計算部を増やすので、calc.cppというファイルを追加して下さい。
calc.cppでは様々な細かな今まで以外の計算処理をかいていくファイルとします。
メインループからはこれから実装するcalc_main関数のみを呼び、
calc_main関数内で、どの関数を呼ぶか決めます。
よって、まず構造体の定義、変数の宣言をしてみましょう。
後、今回ステージを設定する為に、今のステージがどこなのかを示すstageと
全体で何ステージあるのかを示す定義STAGE_NUMを用意します。
---- define.h に以下を追加 ---- //ステージ数 #define STAGE_NUM 5 ---- GV.h に以下(赤字部)を追加---- //フラグ・ステータス変数 GLOBAL int func_state,stage_count,count,stage; //関数制御用変数 GLOBAL int se_flag[SE_MAX]; //サウンドフラグ //設定用変数 GLOBAL int stage_title_count[STAGE_NUM]; 〜略〜 GLOBAL stage_title_t stage_title;//ステージタイトル ---- function.h に以下を追加 ---- //calc.cpp GLOBAL void calc_main(); ---- struct.h に以下を追加 ---- //ゲームステージタイトル typedef struct{ //フラグ、画像ハンドル、カウンタ、輝度、出現カウント int flag,img,cnt,brt,appear_cnt; }stage_title_t;
そしてまず、初期化しておきましょう。
今回は「stage_title_count」という変数を上で用意しましたね。
これは、何カウント目でタイトルを表示させ始めるかというカウントが入ります。
1ステージ目で600カウント目で表示させ始めたければ
stage_title_count[0]に600を代入すればいいわけです。
ゲームカウントがこのカウントになったら自動的に登録されます。
stage_title.appear_cntに、そのステージでの出現カウント数をセットします。
それをやっていきましょう。
---- first_ini.cpp に以下追加 ---- stage=0; stage_title_count[0]=200; ---- ini.cpp に以下(赤字部)追加 ---- //ゲームの初期化 void ini(){ stage_count=1; memset(&ch,0,sizeof(ch_t)); memset(enemy,0,sizeof(enemy_t)*ENEMY_MAX); memset(lazer,0,sizeof(lazer_t)*LAZER_MAX); memset(enemy_order,0,sizeof(enemy_order_t)*ENEMY_ORDER_MAX); memset(shot,0,sizeof(shot_t)*SHOT_MAX); memset(cshot,0,sizeof(cshot_t)*CSHOT_MAX); memset(effect,0,sizeof(effect_t)*EFFECT_MAX); memset(del_effect,0,sizeof(del_effect_t)*DEL_EFFECT_MAX); memset(&bom,0,sizeof(bom_t)); memset(&bright_set,0,sizeof(bright_set_t)); memset(&dn,0,sizeof(dn_t)); memset(&boss,0,sizeof(boss_t)); memset(child,0,sizeof(child_t)*CHILD_MAX); memset(&stage_title,0,sizeof(stage_title_t)); ch.x=FMX/2; ch.y=FMY*3/4; ch.power=500; stage_title.appear_cnt=stage_title_count[stage]; /*弾幕それぞれの設定。後々きちんと設定しましょう。*/ boss.appear_count[0]=2000;//中ボスが出現する時刻 for(int i=0;i<DANMAKU_MAX;i++){//弾幕それぞれのHP boss.set_hp[i]=10000; boss.hp_max=10000; } for(int i=0;i<DANMAKU_MAX;i++)//弾幕それぞれの背景の種類 boss.back_knd[i]=1; /*ここまで*/ bright_set.brt=255;//初期輝度は最大 }
calc.cppにこの処理を書いてみましょう。
出現カウントと一致したら、登録。
そこから段々明るくする処理をし、しばらくして段々暗くなる処理をし、時間が来たら終わります。
今回、この画像を使うのはこの瞬間だけなので、ゲーム全体として画像データをメモリ上に保持するのは勿体無いですね。
ですから、登録された瞬間ロードし、必要なくなったら解放してしまいましょう。
---- calc.cpp に以下を追加 ---- #include "../include/GV.h" //タイトル処理 void calc_stage_title(){ if(stage_title.appear_cnt==stage_count){//今が表示開始時なら stage_title.flag=1; stage_title.img = LoadGraph("../dat/img/board/subject0.png"); } if(stage_title.flag==0)return; if(stage_title.cnt<128)//最初の128の間段々明るく stage_title.brt+=2; if(stage_title.cnt>128+128)//段々暗く stage_title.brt-=2; if(stage_title.cnt>128+128+128){//終り stage_title.cnt=0; stage_title.brt=0; stage_title.flag=0; DeleteGraph(stage_title.img);//画像解放 return ; } stage_title.cnt++; //強制終了した時の画像解放処理が必要 } void calc_main(){ calc_stage_title();//タイトル処理 } ---- graph.cpp に以下(赤字部)を追加 ---- //タイトルの表示 void graph_stage_title(){ if(stage_title.flag>0){ SetDrawBlendMode( DX_BLENDMODE_ALPHA, stage_title.brt ); DrawGraph(120+FX+dn.x,10+FY+dn.y,stage_title.img,TRUE); SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 ); } } 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_child(); 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_lazer();//レーザーの描画 graph_bullet();//弾の描画 if(bright_set.brt!=255)SetDrawBright(255,255,255); graph_effect(1);//ボムのエフェクト graph_effect(2);//ボム線のエフェクト graph_effect(3);//ボムキャラのエフェクト graph_stage_title();//タイトルの表示 graph_board();//ボードの描画 graph_develop(); } ---- main.cppのメイン関数内の以下(赤字部)変更 ---- int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){ ChangeWindowMode(TRUE);//ウィンドウモード if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化 while(ProcessLoop()==0){//メインループ music_ini(); switch(func_state){ case 0://初回のみ入る処理 load(); //データロード first_ini();//初回の初期化 func_state=99; break; case 99://STGを始める前に行う初期化 ini(); load_story(); func_state=100; break; case 100://通常処理 calc_ch(); //キャラクタ計算 ch_move(); //キャラクタの移動制御 cshot_main();//自機ショットメイン enemy_main();//敵処理メイン boss_shot_main(); shot_main(); //ショットメイン out_main(); //当たり計算 effect_main();//エフェクトメイン calc_main();//ゲームタイトル表示計算 graph_main();//描画メイン if(boss.flag==0) stage_count++; break; default: printfDx("不明なfunc_state\n"); break; } music_play(); if(CheckStateKey(KEY_INPUT_ESCAPE)==1)break;//エスケープが入力されたらブレイク ScreenFlip();//裏画面反映 count++; } DxLib_End();//DXライブラリ終了処理 return 0; } ---- load.cppの以下(赤字部)変更 ---- void load_story(){ int n,num,i,fp; char fname[32]={"../dat/csv/38章/storyH0.csv"}; int input[64]; char inputc[64];
実行結果
何気にエクセルデータも変更してありますが、ステージ作りは後でやるので、
今は適当に見ておいて下さい。ステージの最初っぽくなるようにちょっといじっただけです。
- Remical Soft -