複雑な罠の作り方 状態遷移の利用
今回は、アイワナにおける複雑な罠の作り方を解説していきます。
使用ソフトはGame Maker 8.0か8.1を想定しています。
通常、針や林檎が飛ぶだけの単純な罠を作る際は、下のようなエンジン付属のfreetriggerを使用します。
しかし、トリガーは物を直線的に飛ばす機能しか持っていないため複雑な罠を作るにはあまり向いていません。
そこで、トリガーを使わずに複雑な罠を作る方法を解説します。大まかには、更新用のオブジェクトを1つ用意し、状態を変数で管理する流れになります。
今回は、下のマップ上で以下のような罠を実装します。
プレイヤーが赤い領域に触れたとき、針を速度10で左方向に飛ばす
→針が左の壁に触れたら速度10で右に戻る
→針が右の壁に触れたら停止する
最初に、罠の制御を行うためのオブジェクトを作成します。スプライトは不要です。名前はupdateとしました。
罠で動かす予定の針を、上で作成したupdateオブジェクトから参照できるようにします。マップ上でCtrlキーを押しながら針を右クリックし、Creation Codeを開きます。
開いたら、update.o = id;と書きます。
「updateオブジェクトのoという変数に自身を代入する」という意味になります。
これで針がupdateオブジェクト内で使えるようになりました。
続いて、罠の更新処理を作成していきます。
まず、作りたい罠にいくつの状態があるかを考えます。今回の例では
針を動かす前 → 針が左に移動中 → 針が右に移動中 → 針が止まった後
と4段階があります。
図で表すと以下のようになります。
続いて、各状態から次の状態に遷移する条件を考えます。
・状態1「針を動かす前」から状態2「針が左に動いている状態」に遷移する条件は「playerが枠内に触れる」ことです。
・状態2「針が左に動いている状態」から状態3「針が右に動いてる状態」に遷移する条件は「針が壁に触れる」ことです。
・状態3「針が右に動いている状態」から状態4「針が止まった状態」に遷移する条件は「針が壁に触れる」ことです。
各状態と遷移条件を図で表すと以下のようになります。
switch文を使って擬似的なコードにします。各状態ではあるアクションを毎フレーム実行し続け、抜ける条件に当てはまると次の状態に移ります。ブロックの最後にはbreakを忘れないようにしましょう。書かないとそれ以下に書いたブロックが全て実行されてしまいます。
ここから実際のコードにしていきます。
先ほど作成したupdateオブジェクトのCreateイベントにstate = 1;と書きます。
Createイベントはインスタンスの生成時に実行されるイベントです。
stateは状態を管理する変数で、最初の状態番号である1で初期化します。
stepイベントにメインとなる罠の更新を記述します。
stepイベントはインスタンスが存在する限り毎フレーム実行されるイベントです。
完成のコードは次のようになります。
状態1は針が動く前なので動作はありません。
playerが四角形領域に触れたときstateを2にします。
if(collision_rectangle(352, 448, 448, 576, player, false, true))でplayerが左上(352, 448)、右下(448, 576)の四角形領域に触れたかどうかを判定します。
第6引数のfalseは当たり判定を正確にするかどうか、第7引数のtrueは実行主体のインスタンスを衝突対象から除外するかどうかです。今回はあまり関係ありません。
状態2では針を毎フレーム10ドット左に動かし続け、針が壁に触れたときstateを3にします。
place_free(x, y)はコードを実行しているインスタンスがブロックなどのsolidオブジェクトと衝突して"いないか"判定する関数です。
with(o){}の中ではコード実行の主体が針oとなるため、with(o){if(!place_free(x, y)){ }}で針がブロックに触れたかどうか判定できます。
衝突して"いるか"判定したいので!place_free(x, y)で真偽を反転します。
other.stateで、with文の外側にあるupdateオブジェクトが持っている変数stateを参照しています。
状態3では針を毎フレーム10ドット右に動かし続け、状態2と同様の判定で針が壁に触れたときstateを4にします。
状態4は終了状態なので動作も抜ける条件もありません。
これで罠の基礎は完成しました。
ですが、針が飛ぶときに効果音も流したいです。
これまでの動作はstateがある値の間、毎フレーム何かを実行するものでした。
それとは別に、状態が遷移する瞬間に一度だけ実行する動作というものも考えることができます。
効果音を流すのは針が動き出すときと針が向きを変えるときがいいでしょう。
よって状態が2、3に遷移するときに効果音を再生します。
ついでに針を動かす方法も変えてみます。
Game Makerの仕様上、毎フレーム座標をずらさなくても一度hspeedを与えれば後は自動的に動きます。
針が速度を変えるとき、つまり状態が2、3、4に遷移するときに針のhspeedを変更します。
図で表すと以下のようになります。
コードは以下のようになります。
赤枠が追加した部分、コメントアウトが削除した部分です。
マップに戻り、updateオブジェクトを1つ置けば罠は完成です。
ちなみに解説のコードはGame Maker搭載のアラームイベントを使って書くことも可能です。コードだけ示しておきます。
衝突判定の都合上、place_free(x, y)はplace_free(x+hspeed, y)にしました。
以上で解説を終わります。罠が複雑になっても状態数を増やすことで対応することができます。