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 -