FableQuest
小技帳
小技 001 · ヒットストップと画面揺れ

その一撃に、間をつくる。

止める長さを4fから0fへ。画面揺れを足す前に、接触の「間」が何を変えるか、触って確かめる。

実験 01 — 手応えを比べる 60 Hz
基準 0f
止めずに、通り抜ける。
あなたの設定 4f · 66.7ms
停止中
接触時に止める長さ
27 / 89f

まず再生。次に 4f → 0f に切り替えて、もう一度。止まる「間」が、打撃の読みやすさをどう変える?

きっかけ 着想元として記録したWIP: @LivingWorldProj ↗ 元投稿の確認待ち

接触の瞬間に、目が追いつく。

一撃が速すぎると、動きは見えても「当たった瞬間」を見逃すことがあります。ヒットストップは、その瞬間に短い間をつくる手法です。 この実験では、攻撃側と標的の姿勢を接触時に少しだけ保ち、その後に標的が動き出します。

まず 4f、次に 0f で再生してみてください。このデモのシミュレーションは60 Hzなので、差は約67ミリ秒。標的を見ていると、当たる瞬間を捉えやすくなったでしょうか。

これは、自分のゲームで確かめるための出発点です。連続攻撃、重い一振り、遠くから見る戦闘では、同じ長さの停止でも役割が変わります。

4フレームの中身 / 60 Hz
26f 接触前
27f 接触
28f 停止
29f 停止
30f 停止
31f 再開
27、28、29、30f。数えるのはこの4枚。31fではすでに動いています。4 ÷ 60秒 ≈ 66.7ms。

動作を止める。視点を揺らす。

画面を揺らすをオンにして、ヒットストップを 0f にしてみましょう。視点は動きますが、キャラクターの接触姿勢は止まりません。次に4fにして、両方を重ねてみてください。

二つの効果は、作用する対象が違います。

  • ヒットストップは動作のタイミングを変えます。 このデモでは両方のキャラクターを止めていますが、ゲームによっては一部の対象だけを止める設計も考えられます。
  • 画面揺れは視点を変えます。 このデモでは12フレーム(60 Hzで200ms)かけて揺れが減衰します。キャラクターが止まっている間も、揺れは進みます。

揺れを大きくしても、接触姿勢の読みやすさを補えるとは限りません。当たりが分かりにくいときは、まず両方をオフにして、シルエット、間合い、タイミングを見直してみてください。

「4フレーム」を、正確に数える。

接触は 27f で始まります。停止の長さを S フレームとすると、止める区間は 27 ≤ frame < 27 + S。4f設定なら、31fではすでに動いています。0f設定では27fから標的が動き出します。

このデモは、各ステップの更新後の状態を描きます。0fでは接触判定と最初の移動が同じステップで起きるため、衝撃の印は出ますが、接触したまま止まる姿勢は描かれません。「4f」には接触ステップ自体を含みます。接触の1枚に、さらに4枚を加える数え方ではありません。

スライダーと±1fボタンを使えば、アニメーションなしで境界を確かめられます。再生は1/60秒の固定ステップで進むため、120 Hzの画面でも動作が2倍速にはなりません。¼倍速は再生速度だけを変え、シミュレーションの1フレームの意味は変えません。

画面揺れも、毎回違う乱数ではなく、整数ハッシュから同じ値を再現します。同じフレームに戻れば、同じ絵に戻ります。揺れの大きさは図のワールド座標で定義しているため、画面上の大きさは図と一緒に拡大・縮小されます。

自分のゲームで、試す順番。

  1. 画面揺れを切り、接触姿勢だけで当たりが読めるかを確かめる。
  2. シミュレーションの更新頻度を明記し、ほかの条件を変えずに0f、2f、4fを比べる。
  3. 当たる瞬間と、動き出した後の両方を見る。強いアクセントが、操作のリズムを崩すこともある。
  4. 必要なら、動きを読みやすくする程度に視点を揺らす。
  5. 連続攻撃、画面端、動きを減らす設定でも確かめる。

問いは「もっと派手にするには?」よりも、「何に気づいてほしい?」。

次はエンジンに依存しない擬似コードです。止める対象を限定し、入力、UI、エフェクトには適切な時計を使ってください。特定のエンジンで動作確認した実装例ではありません。

on_contact:
  held_steps = chosen_hit_stop_frames
  shake_steps = 12

each_fixed_step:
  # Contact is resolved before this step's hold decision.
  if held_steps > 0:
    held_steps -= 1
  else:
    advance_affected_actors()
  if shake_steps > 0:
    draw_camera_offset(shake_steps)
    shake_steps -= 1
  else:
    clear_camera_offset()

衝突判定と更新処理の順序によって、結果は変わります。タイマーや停止フラグだけでなく、接触時と再開時に実際に描かれる姿勢もテストしてください。

根拠と、まだ分からないこと。

元投稿について
編集資料に記録された投稿リンクです。元のWIPは独立した確認が済んでいないため、作者の実装については述べません。
実験の条件
本サイトの demo、固定60 Hzのシミュレーション。接触は27f。4f設定では27〜30fの姿勢を保ち、31fで再開。画面揺れは12フレーム。
クレジット
@LivingWorldProj ↗ — 編集資料に記録された着想元。引用・メディアの転載はしていません。

誤りやクレジットの変更・削除は、 @FableQuest のDM へ。DMが使えない場合は、公開投稿でお知らせください。 訂正履歴