敵の出現と移動(1/2)

 敵を出し、移動します。

 1.敵の配列変数を宣言する
 2.敵の移動パターンを定義する
 3.敵の変数に初期値を代入する
 4.敵を出現させる
 5.敵を移動する
 6.敵を描画する
 7.現在位置を少し進める

 1.敵の配列変数を宣言する

 敵は最大10個まで存在できることにします。自機の弾と同様、存在フラグ(enemyf)と座標(enemyx,enemyy)を配列変数として宣言します。あともう一つ、敵用のカウンター(enemycnt)を用意します。これは、敵のアニメーションと、敵の動きのために使います。
    dim enemyf,10
    dim enemyx,10
    dim enemyy,10
    dim enemycnt,10
 これは、「プログラム起動時の初期設定」に入れます。

 2.敵の移動パターンを定義する

「全体の流れ」の所でちょっと、一つ一つの種類について動きをプログラミングしていく場合と、移動パターンをデータ化してしまって、処理は一つですむようにする場合がある旨を書きました。ここでは、簡単にたくさんの敵の種類を作れる、後者の方にしようと思います。
 こんなふうに、左右にふらふらしながら降りてくる敵を作ります。
  敵の動き
 最初、左に8ドット、下に4ドット動かします。2回目は左に6ドット、下に4ドット動かします。3回目は左に4ドット、下に4ドットです。
  敵の動き
 何番目にx方向に何ドット、y方向に何ドット動かすかを配列変数enemvdx(enemy move dxの略)、enemvdyに代入します。
    dim enemvdx,16
    dim enemvdy,16
    enemvdx.0=-8:enemvdy.0=4
    enemvdx.1=-6:enemvdy.1=4
    enemvdx.2=-4:enemvdy.2=4
    enemvdx.3=-2:enemvdy.3=4
    enemvdx.4=0:enemvdy.4=4
    enemvdx.5=2:enemvdy.5=4
    enemvdx.6=4:enemvdy.6=4
    enemvdx.7=6:enemvdy.7=4
    enemvdx.8=8:enemvdy.8=4
    enemvdx.9=6:enemvdy.9=4
    enemvdx.10=4:enemvdy.10=4
    enemvdx.11=2:enemvdy.11=4
    enemvdx.12=0:enemvdy.12=4
    enemvdx.13=-2:enemvdy.13=4
    enemvdx.14=-4:enemvdy.14=4
    enemvdx.15=-6:enemvdy.15=4
 これを順々に敵の座標に足しこんでいくと、ふらふらと動きます。15までいったら、0に戻って繰り返します。  これも、「プログラム起動時の初期設定」に入れます。

 3.敵の変数に初期値を代入する

 「ステージスタート時の初期設定」で、存在フラグに0を代入します。
    repeat 10
        enemyf.cnt=0
    loop
 まだ背景のスクロール処理を作っていないのですが、敵はスクロールに合わせて出していきたいので、自機が今ステージのマップ上のどこにいるのかを表す変数mappnt(map pointの略)を追加します。最初が0で、1ドットスクロールすると1増えることにします。
    mappnt=0

 4.敵を出現させる

   ここでは、64ドットスクロールするたびに2匹ずつ敵を出します。すると、mappntが64の倍数の時に出すことになります。ある数がある数の倍数であるかどうかを調べるのに、便利な演算子があります。
    if mappnt\64=0 {
        敵を出す処理
    }
 "\"はモジュロ演算子というもので、mappntを64で割った余りを求めます。余りが0であるということは、64の倍数だということです。
 敵を出す処理ですが、自機から弾を出す処理と同様、要素0から順に存在フラグを見ていき、空いている(存在フラグが0である)要素に割り当てます。1度に2匹出すので、変数nに今何匹出したかを記憶させることにします。
    n=0
    repeat 10
        if enemyf.cnt=0 {
            敵を1匹出す処理
            n=n+1
            if n=2 { break }
        }
    loop
 空きが2箇所以上あれば2匹出しますし、1箇所しかなければ1匹だけ出しますし、1箇所もなければ1匹も出しません。
 敵を1匹出す処理は、座標を決め、存在フラグを1にし、敵用のカウンターを0にします。
 y座標は0です。x座標は、乱数で決めることにします。乱数というのは、「でたらめな値」です。サイコロをふると1から6までがでたらめに出ますが、それと同じです。
    rnd 値を入れる変数,上限の値
 これが、乱数を得る命令です。0から上限の値よりも1小さい数までのうちのどれかが変数に代入されます。
    randomize
 これは、乱数系列を変える命令です。乱数の出方を変えます。これがないと、プログラムを動かすたびに毎回同じ並びの乱数となります。サイコロを5回ふって、1,4,6,2,5という順に目が出たとすると、次にサイコロを5回ふると、また1,4,6,2,5の順に目が出てしまうということです。この命令はプログラムの最初に入れるといいですが、ここではステージスタート時に毎回乱数系列を変えることにします。
 敵が左右にふらふらしていることも考慮し、画面からはみ出さないよう、32から576までの値のどれかをx座標にすることにします。ただし、2匹横に並べて出すので、下手をすると敵同士が重なってしまいます。敵の幅が32ドットなので、x座標には32の倍数しか設定しないことにすると、部分的に重なったりしません。完全に重なる危険はありますが。
  敵のx座標
    rnd r,18
    enemyx.cnt=(r+1)*32
 1行目で、0から17のうちのどれかをでたらめに(ランダムに、という言い方をします)選んで、rに入れます。2行目で、1を足しますから1〜18となり、32倍しますから、32から576までの32の倍数となります。
 しかし、やはり完全に重なるのは嫌ですね。同じ乱数が2回続けて出たら、2匹のx座標は等しくなってしまいます。そこで、前に出た乱数を変数wに記憶させておいて、それとrの値が違えばそれでよしとし、同じだったら、違う値が出るまでrnd命令をやり直すことにします。
    repeat
        rnd r,18
        if r!w { break }
    loop
    w=r
 wには最初に−1を入れておきます。(1回目のrnd命令で、必ず違う値になるから。)
 repeatに引数を指定しないと、永久にループを繰り返します。(break文で抜け出します。)これは、
    *aaa
        rnd r,18
        if r=w { goto *aaa }
        w=r
 と同じですが、ラベルを追加するのが鬱陶しければ引数のないrepeat文を使うといいです。
 以上より、敵を出す処理は以下のようになります。
    if mappnt\64=0 {
        n=0
        w=-1
        repeat 10
            if enemyf.cnt=0 {
                repeat
                    rnd r,18
                    if r!w { break }
                loop
                w=r
                enemyx.cnt=(r+1)*32
                enemyy.cnt=0
                enemyf.cnt=1
                enemycnt.cnt=0
                n=n+1
                if n=2 { break }
            }
        loop
    }
 なお、"if r!w { break }"の方のbreak文は、あくまでも内側のrepeat〜loopから抜けるのであって、外側のrepeat〜loopからは抜け出しません。


[目次へ][前へ][次へ] inserted by FC2 system