縦スクロールシューティング04





高速ループに挑戦、第二回:4つ目の例題

4:高速ループを使ってDukeを上から下に高速移動させてください。移動量は1pixel以下でお願いします。背景(障害物)への衝突処理を追加してください。とりあえずDukeが地面の上に立てれば良いです。見た目が1pixelでも埋まった状態だったらダメです。

メリ込み無し

メリ込み無し



動作確認用Java出力→

前回の例題1、2、3の処理が自力で作れたら例題4の処理は簡単です。ヒントは毎回最低の移動量(1pixel)で座標を移動していて、その結果障害物に当たったのだから、その時点から一つ処理を戻せば障害物には当たって無いってことですよね。衝突したら一つ処理を巻き戻してやれば良いのです。移動は移動量で定めているのだから、一つ戻るためには毎回加算していた移動量をこの時だけ減算してやれば良いってことです。1ピクセルプラスして動いていたのなら1ピクセルマイナスしてやれば良い・・・そして巻き戻しが完了したら高速ループをその時点で「停止」させれば希望の処理が完成です。この例題からアクティブオブジェクトの変数に「on ground」というものが新たに追加してありますが、これは床との衝突判定を行うためのものです。今回は衝突後のイベントを組みませんから0→1に変更した後は変数(on ground)が何の役にも立っていませんが、例えばジャンプアクションなどを作るときはジャンプ中(つまり空中にいる時)は変数(on ground)=0、変数(on ground)=1の時は地面に接している状態という感じで変数の状態を判定すれば今キャラクターがどういう状況にあるのか説明できるようになっています。あるいはいろんな人のソースコードを見てもこの変数(on ground)というのは散見できるはずです(そしてこれはMMF2に限った話ではありません)

解答:ソースコード:→

変数(On Ground)の追加

変数(On Ground)の追加


例題5:縦のコリジョンと横のコリジョンを交互に行う

5:動作サンプル(下のJava出力)を見て高速ループで作ってみてください。

動作確認用Java出力→

例題4ができれば例題5も考え方は簡単ですね。4方を壁に囲まれた状況でまずスプライトは床に向かって移動します。床に当たったらその時点で縦移動のループ処理を停めて、即座に横移動のループ処理に切り替えます。アクティブに設定してある変数をプロパティから確認してみてください。サンプルでは別々の変数を用いて縦移動の時と横移動の時のループ回数を意図的に少し差をつけてあります。本当はこれも縦横で別々の変数にする必要性は無くって、説明用に分かりやすさを求めた結果こうなっています。本来、縦移動が終了した時にループの回数を横移動用に変更して、また縦移動に切り替わった時には縦移動用の数値に変えてやるイベントを組めば変数の利用は一個で済みます。あとは例題4と異なるのはこれまでの縦移動に加えて横移動が加わったため変数(xpos)というスプライトのX座標を代入するための変数が加わったことです。今回、移動量は1で共通としましたが、ループ回数を固定にして移動量を縦(Y)と横(X)でそれぞれ固有の値にするというのもアリだと思います。

  1. 移動量(x)
  2. 移動量(y)
  3. ループ回数(共通/固定)

あるいは

  1. 移動量(共通/固定)
  2. ループ回数(x)
  3. ループ回数(y)
変数(xpos):横の処理追加

変数(xpos):横の処理追加

解答:ソースコード:→

例題5までをやった結果・・・

これであなたは「高速ループマスターになれた!」というワケではちっともありませんが、少なくともここまで自力でやれれば理屈で言えば4方向移動は自分で作れます。そして4方向が作れれば八方向も作れます。しかし実際作ってみればキー対応を考える時に複数同時押しを考慮しないといけないから、思い通りの4方向移動を作るのも慣れない内は意外とタイヘン・・・かもしれません。八方向だと更に多くの複数キー同時押しパターン対応を考えないといけないし、八方向じゃないけどジャンプアクションはもっと多くの計算をもっと多くの変数を使ってこなす必要があります。アクションゲームって2Dとは言え計算の量がそれなりに多いからプログラムうんぬんよりも基礎的な数学の知識が無いと無理だし、だからこそこれまで敷居も高いと言われていた由縁なのだと思います。とは言え、ここまでは「高速ループの使い方とコツ」さえ覚えれば誰でも作れる範囲だと思います。そして八方向を作るのが目的で始めた高速ループレッスンなので、一旦レッスン本編はここで終了とします。この後続く例題6と高速ループ:番外編は蛇足、もしくは自主勉強ってことであえて読む必要はありません。
(※番外編は今後追加予定の記事です)

例題6:配置済みオブジェクトと重ならない位置を探しながらランダム表示をする

以下の動作サンプルを見て似たような処理を作ってください。サンプルは#2(活用事例)の方が分かりやすいかもしれませんが#1も同じ原理です。#1の場合、ランダムな位置を選択するのに左マウスクリックが必要になっています。簡単な説明をすると、すでに配置済みのオブジェクトと重ならない位置を毎回探してオブジェクトをランダムで表示するサンプルです。

ランダムな位置を探す

ランダムな位置を探す

※このサンプルを真似て作る場合、ある程度条件を満たしやすい十分なスペースを意図的に確保しておかないと無限ループに陥るので注意してください。
※ランダム値の作成には「Randomizer object(Cellosoft製)」を使っています。Bonus Pack 2に入っているエクステンションです。

#2は表示されている敵オブジェクト(障害物を除く/中央の頭蓋骨は頭にしかコリジョンが無いです)に重ならないように緑色のウィザードがランダムに位置を変えて表示されています。この重ならないランダムな位置を探すのに高速ループを使っています。

動作確認用Java出力#1(左マウスクリックでランダムな位置を決定)→
動作確認用Java出力#2(活用事例)→

このサンプルはソースコード内部に同じ結果を得られる3パターンが用意してあります。作ってみてパターン3が一番シンプルにできたのでこれを用いて説明をします。パターン1とパターン2も同じような理屈ですが、これらと比較してイベント行が一行少ないのでパターン3を推奨します。

ちなみに「AとBが衝突」という条件にはNOT(論理否定)が使えないので、NOT(論理否定)が使える「AとBが重なっている」という条件を利用しています。

まず高速ループを回す直前にランダムなXY座標を得て実際の変更を試行しておきます(イベント行16)。次に高速ループが回っている時に「AとBが重なっている」か「AとBが重なっていない」の二つで条件を分けて処理をしています。「AとBが重なっていない」時はこのままで良いため即座に高速ループを停止してループ処理を終了させます。

次に「AとBが重なっている」場合の処理。この場合ランダムで再度XYポジションを決定/変更しなおします。この後忘れないで欲しいのが「ループインデックスを0に指定」、つまりループインデックスを変更することです。この処理はよく考えずに使うと、これが原因で無限ループになる可能性を含んでいます。十分な空きスペースがあればそれなりに高速で適当なポジションを確保してくれるはずです。

イベントの流れ

イベントの流れ


処理の流れ(一覧)

処理の流れ(一覧)

解答:ソースコード:→