第四十五章 实现道中和最终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++;
}
运行结果