第二章 演出と手応えNo.009
画面揺れ
Screen Shake別名 スクリーンシェイク、カメラシェイク、画面振動
概要
攻撃が当たったときや爆発したときに、ゲームの画面を短いあいだ小刻みにずらす演出。画面全体が動くので衝撃の大きさが伝わり、当たった場所を見ていなくても何かが起きたと気づける。揺らしすぎると何が起きているか見えなくなり、酔いやすくもなる。
使われる場面
- 強い攻撃が当たったとき
- 強い攻撃ほど強く長く揺らすか、強い攻撃だけを揺らす。揺れの違いで弱い攻撃との重さの違いが伝わる。
- 爆発
- 爆発の大きさに合わせて揺らす。爆発には決まった向きがないので、ずらす向きは毎フレーム乱数で決める。
- 重い物の着地や大きな足音
- 巨大な敵が着地したり歩いたりするときや重い物が落ちたときに、縦の向きに揺らす。地面に重さが伝わったように見せる。
- プレイヤーが攻撃を受けたとき
- 受けた瞬間に短く揺らす。画面全体が動くので、ほかの所を見ていても攻撃を受けたことに気づける。
判断基準
| こういうとき | こうする |
|---|---|
| 攻撃が当たった気がせず、特に強い攻撃や爆発に迫力がない | 画面揺れを入れる。強い攻撃や爆発は強さを画面の高さの 2〜5%、収まるまでの時間を 0.2〜0.5 秒(毎秒 60 回の更新で 12〜30 フレーム)の範囲から試す。 |
| 強い攻撃を当てても、弱い攻撃と手応えが変わらない | 強い攻撃ほど強く長く揺らす。弱い攻撃は強さも時間も強い攻撃の半分以下にするか、揺らさない。 |
| 画面が揺れすぎて、敵や弾の位置が見えない | 強さを下げ、収まるまでの時間を短くする。まず、回数の多い弱い攻撃の揺れを減らすか切る。 |
| 攻撃を続けて当てると、画面が揺れっぱなしになるか、揺れがだんだん大きくなる | 収まるまでの時間を短くする。揺れの最中に次の揺れが起きたら、足し合わせずに、残っている揺れと新しい揺れの強いほうを使う。 |
| 揺れているあいだ、体力や弾数の表示が読みにくい | 揺らすのはゲームの画面の描画だけにし、UI はずらさずに描く。 |
| 揺れが収まった後も、画面の位置が少しずれたまま戻らない | ずれをカメラの位置に書き込んでいる。カメラの位置はそのままにし、描くときだけずれを足す。 |
| 揺れで酔う、疲れるという声がある | 設定画面で揺れの強さを弱めたり揺れを切ったりできるようにする。 |
遊んでこう感じたら
指示の例
強攻撃を当てても軽く感じる。強攻撃が当たった瞬間に画面揺れを入れて、画面の高さの 3% くらいずらし、0.3 秒くらいで収まるようにして
敵を続けて斬ると画面が揺れっぱなしで、敵の位置が見えない。弱攻撃の画面揺れは切って、強攻撃の画面揺れは収まるまでの時間を今の半分くらいにして
画面揺れのたびに体力の数字がぶれて読めない。画面揺れはゲームの画面にだけかけて、体力や弾数の表示は揺らさないで
画面揺れで酔うという声があった。設定画面に画面揺れの強さの項目を足して、0〜100% のあいだで弱めたり切ったりできるようにして
爆発の画面揺れが攻撃のときと同じくらいで、迫力がない。爆発の画面揺れは強さを強攻撃の 1.5 倍くらいにして、0.5 秒くらいかけて収めて
詳細
画面を揺らすと手応えが出る理由
攻撃が当たっても、動くのが攻撃した側と受けた側だけなら、出来事は画面の一部で起きて終わる。一方、大きな物がぶつかったり爆発したりすると周りの地面や建物まで揺れ、近くで見ている人の視界も揺れる。
そこで、攻撃が当たった瞬間や爆発した瞬間にゲームの画面を短いあいだ小刻みにずらす。この演出を画面揺れと呼ぶ。画面全体が動くので、衝撃が当たった二者だけでなく周りにまで及んだように見え、出来事の大きさが伝わる。視界の広い範囲が動くため、当たった場所を見ていなくても何かが起きたことに気づける。デモの二つの段は火花と人形ののけぞりを同じにしてあり、違いは画面を揺らすかどうかだけである。
強さと収まるまでの時間の目安
揺れは揺れの強さ(最初にずらす最大の量)と収まるまでの時間の二つで決まる。強さは画面の大きさによらず比べられるよう、画面の高さに対する割合で考える。画面の高さが 1080 ピクセルなら、1% は約 11 ピクセルになる。
目安は弱い攻撃で強さ 0.5〜1.5%、収まるまで 0.1〜0.2 秒(毎秒 60 回の更新で 6〜12 フレーム)ほどである。強い攻撃や爆発では強さ 2〜5%、収まるまで 0.2〜0.5 秒(12〜30 フレーム)ほどである。この範囲から試して遊びながら調整する。何度も起きる出来事ほど、弱く短くする。そうした出来事を強く長く揺らすと、遊んでいる時間の多くで画面が揺れていることになる。
強い攻撃ほど強く長く揺らすと、揺れの違いが攻撃の重さの違いとして伝わる。どの攻撃も同じだけ揺らすと、強い攻撃を当てても弱い攻撃と同じ手応えしか返らない。デモの弱い攻撃は強さも時間も強い攻撃の半分にしてある。既定では強い攻撃が 3% で 20 フレーム、弱い攻撃が 1.5% で 10 フレームになる。「弱い攻撃の揺れ」を「同じ」に切り替えると、1 つ目と 2 つ目の試行で揺れ方の差がなくなる。回数の多い弱い攻撃は揺らさず、強い攻撃だけを揺らす作り方もある。
揺らしすぎたとき
強すぎる揺れは敵や弾の位置を読み取りにくくする。画面の上の物が 1 フレームごとに別の位置へ跳ぶので、目で位置を追えなくなる。
長すぎる揺れは攻撃を続けて当てる場面で問題になる。デモの 3 つ目の試行では最初に押してから 4、20、42 フレーム目に攻撃が当たる。強い攻撃の揺れが収まるまでを既定の 20 フレームにすると、揺れは当たるたびに収まり、揺れていないあいだが挟まる。60 フレームにすると、揺れは 4 フレーム目から 101 フレーム目までの 98 フレーム(約 1.6 秒)途切れない。当てるたびに次の揺れが始まるので、画面が落ち着く時間がなくなる。
重なった揺れの扱い
揺れている最中に次の攻撃が当たったとき、二つの揺れの強さを足し合わせると、続けて当てるほど揺れが強くなる。一度の攻撃が何体もの敵に当たる場面では、同じフレームに揺れがいくつも重なって一気に強くなる。そこで、足し合わせずに、残っている揺れと新しい揺れの強いほうを使う。デモでは新しい揺れが残っている揺れより強いときだけ、新しい揺れに置き換えている。揺れの量を一つの値で持ち、当たるたびに足して上限で抑え、時間とともに減らす作り方もある。
揺れの減り方と向き
揺れ幅は揺らし始めに最も大きく、収まるまでの時間をかけて 0 まで減らす。減り方には揺れ幅の倍率を時間に比例して 1 から 0 へ減らす直線と、その倍率を 2 乗して使う方法がある。収まるまでの時間の半分の時点で、揺れ幅は直線なら最初の半分、2 乗なら 4 分の 1 になる。最初の 1 割を下回るのは、直線では収まるまでの時間の 9 割の時点、2 乗では約 7 割の時点である。2 乗で減らすと、揺れの大部分が当たった直後に集まる。揺れが長く尾を引いて見えるときは、時間を縮める前に 2 乗で減らす方法を試す。最初の揺れの強さは変えずに、揺れて見える時間を縮められる。
ずらす向きを毎フレーム乱数で決めると、画面はどの向きにも細かく揺れる。爆発のように決まった向きのない出来事には、この揺らし方が合う。攻撃のように向きのある出来事では、当たった向きに沿って 1 フレームごとに向きを反転させながら揺らす方法もある。デモの「揺れの向き」を「当たった向き」にすると、下の段は攻撃の向きに沿って横にだけ揺れる。着地のように上下の向きがある出来事は縦に揺らす。
乱数はシードを指定できるものを使う。同じ入力から同じ揺れが出るので、記録した入力を流し直して揺れを確かめたり調整の前後で比べたりできる。
揺らすものと揺らさないもの
揺らすのはゲームの世界を映した画面の描画だけにする。体力や弾数の表示などの UI まで一緒にずらすと、数字や目盛りが 1 フレームごとに別の位置に描かれて読みにくくなる。デモの「体力の表示も揺らす」を有効にすると、下の段の体力の表示も揺れる。
揺れはカメラの位置そのものを動かさずに、描くときだけずれを足して作る。カメラの位置にずれを書き込むと、揺れが収まった後もずれが残ることがある。たとえば「カメラのデッドゾーン」のあるカメラは、キャラクターが枠の中にいるあいだ動かないので、書き込まれたずれを戻さない。
// 当たったとき。揺れの最中なら、残っている揺れより強いときだけ置き換える
function startShake(strength, frames) {
if (strength >= remaining()) shake = { strength, frames, age: 0 };
}
// このフレームの揺れ幅。直線で減らす(2 乗で減らすなら t * t を掛ける)
function remaining() {
if (!shake) return 0;
const t = 1 - shake.age / shake.frames;
return shake.strength * t;
}
// 1 ステップごとに
if (shake) {
const m = remaining();
const angle = random() * Math.PI * 2; // シードを指定できる乱数
offsetX = Math.cos(angle) * m;
offsetY = Math.sin(angle) * m;
shake.age += 1;
if (shake.age >= shake.frames) shake = null;
} else {
offsetX = 0;
offsetY = 0;
}
// 描くとき。ゲームの画面はカメラの位置にずれを足して描き、UI はずれを足さずに描く
drawWorld(cameraX + offsetX, cameraY + offsetY);
drawUI();
揺れを弱める設定
画面の揺れで酔ったり疲れたりするプレイヤーもいる。設定画面に画面揺れの強さの項目を置き、0〜100% のあいだで弱めたり 0% で切ったりできるようにする。揺れの強さにこの設定の割合を掛ければよい。ブラウザで遊ぶゲームなら、端末で動きを減らす設定が有効なときに揺れを弱めた状態で始める作り方もある。このページのデモもその設定が有効なときは、強い攻撃の揺れの強さを 1% にして始める。
ほかの演出と組み合わせるとき
「ヒットストップ」と組み合わせるときは、止め始めと同時に揺らし始める。止め終わるまで待つと、揺れが止めた分だけ遅れる。ゲーム全体の時間を止める作りで揺れもゲームの時間で進めていると、揺れまで一緒に止まり、止めているあいだ画面がずれた位置で固まる。揺れは止めている時間とは別に進める。
カメラのデッドゾーンの揺れとの違い
画面揺れは出来事に合わせてわざと起こし、決めた時間で収まる揺れである。一方、キャラクターが少し動くたびに画面全体が揺れて落ち着かないのは、カメラがキャラクターを追う方法から生じる揺れである。これは「カメラのデッドゾーン」で直す。どちらも画面が揺れると言い表せるので、頼むときは画面揺れを弱くしたいのかカメラのデッドゾーンを入れたいのかを分けて言う。