弾幕名:パーフェクトフリーズ
作製難易度:★★ (2/10)

実行結果




第ニ回弾幕作製講座は「パーフェクトフリーズです。

今回注目すべき点は乱数の生成です。

rang(PI2/20)+PI2/10*t

と書いているランダムな角度の生成箇所に注目して下さい。

360°のランダムな方向の生成ならrang(PI)でいいはずですね。

rang(n)は-n<=θ<=nの角度を返す関数ですから、これで全方向のランダムな方向が作れるはずです。

しかしランダムな数というのは怖いもので、ある時はある場所にばっかりかたまったり、

「均等なランダム」ではないかもしれません。

そこで「想定されたランダム」をここで生成してみましょう。

今、0〜99が全方向の角度に対応しているとし、その値の乱数を出したいとしましょう。

この時は、

・1フレーム目は0〜9の値のどれかをだす

・2フレーム目は10〜19の値のどれかをだす

・3フレーム目は20〜29の値のどれかをだす

・4フレーム目は30〜39の値のどれかをだす・・・・・

そうして99まで来たらまた0〜の値に戻してループしてみます。

すると、10フレームで区分された10方向には必ず発射されます。

ランダムな方向だとしても、10フレーム中に10の区分の範囲でランダムな方向に飛ぶわけであって、

その時たまたま0〜9の中に集中したりはしません。

こうすると、1フレームずつ区分角度が回転するわけですから、

事実上回転していることになりますが、1/6秒で一周するため、見た目にはまわっているように

見えません。パーフェクトフリーズのランダム発射ではこれが使われていますが、

回転が気になるでしょうか?

こうすることで、想定されたランダムな値が出せます。

これは質のよい弾幕を作るうえでは重要ですから、どこかで詰んだりしないように

十分考えられたランダムな数を生成するようにしましょう。

パーフェクトフリーズのアルゴリズムとしては

・全方向ばら撒きショットをうつ

・フリーズ!!弾を止めて白くする

・自機依存された8方向ショットを連続でうつ

・止めていた弾を全方向で動かし始める

という流れになります。


---- 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 の範囲で100離れた位置に80カウントで移動する
        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_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;//弾を回転するかどうかのフラグ
            }
        }
        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;
                //自機とボスとの成す角を基準に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;//回転するフラグを立てる
                }
                if(boss_shot.bullet[i].cnt>200)
                    boss_shot.bullet[i].spd+=0.01;//段々加速
            }
        }
    }
}


変更されているfunc.hも確認しておいて下さい。



- Remical Soft -