>>点此回到教程目录
弹幕名:完美冻结(パーフェクトフリーズ)(Perfect Freeze)
制作难易度:★★ (2/10)
运行结果
第二回弹幕制作讲座我们将制作弹幕——“完美冻结”。
本章中我们需要考虑的关键是随机数的生成。
请注意
rang(PI2/20)+PI2/10*t
这个生成随机角度的地方。
如果是生成360°的随机方向的话调用rang(PI)就可以了呢。
由于rang(n)函数返回的是-n⇐θ⇐n的角度,那么使用这个函数我们应该就可以生成全方向的随机方向了。
但是,随机数是个可怕的东西,很有可能某个时候某个地点会出现聚集现象,也即无法产生“概率均等的随机数”。
于是,我们干脆来生成“假定随机数”吧。
现在,我们希望让0~99分别对应全方向的角度,然后生成0~99之间的随机数。
这个时候
第1帧中返回0~9之间的随机数 第2帧中返回10~19之间的随机数 第3帧中返回20~29之间的随机数 第4帧中返回30~39之间的随机数…… 如此继续下去,一直到99,然后又回到0重新开始,进入这样一个循环。
这么一来,在10帧内必定可以往各不相同的10个方向发射。
即便是随机方向,由于10帧中在10个区分范围内进行随机方向的前进,因此不可能偶尔出现0~9中聚集现象。
这么一来,1帧1帧地区分角度的话就会循环起来,事实上虽然是在循环,但是由于是1/6秒循环一周,实际上看上去也就根本没有循环。完美冻结的随机发射如果采取这样的方式,您还会在意循环么?(译者注:这里我复述一下作者的意思。其实作者就是想说明10个随机的方向虽然是分别产生的,但是由于分别产生于10帧中,这个时间相当短,根本可以认为就是同时产生的,因此不用在意0~9这个变化过程,显示出来的时候看起来也就是同时往10个方向前进了。)
这么一来,我们就可以生成假想的随机数了。
由于这对于高质量的弹幕的制作而言相当重要,因此我们要防止在任何地方产生聚集性的随机数,深思熟虑过后再生成之。
完美冻结的算法中进行了如下流程:
分别向所有方向散射出子弹 冻结!!停止子弹的运动然后变白色。 连续向以自机所在位置为基准的八个方向 停止的子弹朝着全方向开始移动。
分别向所有方向散射出子弹
冻结!!停止子弹的运动然后变白色。
连续向以自机所在位置为基准的八个方向
停止的子弹朝着全方向开始移动。
—-在 boss_shotH.cpp 中进行以下追加 —-
//完美冻结 void boss_shot_bulletH002(){ #define TM002 650 int i,k,t=boss_shot.cnt%TM002; double angle; if(t==0 || t==210){ //在40<x<FMX-40 50<y<150的范围内80次计数中移动到100单位远的地方 move_boss_pos(40,50,FMX-40,150,100, 80); } //最开始的随机发射 if(t<180){ for(i=0;i<2;i++){//1次计数发射2次 if((k=search_boss_shot())!=-1){ boss_shot.bullet[k].col = GetRand(6);//随机像是7种颜色 boss_shot.bullet[k].x = boss.x;//发射初始坐标为Boss的坐标 boss_shot.bullet[k].y = boss.y; boss_shot.bullet[k].knd = 7;//子弹的种类 boss_shot.bullet[k].angle = rang(PI2/20)+PI2/10*t; boss_shot.bullet[k].flag = 1; boss_shot.bullet[k].cnt = 0; boss_shot.bullet[k].spd = 3.2+rang(2.1); boss_shot.bullet[k].state = 0;//子弹的状态 boss_shot.bullet[k].kaiten= 1;//决定子弹是否旋转的flag } } if(t%10==0) se_flag[0]=1; } //根据自机的位置往8个方向发射 if(210<t && t<270 && t%3==0){ angle=bossatan2(); for(i=0;i<8;i++){ if((k=search_boss_shot())!=-1){ boss_shot.bullet[k].col = 0; boss_shot.bullet[k].x = boss.x; boss_shot.bullet[k].y = boss.y; boss_shot.bullet[k].knd = 7; //以自机与Boos所成的夹角为基准往8个方向发射 boss_shot.bullet[k].angle = angle-PI/2*0.8+PI*0.8/7*i+rang(PI/180); boss_shot.bullet[k].flag = 1; boss_shot.bullet[k].cnt = 0; boss_shot.bullet[k].spd = 3.0+rang(0.3); boss_shot.bullet[k].state = 2; boss_shot.bullet[k].kaiten= 1; } } if(t%10==0) se_flag[0]=1; } for(i=0;i<BOSS_BULLET_MAX;i++){ if(boss_shot.bullet[i].flag>0){ //t在190的时候将所有的子弹都停止下来,然后变白色,重置计数器 if(boss_shot.bullet[i].state==0){ if(t==190){ boss_shot.bullet[i].kaiten=0;//停止子弹的旋转 boss_shot.bullet[i].spd =0; boss_shot.bullet[i].col =9; boss_shot.bullet[i].cnt =0; boss_shot.bullet[i].state =1;//将状态设置为1 } } //开始往随机方向移动 if(boss_shot.bullet[i].state==1){ if(boss_shot.bullet[i].cnt==200){ boss_shot.bullet[i].angle=rang(PI);//全方向随机 boss_shot.bullet[i].kaiten=1;//设置旋转flag为有效 } if(boss_shot.bullet[i].cnt>200) boss_shot.bullet[i].spd+=0.01;//逐渐加速 } } } }
也请确认变更了的func.h。