今回は敵を色々と移動させてみます。また、各段階でダメージの大きさを変更したりもしてみましょう。
Concentration01
で力を集中する効果を表示できます。SetInvincibility
で一定時間だけ敵を無敵にできます。SetDamageRate
でダメージレートを変更できます。それではいってみましょう。
では、今回は敵を移動させてみましょう。悟入幻想では、ボスは次のように移動します。
1 は既に standBy
で行いましたね。今回は 2 以降を作りたいと思います。
これら全ての動作を TMain
に直接書くこともできます。しかし、standBy
でやったのと同様に、段階ごとにサブルーチンに分けた方が流れが把握しやすくなります。1つの関数、サブルーチン、マイクロスレッドは、あまり長くならないようにするのが、綺麗なプログラムを書くコツです。どんなに長くても、100 行は超えないよう心がけましょう。綺麗なプログラムは、バグを未然に防ぎやすく、また、バグを発見しやすく、修正しやすいです。一方、複雑で汚いプログラムは、バグを生みやすく、バグを発見しにくく、修正しにくいのです。プログラムを綺麗に書くというのは、美的感覚を満足させるために行うのではなく、バグを抑えるために行うのです。
では、1つずつ作っていきましょう。先ずは 2 の浮揚するサブルーチン levitate
です。
// 浮揚 sub levitate { let wLev = 60; setGraphicStop; SetMovePosition02(xIni, yIni + 10, wLev); wait(wLev); SetMovePosition02(xIni, yIni, wLev); wait(wLev); }
先ず、浮揚時はキャラのグラフィックを停止時のグラフィックにします。そのため、サブルーチン setGraphicStop
を呼んでいます。これは前回作ったサブルーチンです(この講座では自作の関数やサブルーチンは小文字で始めているので、東方弾幕風が提供する関数かそうでないかが分かるようになっています)。
あとは 60×2 フレームかけて、10 ピクセルだけ上下します。これは特に問題ないですね。
次は、3 の力を溜めるサブルーチン concentration
です。力を溜める効果を表示するには、Concentration01
という関数を使います。
// 力を集中 sub concentration { let wConc = 60; setGraphicPose; Concentration01(wConc); wait(wConc); }
力を溜めるときは、特殊なポーズをとることにします。そのため、サブルーチン setGraphicPose
を呼んでいます。そして、力を溜めるために Concentration01
を呼んでいます。これは、指定したフレーム数の間、力を溜める効果を表示する関数です。自動的に yield
してくれるわけではないので、wait
を自前で呼ぶ必要があります。これで力を溜める処理は終了です。
次は、4 の左端へ移動するサブルーチン slash
です。実際には一番下に剣戟の跡が残って、そこに当たると死ぬわけですが、この部分は今回実装しません。
// 横薙ぎ sub slash { let wMove = 10; let wStop = 60 - wMove; SetMovePosition02(xSlash, ySlash, wMove); setGraphicMove; wait(wMove); wait(wStop); }
単に、左端へ移動し、その後停止しているだけです。座標 xSlash
, ySlash
は別のところで定義しておきます。
次は、5 の左上へ移動するサブルーチン ready
です。
// 定位置へ移動して、攻撃開始 sub ready { let wMove = 120; let wStop = 60; SetMovePosition02(xStart, yStart, wMove); setGraphicMove; wait(wMove); setGraphicStop; wait(wStop); }
単に、左上へ移動し、その後停止しているだけです。slash
では停止時にも移動時とグラフィック同じでしたが、ready
では停止時のグラフィックに変更しています。
最後に、6 の移動するサブルーチン move
を作ります。
// 移動 sub move { let wMove = 60; moveToPlayer(rand(40, 80), rand(-40, 40), wMove, GetClipMinX + 48, GetClipMinY + 32, GetClipMaxX - 48, GetClipMinY + 128); setGraphicMove; wait(wMove); }
前と可動範囲が変わってますが、それ以外は特に変わっていませんね。moveToPlayer
の定義は前と同じです。
では、これらのサブルーチンを TMain
で呼んでみましょう。
// メインタスク task TMain { yield; standBy; levitate; concentration; slash; ready; loop { move; shot; } }
すっきりしてますね。ここで、shot
は攻撃のためのサブルーチンですが、今のところは一時停止するだけにしておきましょう。
// way 弾を発射 sub shot { let wStop = 60; setGraphicPose; wait(wStop); }
以上をまとめたプログラムをここに置いておきます。実際に実行してみて、期待通り動いていることを確かめてみてください。
さて、実行してみて気付いたことはありませんか? ショットを打たないでテストしていると気付かないかもしれませんが、ちょっとショットを当ててみてください。最初の下側で動いているところでも、ゴンゴンとライフが減っていくことが分かると思います。
こういう、準備段階の動作中でもライフがどんどん削れてしまうのは問題です。実際、妖々夢においては攻撃が始まるまでは守備力が非常に高く、あまりライフが減らないようになっています。
そこで、ここでも同様にライフがあまり減らないようにしてみましょう。具体的には、
としてみましょう。ただ、このように守備力を変化させるにはどのようにすればいいのでしょうか?
先ずは、無敵状態にする方法です。無敵状態にするには、SetInvincibility
という関数を使います。Invincibility というのは無敵という意味で、Invincible(インビンシブル;無敵の)の名詞形です。ファミコン世代の人には、ファイナル○ァンタジー3で出てくる巨大飛空艇でおなじみの単語ですね。SetInvincibility
には、無敵にする時間を指定します。
// 初期位置へ移動 sub standBy { let wIni = 120; SetMovePosition02(xIni, yIni, wIni); setGraphicMove; SetInvincibility(wIni); wait(wIni); }
次は、守備力を変化させる方法です。守備力を変化させるにするには、SetDamageRate
という関数を使います。これには、ショットに対するダメージレートと、ボムに対するダメージレートを指定します。ダメージレートは、ダメージを通常の何 % にするかを表します。
@Initialize { CutIn(YOUMU, name, "", 0, 0, 0, 0); SetLife(2000); SetTimer(66); SetScore(4000000); SetDamageRate(5, 5); LoadGraphic(imgBoss); SetTexture(imgBoss); TMain; } // 定位置へ移動して、攻撃開始 sub ready { let wMove = 120; let wStop = 60; SetMovePosition02(xStart, yStart, wMove); setGraphicMove; wait(wMove); setGraphicStop; wait(wStop); SetDamageRate(40, 40); }
100 で 100% になるわけですが、別に最終的に 100% にする必要はありません。最終的にダメージレートが 100% になるようにライフを調整するか、それともライフを変えずにダメージレートを調整するかは、状況次第です。後に出てくる Plural のスクリプトを作る場合には、ライフを固定してダメージレートを調整する場合が多くなると思います。ここでは、Single のスクリプトですが、気にせずライフを固定して調整しました。
また、ダメージレートを 0% にすることで無敵にすることもできます。SetInvincibility
を使うか SetDamageRate
を使うかは、状況と好み次第でしょう。
以上をまとめたプログラムをここに置いておきます。実際に実行してみて、ダメージレートが変化してることを確認してみてください。
Concentration01
で力を集中する効果を表示できます。SetInvincibility
で一定時間だけ敵を無敵にできます。SetDamageRate
でダメージレートを変更できます。次回はレーザーを配置してみましょう。