第四十五章 实现道中和最终Boss吧

>>点此回到教程目录

一直到上一章为止Boss都还在一直放着弹幕不会停止,反复地多次重复弹幕的话就会出现指针错误。

本章中我们将要让Boss的弹幕停止,同时也要做出道中Boss和最终Boss。

虽然说是道中Boss和最终Boss,但是它们都是敌人,在龙神录和东方中,Boss在道中出现一次被干掉跑掉后,在最后会完整地再出现一次。我们试着实现这个吧。

在boss结构体中追加danmaku_num[2]。

这是设定道中Boss发射多少个弹幕、最终Boss发射多少个弹幕的变量。

在接下来的弹幕临近的时候,如果当前的弹幕数和这个数字一样的话那么就让Boss被销毁。

另外本章中,由于进行画面咚!地摇动的dn处理全部在一个文件中实现了,因此请配合那里一起阅读。

dn的登录需要使用enter_dn。

—-在 struct.h 中进行以下部分变更 —-

//Boss的信息
typedef struct{
    //flag、计数器、种类、待机时间、状态、直至弹幕结束的计数器、背后的羽衣、显示flag
        int flag,cnt,knd,wtime,state,endtime,hagoromo,graph_flag;
        //HP,最大HP
        int hp,hp_max;
        //出现计数、各个弹幕的的HP、背景的种类、道中Boss-最终Boss弹幕数(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为SC用
};
/***修改请注意***/

//游戏的初始化
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;//初始化power(41)
        ch.num=5;//初始化残机数(41)

        stage_title.appear_cnt=stage_title_count[stage];

    /*弹幕的各种设定。留在后面好好设定吧。*/

        /***修改请注意***/
        boss.appear_count[0]=800;//道中Boss出现的时刻(42)
        boss.appear_count[1]=1100;//最终Boss出现的时刻(44)

        boss.danmaku_num[0]=1;//道中Boos要放的弹幕个数
        boss.danmaku_num[1]=3;//最终Boos要放的弹幕个数

        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://Boom的特效
                    //速度計算
                    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里面传入Boss当前发射哪个种类的弹幕。

如果这个值和ini函数中保存了的boss.danmaku_num的值一样的话就销毁Boss。(译者注:前提是boss.knd的这个弹幕已经放完)

在销毁的时候发出咚梆!的声音同时加以特效吧。

boss.danmaku_num[0]是道中Boss的终止值而[1]是最终Boss的终止值。

由于编号从0开始的,那么想要让道中Boss显示在func.h的void (*boss_shot_bullet[DANMAKU_MAX])()中指定的到第2个弹幕为止的这些弹幕的话,也即是说我们要让道中Boss显示到编号为1为止,那么我们就指定1。(译者注:这里我多说两句,由于全局只有一个保存弹幕函数指针的全局变量boss_shot_bullet,因此对于一面的所有Boss而言,它们的knd的变化事实上应该是这个样子的:第1个Boss:0~x1,第2个Boss:x1+1~x2,第3个Boss:x2+1~x3……最终Boss:xk~n-1,这里的n是boss_shot_bullet中这一面所有的弹幕的数量,这里通过对boss.knd的累加来实现弹幕的变换——这是非面向对象化的方法)

—-在 boss_shot.cpp 中进行以下变更 —-

//设置Boss
void enter_boss(int num){
        if(num==0){//道中Boss开始的时候
                memset(enemy,0,sizeof(enemy_t)*ENEMY_MAX);//销毁杂兵
                memset(shot,0,sizeof(shot_t)*SHOT_MAX);//销毁弹幕
                boss.x=FMX/2;//Boss的初始坐标
                boss.y=-30;

                if(stage_count==boss.appear_count[0])//最开始的话
                        boss.knd=-1;//弹幕的种类

        }
        boss.phy.flag=1;
        boss.flag=1;
        boss.hagoromo=0;//是否扇形扩展开的flag
        boss.endtime=99*60;//剩余时间
        boss.state=1;//变为待机中状态
        boss.cnt=0;
        boss.graph_flag=0;//恢复绘制flag
        boss.knd++;
        boss.wtime=0;//初始化待机时间
        input_phy(60);//60次计数内物理计算下回到固定位置
}

//Boss的弹幕main
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)//如果Boss没有登录的话直接返回
                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));//初始化Boss的弹幕信息
                memset(&lazer,0,sizeof(lazer_t)*LAZER_MAX);//初始化Boss的激光信息
                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;//Boss击毁声效
                        return ;
                }
                else
                        enter_boss(1);//登录下一个弹幕
                /***修改请注意***/

        }
        if(boss.state==1){//弹幕之间的待机时间
                waitandenter();
        }
        if(boss.state==2){//如果在弹幕中的话
                boss_shot_bullet[boss.knd]();//开始弹幕
                boss_shot_calc();//弹幕计算
        }
        boss.cnt++;
}

运行结果


>>点此回到教程目录

results matching ""

    No results matching ""