45 章
前回まではボスの弾幕は終わりが無く、何度も弾幕を次へ繰り返していくとポインタエラーになっていました。
今回はちゃんと終わりを作り、中ボス、ラスボスを作りましょう。
中ボスラスボスといっても、同じ敵ですが、龍神録や東方は中間に1度出てきて、やられて引っ込んだあと、
ラストで本格的にもう一度出現します。それを実装してみましょう。
boss構造体にdanmaku_num[2]を追加します。
中ボスでいくつ弾幕を出し、ラスボスでいくつ弾幕を出すかセットするための変数です。
次の弾幕へさしかかるとき、現在の弾幕数がこの数字と一致したら倒すということにします。
また今回は、画面をドン!と揺らすdn処理を一つのファイルに纏めましたので、そちらもあわせてご覧下さい。
dnの登録にはenter_dnを使用します。
---- struct.h の以下の部分を変更 ---- //ボスの情報 typedef struct{ //フラグ、カウンタ、種類、待機時間、状態、弾幕終了までのカウンタ、後ろの羽衣、表示フラグ int flag,cnt,knd,wtime,state,endtime,hagoromo,graph_flag; //HP,最大HP int hp,hp_max; //出現カウンタ数、各弾幕のHP、背景の種類、中ボス-ラスボスの弾幕数(45) int appear_count[2],set_hp[DANMAKU_MAX],back_knd[DANMAKU_MAX],danmaku_num[2]; //座標 double x,y,dx,dy,ang,spd; //物理移動のための変数 phy_t phy; }boss_t; ---- function.h に以下を追加 ---- //dn.cpp GLOBAL void enter_dn(int size,int time); ---- define.h の以下を変更 #define BOSS_POS_Y (FMY/4) ---- func.hの以下を変更 ---- void (*boss_shot_bullet[DANMAKU_MAX])() = { boss_shot_bulletH000, boss_shot_bulletH001, boss_shot_bulletH000, boss_shot_bulletH009, boss_shot_bulletH000, }; ---- ini.cpp の 以下を変更 ---- int back_knd[DANMAKU_MAX]={//背景の種類 0,1,0,1,//0は通常 1はスペル用 }; //ゲームの初期化 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)); memset(item,0,sizeof(item_t)*ITEM_MAX); ch.x=FMX/2; ch.y=FMY*3/4; ch.power=0;//初期パワー(41) ch.num=5;//初期残機数(41) stage_title.appear_cnt=stage_title_count[stage]; /*弾幕それぞれの設定。後々きちんと設定しましょう。*/ boss.appear_count[0]=800;//中ボスが出現する時刻(42) boss.appear_count[1]=1100;//最後ボスが出現する時刻(44) boss.danmaku_num[0]=1;//中ボスが何個目までの弾幕を出すか boss.danmaku_num[1]=3;//最後に出るボスが何個目までの弾幕を出すか for(int i=0;i<DANMAKU_MAX;i++){//弾幕それぞれのHP boss.set_hp[i]=1000; boss.hp_max=1000; } for(int i=0;i<DANMAKU_MAX;i++)//弾幕それぞれの背景の種類 boss.back_knd[i]=back_knd[i]; /*ここまで*/ bright_set.brt=255;//初期輝度は最大 } ---- effect.cpp の先頭に 以下を追加 ---- extern void dn_calc(); ---- effect.cpp の calc_effect()の以下を変更 ---- case 1://ボムのエフェクト //スピード計算 if(effect[i].cnt<60) effect[i].spd-=(0.2+effect[i].cnt*effect[i].cnt/3000.0); if(effect[i].cnt==60){ effect[i].spd=0; se_flag[15]=1; enter_dn(11,20);//(45) } //明るさと大きさ計算 effect[i].r+=0.015; if(effect[i].cnt<51) effect[i].brt+=5; if(effect[i].cnt>=60){ effect[i].r+=0.04; effect[i].brt-=255/30.0; } //カウントアップと消去計算 effect[i].cnt++; if(effect[i].cnt>=90) effect[i].flag=0; break; ---- dn.cpp を新たに追加し、以下を追加 ---- #include "../include/GV.h" void enter_dn(int size, int time){ dn.flag=1; dn.cnt=0; dn.time=time; dn.size=size; } //ドガーンとゆれる画面の処理 void dn_calc(){ if(dn.flag==1){ dn.x=(int)rang(dn.size); dn.y=(int)rang(dn.size); dn.cnt++; if(dn.cnt>dn.time){//指定された時間がたつと終わる dn.flag=0; dn.x=0; dn.y=0; } } }
ボスが今どの種類の弾幕をうっているかはboss.kndに入っています。
これがini関数で格納したboss.danmaku_numと同じだったらボスを消します。
消す時はドガーンを言う音とエフェクトをつけてやりましょう。
boss.danmaku_num[0]は中ボスまで、[1]はラスボスまでです。
番号は0から始まりますから、中ボスでfunc.hの
void (*boss_shot_bullet[DANMAKU_MAX])()
に指定した2つ目までを中ボスで表示したいのなら1番まで中ボスで表示したいので1を指定します。
---- boss_shot.cpp の以下を変更 ---- //ボスをセット void enter_boss(int num){ if(num==0){//中ボス開始時の時は memset(enemy,0,sizeof(enemy_t)*ENEMY_MAX);//雑魚敵を消す memset(shot,0,sizeof(shot_t)*SHOT_MAX);//弾幕を消す boss.x=FMX/2;//ボスの初期座標 boss.y=-30; if(stage_count==boss.appear_count[0])//最初なら boss.knd=-1;//弾幕の種類 } boss.phy.flag=1; boss.flag=1; boss.hagoromo=0;//扇を広げるかどうかのフラグ boss.endtime=99*60;//残り時間 boss.state=1;//待機中状態に boss.cnt=0; boss.graph_flag=0;//描画フラグを戻す boss.knd++; boss.wtime=0;//待機時間を初期化 input_phy(60);//60カウントかけて物理的計算で定位置に戻す } //ボスの弾幕メイン void boss_shot_main(){ if((stage_count==boss.appear_count[0] || stage_count==boss.appear_count[1]) && boss.flag==0){//開始時間なら enter_boss(0);//開始 } if(boss.flag==0)//ボスが登録されて無ければ戻る return; calc_boss(); if(boss.phy.flag==1)//物理演算移動オンなら calc_phy();//物理計算を if(boss.state==2 && (boss.hp<=0 || boss.endtime<=0)){//弾幕中で体力が無くなったら se_flag[1]=1;//敵のピチュリ音 se_flag[11]=1; input_phy(30);//30カウントで定位置に戻す memset(&boss_shot,0,sizeof(boss_shot_t));//ボスの弾幕情報を初期化 memset(&lazer,0,sizeof(lazer_t)*LAZER_MAX);//ボスのレーザー情報を初期化 flash.flag=0;//フラッシュを消す if(boss.knd==boss.danmaku_num[0] || boss.knd==boss.danmaku_num[1]){//弾幕をだしきったら boss.flag=0;//消す enter_dn(10,40);//(45)ドガーン処理 se_flag[9]=1;//ボスが死んだ音 return ; } else enter_boss(1);//次の弾幕を登録 } if(boss.state==1){//弾幕間の待機時間 waitandenter(); } if(boss.state==2){//弾幕中なら boss_shot_bullet[boss.knd]();//弾幕関数へ boss_shot_calc();//弾幕計算 } boss.cnt++; }
実行結果
- Remical Soft -