MZではクイックタイムイベント(QTE)のミニゲームが作成可能だと学びましたが、どこまで深く作れるかは分かりません。可能な限りプラグインを使わずに何かを作りたいです。これらの質問に答えられる方がいれば嬉しいです。
1. 円形に回転し、ポインターが円に沿って動くQTEバーを作成できますか?
2. 1つのイベント内で、異なるボタン入力を必要とする複数のQTEを同時に実行できますか?
3. イベント内の選択肢に基づいて、異なるQTEを複数作成できますか?
MZではクイックタイムイベント(QTE)のミニゲームが作成可能だと学びましたが、どこまで深く作れるかは分かりません。可能な限りプラグインを使わずに何かを作りたいです。これらの質問に答えられる方がいれば嬉しいです。
1. 円形に回転し、ポインターが円に沿って動くQTEバーを作成できますか?
2. 1つのイベント内で、異なるボタン入力を必要とする複数のQTEを同時に実行できますか?
3. イベント内の選択肢に基づいて、異なるQTEを複数作成できますか?
フォーラムへようこそ、NiamhNyxさん!
イベントコマンドでは、この角度を直接読み取ることはできません。同じループ内で独自のカウンター変数を増やして角度として扱い、ボタンが押された瞬間にその値をチェックします。リングを画像 1、ポインターを画像 2 として、どちらも原点を中央に同じ座標に配置した場合の概略は以下の通りです:
◆制御変数:#0011 角度 = 0
◆画像表示:#1、リング、中央 (408,312)、(100%,100%)、255、通常
◆画像表示:#2、ポインター、中央 (408,312)、(100%,100%)、255、通常
◆画像回転:#2、+2
◆ループ
◆制御変数:#0011 角度 += 1
◆分岐:角度 ≥ 360
◆制御変数:#0011 角度 -= 360
◆分岐終了
◆分岐:ボタン [OK] がトリガーされた場合
◆画像回転:#2、0
◆分岐:角度 ≥ 80
◆分岐:角度 ≤ 100
◆制御スイッチ:#0021 ヒット = ON
◆分岐終了
◆分岐終了
◆ループ終了
◆分岐終了
◆待機:1 フレーム
◆上記を繰り返す
速度 2 は 1 フレームあたり 1 度なので、カウンターは各パスで 1 ずつ増加します。80 から 100 のペアがヒットウィンドウであり、2 つの分岐をネストさせることで AND 条件を実現しています。
カウンターと実際の画像の角度のズレが気になる場合は、画像回転コマンドを完全にスキップし、ポインターを事前にフレームセット(例えば 10 度ごとに 36 フレーム)に回転させ、カウンターに一致するフレームを画像表示するという別の方法もあります。画像ファイルは増えますが、角度は常に変数の値と完全に一致します。
イベントコマンドは順序通りに実行されるため、「同時実行」とは、1 つのループ内でフレームごとにすべてのボタンをチェックすることを意味します。同じループ内で、各ボタンに対して条件分岐→ボタンを追加し、それぞれに独自の変数と画像を割り当て、最後に 1 フレームの待機を配置します。制約となるのはイベントコマンドそのものよりも、ドロップダウンリストでエンジンのマッピング済みボタン(OK、キャンセル、シフト、4 つの矢印、ページアップ、ページダウン)しか提供されていない点であり、OK とキャンセルはそれぞれ複数のキーをカバーしています。もし矢印キーが QTE(クイックタイムイベント)の一部であるなら、プレイヤーが押し続けながら移動してしまわないよう、並列実行ではなく自動実行で全体を動かすことをお勧めします。
それについては問題ありません。選択肢を表示して別々の分岐や別々の共通イベントに分け、QTE ごとに 1 つずつ割り当て、それぞれが独自のループを実行し、呼び出し元イベントが後で読み取る結果変数に書き込みます。
なるほど、面白いですね。私が考えていることは実現可能のようですが、さらに明確にするために、どうやって完全に説明すればよいかを少し考え込む必要があるかもしれません。頭の中にあるものを説明するのが本当に苦手なんです。
ありがとうございます。
どういたしまして!説明についても急がなくて大丈夫です。それに、実際に画面に何が表示されるかのざっくりとしたスケッチがある方が、文章で説明されるよりも私には読みやすいですよ。用意できたら投稿してください。セットアップについて一緒に進めていきましょう。
うーん、数時間格闘したけど、思った通りに動いてくれない。目標地点を正しく認識したり、壁として定義したところで反射したりしないんだよね。
ここで作ろうとしているミニゲームは、ポーションの調合用なんだ。
第1フェーズのイージーレベルでは、材料を釜に入れる作業になる。このフェーズでは、成功するたびにランダムな位置に移動する目標が描かれた円があり、ポインターバーは円の上部で反射して逆方向に動き出す仕組みにするつもりだ。
今のところ、イベント内の「画像の回転」設定のおかげでポインターを回転させることはできるんだけど、上部を壁として認識させて反転させることができないんだ。
◆ループ
◆待ち:1フレーム
◆条件分岐:右移動ポインターがONの場合
◆変数操作:#0011 ポインター角度 += 2
◆条件分岐:ポインター角度 ≥ 360
◆スイッチ操作:#0001 右移動ポーター = OFF
◆
:終了
◆
:それ以外
◆変数操作:#0011 ポインター角度 -= 2
◆条件分岐:ポインター角度 ≤ 1
◆スイッチ操作:#0001 右移動ポーター = ON
◆
:終了
◆
:終了
◆
:上記を繰り返す
これが私が直面している最初の壁だ。
この部分を完成させたい。なぜなら、これができれば、より難易度の高いポーション用に第2フェーズ(ダブルフェーズ)を作れるからだ。円の半分は一つの入力、もう半分は別の入力とし、中央の上下で反射する2つの独立した目標とポインターを設定するつもりだ。
目標がランダムに移動する件も、この部分の問題が解決できればおそらく対処できると思うんだ。
今はうまく上方向に反射させることができましたが、画像回転オプションを使っても同じことができるかどうかは分かりません。そのため、現在はスクリプトで対応しています。
この設定をより良い方法で行う方法はありますか?というのも、各フェーズを共通イベントとして作成し、マップイベント中に難易度をランダムに引き出せるようにする予定だからです。
◆ループ
◆条件分岐:右移動ポインターがOFFの場合
◆変数操作:#0021 ポインター角度 = 0
◆変数操作:#0022 ポインター速度 = 2
◆画像表示:#1, 01_Circle_Test, 中央 (552,312), (100%,100%), 255, 通常
◆画像表示:#3, 01_Pointer_Test, 中央 (552,312), (100%,100%), 255, 通常
◆スイッチ操作:#0001 右移動ポインター = ON
◆
:分岐終了
◆条件分岐:ポインター角度 ≥ 360 の場合
◆変数操作:#0022 ポインター速度 = -2
◆
:分岐終了
◆条件分岐:ポインター角度 ≤ 0 の場合
◆変数操作:#0022 ポインター速度 = 2
◆
:分岐終了
◆変数操作:#0021 ポインター角度 += ポインター速度
◆スクリプト:$gameScreen.picture(3)._angle = $gameVariables.value(21);
◆待機:1フレーム
◆
:ループ終了
スクリプト行は残しておく価値があると思います。Rotate Picture(画像回転)は、負の速度がそれを反転させるため、バウンス(跳ね返り)も処理できるはずです。ただし、そうすると角度の制御がエンジン側に移り、変数はそれに追従して記録されるだけになります。_angle に書き込むことで、両方が同じ数値を維持し、これがゴール判定の信頼性を高めています。
私が変更したいのは、セットアップの配置場所です。init ブロックは「右ポインター移動」のループ内にあり、そのスイッチをオフに戻す処理が見当たりません。そのため、2回目の呼び出しでは「画像の表示」をスキップして、残っていた角度から始まってしまいます。ループの上に移動させることで、スイッチなしで同じ処理を実現できます:
◆コントロール変数: #0021 ポインター角度 = 0
◆コントロール変数: #0022 ポインター速度 = 2
◆画像の表示: #1, 01_Circle_Test, 中心 (552,312), (100%,100%), 255, 通常
◆画像の表示: #3, 01_Pointer_Test, 中心 (552,312), (100%,100%), 255, 通常
◆ループ
◆条件分岐: ポインター角度 ≥ 360
...
そこから先は、難易度に応じてマップイベントが呼び出し前に変数に値を設定するだけです。ポインター速度は移動速度を、ゴールウィンドウの両端には2つの変数を使用し、共通イベントはそれらの値を読み取るため、数値を直接記述する必要はありません。そうすれば、1つの共通イベントですべての難易度に対応でき、マップイベント側で選択します。
2つのポインターのフェーズも同じループに収まります。各ポインターには独立した角度変数、速度変数、画像番号が必要になり、制限値は0〜180と180〜360になります。また、スクリプトボックスでは代入行を一度に両方受け取ります。
ふーん、なぜ今になって急に動くようになったのか不思議だ。スイッチなしで試したときはうまく動かなかったような気がする。もしかしたら、以前に何か削除して、それに気づかなかっただけかもしれない。
今のところ、もう2つうまく動いていることがある。1つは、ヒットごとにポインターの速度が速くなること、もう1つは、後にそれが必要になるフェーズのためにゴールの位置がランダムに変更されることだ。
ただ、現在のゴールに少し問題がある。ゴールの中心が上部から14度以内にある場合、ヒットが一定して検出されないようだ。
これは、動くゴールのヒットゾーンを30度にしたときに誤検知(false goal hits)が発生していた時と似ている。片側では角度が負になり、その先すべてがゴールとしてカウントされていた。ただし、上部から15度オフセットしてゴールのランダム配置を制限する以外の修正方法はわからない。
これが今のところのコードだ。一つずつうまく動くように調整しているところ。
◆Comment:自分へのメモ!!! 何をするコードかコメントするのを忘れるな!!!
: ::忘れると後悔するぞ、「後で忘れるな」くん!!!
◆Comment:0021はポインターの角度、0022はポインター速度の設定用
: :0023はゴールの中心、0025は速度増加量
◆Control Variables:#0021 Pointer Angle = 0
◆Control Variables:#0022 Pointer Speed = 2
◆Control Variables:#0025 Increase Speed = 2
◆Comment:現在のところ、左側でのヒットを無視する問題を解決するために必要な数学を学ぶまで、
: :ゴールの中心を上部から15度以内に制限する。
◆Control Variables:#0023 Goal Center Angle = Random 15..345
◆Comment:ミニゲームの画像を読み込む
: :レイヤーは順番に読み込まれる。1が最下層。
◆Show Picture:#1, 01_Circle_Test, Center (552,312), (100%,100%), 255, Normal
◆Show Picture:#2, 01_Goal_Test, Center (552,312), (100%,100%), 255, Normal
◆Show Picture:#3, 01_Pointer_Test, Center (552,312), (100%,100%), 255, Normal
◆Comment:ミニゲームループ
: :現在はbreakがないため無限ループ。忘れるな
◆Loop
◆Comment:ポインターの反射に関する最初の2つの分岐
◆If:Pointer Angle ≥ 360
◆Control Variables:#0022 Pointer Speed = Increase Speed
◆Control Variables:#0022 Pointer Speed *= -1
◆
:End
◆If:Pointer Angle ≤ 0
◆Control Variables:#0022 Pointer Speed = Increase Speed
◆
:End
◆Comment:角度と回転
◆Control Variables:#0021 Pointer Angle += Pointer Speed
◆Script:$gameScreen.picture(3)._angle = $gameVariables.value(21);
◆Script:$gameScreen.picture(2)._angle = $gameVariables.value(23);
◆Comment:ゴールヒットチェックのテスト
: :
: :後で使うために、押下中は「押されている」を使用、単発押しには「トリガー」を使用
: :
◆If:Button [OK] is being triggered
◆Control Variables:#0024 Angle Distance = Pointer Angle
◆Control Variables:#0024 Angle Distance -= Goal Center Angle
◆If:Angle Distance < 0
◆Comment:誤ったゴールヒットを防止。これを忘れるな
◆Control Variables:#0024 Angle Distance *= -1
◆
:End
◆Comment:テスト用のゴール幅は30度。
◆If:Angle Distance ≤ 15
◆Comment:ヒット成功時に速度を増加させる
◆Control Variables:#0025 Increase Speed += 1
◆Comment:負の速度値が存在し、それに対応する必要があることを忘れるな。
◆If:Pointer Speed > 0
◆Control Variables:#0022 Pointer Speed = Increase Speed
◆
:Else
◆Control Variables:#0022 Pointer Speed = Increase Speed
◆Control Variables:#0022 Pointer Speed *= -1
◆
:End
◆Comment:ゴールの配置は円上でランダムにシフトする。
: :
: :ゴールが上部を通過した場合、左側では機能しない。
: :スクリプトで修正できるかもしれないので、後で調べる。
◆Control Variables:#0023 Goal Center Angle = Random 15..345
◆Wait:1 frame
◆
:Else
◆Comment:ゴールヒットミス
: :
: :アイデア!!! 品質とミスを判断するためのポイントシステムを作る
: :成功したヒットでポイントを増やし、ミスで減らす。
: :フェーズに時間制限と最大ポイントキャップを設定する。
◆Wait:1 frame
◆
:End
◆
:End
◆Wait:1 frame
◆
:Repeat Above
これは以前からのラップ(wrap)の問題で、今度は円の上部で発生しています。ポインターと目標が0の反対側に位置する場合、距離は長い方(逆方向)で測定されます。例えば、ポインターが358で目標が5の場合、実際は7の差ですが353として認識されてしまい、見た目では接触しているにもかかわらず入力が無効になります。これが、完全に機能しないのではなく不規則に動作する理由です。目標が5の場合、5から20の範囲に入力されたものは依然として検出されます。
すでに作成した条件の直後に、もう一つの分岐を追加することでこの問題を解決できます:
◆If:Angle Distance < 0
◆制御変数:#0024 Angle Distance *= -1
:End
◆If:Angle Distance > 180
◆制御変数:#0024 Angle Distance *= -1
◆制御変数:#0024 Angle Distance += 360
:End
180より大きい差は、逆方向に測定した短い距離を表すため、符号を反転させて360を足すことで実際の正しい距離が得られます。353は7になり、≤ 15のチェックが通過します。これにより、オーバーシュート(目標を過ぎること)もカバーされます。ポインターは反発処理の分岐が適用される前に、361または0の少し下にあるフレームが存在する可能性があるためです。
これにより、両方の「目標中心角度」は「ランダム 0..359」に戻すことができます。上部のものも、ヒット処理の分岐内のものも同様です。
なるほど、ありがとうございます。家に帰ったらその修正を追加します。その修正が入れば、私のあまりにも愚かで複雑なアイデアの一つが実現可能に思えます。
これがきっかけで進歩できたことを共有します。

思った通りにポイントを追跡させるために、かなり長い間悪戦苦闘しました。結果として、緑のゴールを通過したとき、プレス(押す操作)のタイミングを間違えたとき、あるいは赤のゴールに到達したときに1ポイント減点されるようにしました。
しばらくの間、現在接近しているゴールの縁を通過したときにポイントが減少する理由がわからず困りました。結局のところ、単純なミスで、ゴールに触れたことを通過としてカウントしていたのが原因でした。
その後、ゲーム内でどのように機能させたいかの基礎を作るために、実際のゴールを2つ、偽のゴールを2つ設けることにしました。2つの食材はポーション用で、他の2つはランダムに選ばれた(ポーションには関係ない)ものです。
これに関連する小さな投げアニメーションについては、口を開く気にもなりません。約15時間もの苦難と苦しみを経て、ようやく原因が判明しました。元のポインターが、小さな青い円が含まれた688x688の画像だったため、位置を正確に追跡できなかったのです。
タイマーは少なくとも簡単でしたが、まあ、タイマーですからね。
見栄えが良く、ポイントルールも明確ですね。緑のゴールでパスを出すとペナルティを与えるという仕様は、キャンプ(待機)ではなく積極的なプレイを促す良い方法だと思います。
688の画像に関する件は、後から考えると納得できますね。画像の位置がキャンバスの中心にあるため、ドットの実際の座標は変数には含まれていません。もしトスやパーティクルなどで再度必要になった場合、すでに追跡している角度を使って計算できます:
x = 552 + r * Math.sin(angle * Math.PI / 180)
y = 312 - r * Math.cos(angle * Math.PI / 180)
ここで、rは中心からのドットの距離(ピクセル単位)です。回転の規約と同じで、0度は上向きで、時計回りが正となります。
結局、大きな回転画像を単に使うだけでは非常に制限されることに気づいたため、基本的にすべてをやり直すことになりました。緑のゴールが正しい素材スプライトで、赤が間違いであることをどう設定するかは全く見当もつきませんが、読んでいる限り、データベースIDとそれ用の変数を設定する何かに関連しているようです。でも、今はそれ以上調べるほど疲れていません。
今「簡単な難易度」と呼んでいる素材追加の部分をやり直しました。
ゴールのサイズを90x90に設定したので、素材スプライトをそこそこ適切な大きさにでき、さらに当たり判定も適切に設定できます。また、ポインターの1/8だけがゴールに乗っていれば成功とみなすように設定しました。そうでないと不公平だと感じたからです。

中級レベルの難易度の実装には時間がかかりました。なぜか前回のイベントをコピー&ペーストしなかったという、わけのわからない理由で!そして、完全なバカみたいに、簡単な難易度ですでに修正済みのバグを1日半かけてデバッグしていました…

最後の難易度のバランス調整はまだ途中ですが、集中力が途切れた瞬間に絶対的な地獄になるでしょう。赤と緑の円がすぐに区別できる状態ではなくなると、本当に大変です。また、残りの不具合(ジャック)も解消中です。ゴールのコンガラインはまだ occasionally 発生しますが、バウンスの当たり判定を微調整し、反発力を少しだけ強くすれば修正できると思います。

とにかく、RPG MakerMZでこれが可能であることを教えてくれてありがとう。これが可能だと知らなければ、すでにプラグインを探していたことでしょう。
イングリデントのスプライトについては、各画像を数字の名前で命名するのが良いでしょう。例えば、Ingredient_1、Ingredient_2、という具合です。もしイングリデントがすでにデータベース内のアイテムとして登録されているなら、アイテムIDを使ってください。つまり、Ingredient_12はアイテム12に対応します。
「画像の表示」ウィンドウでは画像名に変数を直接使用できませんが、スクリプト行では変数から名前を構築することができます:
◆Script:$gameScreen.showPicture(4, "Ingredient_" + $gameVariables.value(31), 1, 552, 312, 100, 100, 255, 0);
これは、変数31に入っているイングリデントIDを画像4として表示します。名前の後の引数は、「画像の表示」ウィンドウと同じ順序で指定します:原点(1は中央)、X座標、Y座標、スケールX、スケールY、不透明度、合成モードです。もしループ処理ですでに毎フレーム目標を配置しているなら、XとYの値は処理が引き継がれるまでの間のみ意味を持ちます。同じ画像番号でこの行を再度実行すると画像が入れ替わるため、目標が新しい位置に移動して新しいイングリデントが必要になった場合にも機能します。
難易度変数の場合と同様に、マップイベントは共通イベントを呼び出す前に、実際のイングリデントIDを2つ埋め込むことができます。偽物の方については、イングリデントの範囲内で乱数を生成し、それが実際のイングリデントや他の偽物に該当した場合は、もう一度乱数を生成します。もし実際のイングリデントか偽物かの判定が、どの画像がクリックされたかによって行われているなら、その部分は変更の必要はなく、画像だけを更新すれば十分です。
デプロイする際、「未使用ファイルを除外」機能は、スクリプト行内で構築された画像名を認識できないため、イングリデントの画像をビルドから除外してしまいます。これを防ぐには、一度も呼び出されない共通イベントを作成し、その中に各イングリデント画像に対する単純な「画像の表示」コマンドを記述しておくことで、ビルドに画像を含めることができます。
これは、自分がいつか抱えることになるかもしれない質問、つまりデプロイメントの際にスクリプトで呼び出されるアセットが壊れないようにする方法についても答えてくれています。
改めてありがとうございます。