この番外編記事を書く気になった発端は、MMF2 のチャットで某 ●SD さんがMMF2 関する新しい HP ( http://kamexmmf.com/index.html )を見つけて教えてくれたことに由来します。
ここの「5. 自機や敵をレーダー表示する ( http://kamexmmf.com/n5/5.html )」というサンプルを見ていたら、ふと自分で作ってみたくなったので作ってみた。その時単なる思いつきでカウンタもオブジェクトの数に合わせて作り動作を同期させるように組んだのだが…。
気楽に考えていたがカウンターオブジェクトはもともとちょっとやっかいだった。
そういえばクアッドを作った時にもカウンタには少々困ったんだけど、カウンターはオブジェクト自体が独自の数値型変数を持たないのである。
例えばカウンタ・オブジェクトをフレーム中で複数コピーした場合、そのカウンターオブジェクトに対して通し番号を振りたくても MMF2 における黄金パターンが利用できないのだ。そんな理由でとりあえずまっさきにできたのはカウンタを使わない簡単なミニマップ動作バージョンであった。
MMF2 における黄金パターンって?
これを読む人はすでにご存知の通り、アクティブオブジェクトなら「数値型変数」と「文字列型変数」を各オブジェクトが保持できる機能がある。
各オブジェクトが独自に変数を持てるので、MMF2 標準のループ処理である「高速ループ」と組み合わせればオブジェクトが 100 個であろうと 200 個であろうと条件に合った任意のオブジェクトだけを抽出し命令を実行させることができる。
いわゆる MMF2 の黄金パターンというのは…
- 「通し番号(アクションループ)」 + 「高速ループ」 + 「ループインデックス」
という方法だ。
通し番号を振れないオブジェクトに通し番号を振りたい?
この解決策を出す場合、まず ForEach を使うのが一番楽だし SWF でも出力できるコレだ!………と思ったのだが「 ForEach オブジェクト」は日本語版 MMF2 ではインストールできない。
その時、日本語版なんかもうどうでもいいかと一瞬思ったのだが、一応もう少し頑張って別の方法を考えた…というより考えてもらった。
そこで AS● さんが持ってきた解決法は「 ValueAdd 」というエクステンションの利用。
これはエクステンションの中に独自の変数を持てないものがあっても、それらが変数を持てるようにしてくれるという便利アイテムだ。 MMF2 はこの辺がさすがドラえもんチックな素敵な4次元ポケットである。
程無くしてドラえもん、…じゃなくて A●D さんが ValueAdd を使って黄金パターンでカウンタに通し番号を振ることができたらしい。日本語版で PC 用ビルドならこれでいけるんじゃないかなってことで一件落着。じゃあ次に ForEach を使った方法を自分で作ってみた。This is it!(マイケルジャクソン風に)。
おい、バグってんぞについては SWF の ForEach か MMF2 のエクスポータどちらかのバグなのでボクは知らんぷりをするんやな。ネット・コンテンツにおける荒野の掟は諸行無常、色即是空焼肉定食、つまり非情なんやな。PC ではちゃんと動作確認して動いてたんやな。
サンプル( 高速ループと ForEach 両方入り ):mmf2_loop_samples
なぜ ForEach なのか
ForEach は ValueAdd と同じことをしているのではない。
しかしなぜ ForEach なら変数を持たないオブジェクトにも簡単に通し番号を振れるのか、あるいは通し番号無しでも各インスタンスを区別して命令が出せるのか、これについて。
ForEach はオブジェクト・インスタンス(あるいはグループ)に対するループ処理を行うことができる拡張機能なんだ。そして仕様としてそれに特化していると言っても良い。ForEach ではオブジェクト数でループ処理する際に、on loop for Object という機能があるのだ。
「拡張された For 」と言われてもピンとこないかもしれないが、MMF2 では ForEach の役割として「オブジェクトを要素にしたループを回す」という点がポイントになる。そんなもん高速ループだってできる、高速ループをオブジェクト数のカウントしてその数で回せばいいんだろ?てな話だが、詳しく見ていくと原理が異なる。
ForEach の旨味成分
高速ループを使った場合を考えてみよう。
まずアクティブオブジェクトの変数に通し番号を振って、高速ループをオブジェクト数をカウントしてその数でループ開始、ループインデックスとアクティブオブジェクトの変数が一致したら~、というのが従来の MMF2 における黄金パターン。
一方で ForEach が使えるならまず変数に固体識別用の通し番号を振らなくとも良い。ForEach ならループ数もオブジェクトを指定するだけで勝手にループを回してくれる。そして実際にループが始まったら、オブジェクトの持つ固定値で一つ一つ指示を出すのと同じ効果が得られる。つまりこの時点で通し番号も振れる。
ややこしい??ちょっと整理しよう。
高速ループの場合
- :オブジェクトのもつ変数にまず通し番号を振る
- :オブジェクトの数を数える
- :数えたオブジェクト数で高速ループを登録し開始する
- :ループを回しながら一個ずつ条件を判断する(ループインデックスと変数の値比較)
- :条件が一致したらアクション
ForEach の場合
- :オブジェクトを指定して高速ループを登録し開始する
- :ループを回しながら(ループインデックスと変数の値比較)
- :条件が一致したらアクション
その他まとめ
- オブジェクト削除のコツ
二重衝突判定処理を考える
オブジェクトの破壊はすぐに実行されない
衝突を複数処理しようとするよりもひとつに絞った方が対応は楽です。つまり二つ以上コリジョンを検出しても消すのはどれかひとつにする。複数を一括して消す場合はその都度正確にコリジョンを検出して何個同時に消すのかその数をはっきりさせなければなりません。コリジョンの同時検出には Select Object などが便利です。今回は SWF で出力したかったので Select Object は利用せず、衝突判定も強制的に一個だけを選んで消す処理を行っています。
そしてオブジェクトの破壊は実際に指示があってもその場ですぐオブジェクトは破壊されません。これは MMF2 の仕様です。イベントの一番最後に一括してオブジェクトの破壊フラグが立ったオブジェクトだけ破壊されます。MMF2 が普段自動でやってくれている部分なのであまり意識されていませんが、オブジェクトが実際に破壊されるタイミングを知らないと、それが原因で上手に動かせない場合もあります。
- カウンタについて
独自の可変変数が持てないオブジェクトである。
ループを使った通し番号の振り方はアクティブオブジェクトと異なる
カウンタは便利なんだけどアクティブオブジェクトの動きに追従させたい場合には多少勝手が異なってきます。ForEach が使える環境ならばむしろ楽ですが、使えない場合はいろいろ考えることが増えると思われます。可変変数が持てないオブジェクトというのがポイントで、こういったオブジェクトは AddValue Object で変数を持たせることができるようですが、ビルドタイプが PC 用だけになってしまう。ForEach も SWF だと PC 用と違って動作が一部異なるなど SWF エクスポータで使う場合には問題があります。
- ForEach について
日本語版では使わせてもらえない(主にインストーラの問題)
SWF と PC で動作が異なっている場合がある
前述の通り、PC 版と SWF 版で動作が異なります。互換性についてはエクスポータ側のバグとして CT に報告できますが、すぐに直るかどうかは分からない。
ForEach の利点はそのループの動作仕様が高速ループより合理的、だから高速ループよりも速く処理を完了できるとも。ForEach が速いというよりも高速ループはループを開始して条件を判断させて実際に処理するまでの手順にかなりロスがあります。使い方次第なので高速ループがまったく要らなくなるわけでは無いのですが、ForEach が必要な場面というのが出てきたら使わなくっちゃ損です。