第二十八章 制作弹幕——“完美冻结”

>>点此回到教程目录

弹幕名:完美冻结(パーフェクトフリーズ)(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。

>>点此回到教程目录

results matching ""

    No results matching ""