ヒットストップは世界を止めない ― 攻撃した側と受けた側だけを止める設計
攻撃が当たった瞬間の手応えを出すヒットストップ。ゲーム全体の時間を止めるのではなく、当事者の2人だけを止める方式にした理由と、止める対象の決め方をまとめます。
- Unity
- ゲーム設計
- アクション
攻撃が当たった瞬間に、ほんの一瞬だけ動きが止まる。 アクションゲームや格闘ゲームでおなじみのヒットストップは、 打撃の「重さ」や「手応え」を生む、最も効果の大きい演出の一つです。 ベルトスクロールの名作と呼ばれる作品でも、手触りの中心にあるのはこの演出です。
このプロジェクトでは、ヒットストップを攻撃した側と受けた側の2人だけを止める 方式で設計しました。この記事では、その理由と具体的な設計を書きます。
一番簡単な方法と、その問題
Unity には、ゲーム全体の時間の流れる速さを変える仕組みがあります。 ヒットした瞬間にこれを極端に遅くして、少し経ったら元に戻す。 これが一番簡単なヒットストップの作り方で、数行で書けます。
ただ、この方法は世界のすべてを止めてしまいます。 攻撃を当てた相手だけでなく、画面の奥にいる無関係な敵も、 背景で揺れている草も、飛んでいるエフェクトも、全部一緒に止まります。
一体の敵を殴っただけで世界が停止すると、 「重い一撃を当てた」ではなく「処理が引っかかった」ように見えがちです。 特にベルトスクロールは、画面内に複数の敵がいて、あちこちで 同時に戦闘が起きるジャンルです。一撃ごとに画面全体が止まっていては、 テンポが大きく損なわれます。
さらに、時間の流れを変えると物理演算の刻み幅との関係も変わるため、 吹き飛びの距離などが微妙に変わる恐れもあります。 アクションゲームでは、同じ技を当てたら同じ結果になることが重要です。
当事者だけを止める
そこで、止める対象を攻撃した側と、攻撃を受けた側の2人だけに絞りました。 それ以外のキャラクターやエフェクトは、普段どおり動き続けます。
止める2人に対しては、次のものを止めます。
- アニメーションの再生:再生速度をゼロにして凍結し、終わったら元に戻す
- 技の進行時間:技のタイムラインを進めるタイマーを止める
- 移動:キャラクターの移動処理を止める
アニメーションだけ止めても、技の進行時間が進んでいれば 攻撃判定のタイミングがずれてしまいます。 逆に進行時間だけ止めても、見た目が動いていれば止まったように見えません。 見た目と中身の両方を、同じだけ止める必要があります。
カメラも止める
見落としやすいのがカメラです。 カメラはプレイヤーを追いかけて毎フレーム位置を更新しているので、 キャラクターが止まっていても、カメラが追従の途中で動き続けることがあります。 すると、止まっているはずの画面がぬるっと流れて見え、 ヒットストップの「止まった感」が薄れてしまいます。
このプロジェクトでは、ヒットストップ中は追従カメラの更新も止めることにしました。 止まる瞬間に画面ごとぴたりと止まることで、打撃の強さがはっきり伝わります。 その上で、必要に応じて画面をわずかに揺らす演出を足せるようにしています。
止める長さは技ごとに決める
ヒットストップの長さは一律ではなく、技のデータで技ごとに指定します。 目安は 50 ミリ秒から 150 ミリ秒のあいだです。
弱い攻撃は短く、強い攻撃は長く。この差が、技の重さの違いとして伝わります。 連続で当てる弱攻撃に長いヒットストップを付けると、 コンボのテンポが悪くなるので、軽い技ほど短くするのが基本です。
意外に感じるかもしれませんが、この長さはかなり短いものです。 150 ミリ秒でも、60 フレームのゲームでは 9 フレームほどにすぎません。 プレイヤーが「止まった」と意識するほど長くすると、 手応えではなく遅延として感じられてしまいます。 意識されない程度の長さのほうが、手応えは強く感じるというのが、 ヒットストップの面白いところです。
多段ヒットで気をつけること
一つの技が短い間隔で何度も当たる場合、前のヒットストップが終わる前に 次のヒットが発生することがあります。 このとき、停止時間を単純に足し合わせると止まりすぎますし、 短い値で上書きすると演出が弱くなります。
多段ヒットの扱いは、技の手触りに直結する部分なので、 実際に触りながら決めていく必要があります。 データで長さを技ごとに指定できるようにしておいたのは、 こうした調整を繰り返しやすくするためでもあります。