第一章 操作感No.008
入力遅延
Input Latency別名 インプットラグ、操作遅延、入力の遅れ
概要
ボタンを押してから、その結果が画面に出るまでの時間。入力を読む間隔、ゲームの処理の順番、描いた絵を画面に出すまでの待ちが積み重なって生まれる。遅れが長いとキャラクターは押したときより遅れて動くので、狙った位置で跳べず、見えてから押しても間に合わなくなる。
使われる場面
- 足場の端や障害物の手前で跳ぶアクション
- 跳ぶ位置がそのまま成否を決める。キャラクターは遅れのあいだも進み続けてから跳ぶので、遅れが長いと端から落ちたり障害物に当たったりする。
- 敵の攻撃や不意に出る障害を見てよける場面
- 見えてから押すしかないので、遅れはそのまま反応時間に足される。攻撃の予備動作や、障害が出てから当たるまでの時間は遅れを含めて決める。
- 音楽に合わせて押すゲーム
- 押した時刻そのものを判定する。画面や音を出す機器で生まれる遅れはゲームの側では減らせない。判定の時刻をずらす設定を用意し、プレイヤーが自分の環境に合わせられるようにする。
- 照準やカーソルを合わせる場面
- 狙った位置に来たのを見てから止めても、遅れのあいだは動き続けるので行き過ぎる。動く速さが速いほど行き過ぎる距離は長くなる。
判断基準
| こういうとき | こうする |
|---|---|
| 押してから動くまでに間がある、という感想が出る | 押下を読んだフレームと、キャラクターの状態が最初に変わったフレームの番号をログに出す。2 つが同じフレームでなければ、入力を読む位置と処理の順番を見直す。 |
| 見えている障害は越えられるのに、不意に出る障害や敵の攻撃には間に合わない | 遅れを減らす。減らしきれない分は、障害や攻撃が見えてから当たるまでの時間を反応時間と遅れの和より長くする。 |
| ジャンプや攻撃に構えの動きを付けたら、押しても一瞬何も起きない感じがする | 構えの最初の絵を押したフレームに出し、同時に音を鳴らす。動き出しが遅くても押したことは伝わる。 |
| フレームレートが下がると操作が重くなる | 遅れはフレームの数で積み重なるので、1 フレームが長くなるとその分伸びる。毎秒 60 回で 0.05 秒だった 3 フレームの遅れは、毎秒 30 回では 0.1 秒になる。フレームレートを保つ。 |
| 同じタイミングで押しているのに、跳ぶタイミングが毎回ずれる | 遅れの長さが押すたびに変わっている。フレームレートを安定させ、入力は毎フレーム決まった位置で読む。遅れは短くするだけでなく一定に保つ。 |
| 音楽に合わせて押すと、判定がいつも同じ向きにずれる | 判定の時刻をずらす設定を付ける。拍に合わせて何回か押してもらい、押した時刻のずれの平均からずらす量を決める画面も用意する。 |
遊んでこう感じたら
指示の例
ジャンプを押してから跳ぶまでに少し間があって、障害物の手前で押しても当たる。入力遅延を減らして、押したフレームのうちにジャンプが始まるように入力を読む位置と処理の順番を直して
操作が少し遅れる気がする。入力遅延を測りたいので、押下を読んだフレームとキャラクターの状態が最初に変わったフレームの番号をログに出して
攻撃ボタンを押すと一瞬何も起きない。入力遅延なのか攻撃の構えが長いのかを調べて、構えのせいなら押したフレームに構えの最初の絵と音を出して
不意に出る障害物は見てから押しても間に合わない。入力遅延を減らしたうえで、障害物が出てから当たるまでを今より 0.1 秒くらい長くして
音楽に合わせて押しても、判定がいつも少し遅れる。入力遅延の分を合わせられるよう、判定の時刻を 0.01 秒刻みでずらせる設定を付けて
詳細
押してから画面に出るまで
ボタンを押すと、ゲームは入力を読んでキャラクターを動かし、動いた後の絵を描いて画面に出す。どの段階も一瞬では終わらないので、押してから結果が画面に出るまでには時間がかかる。この時間を入力遅延と呼ぶ。遅れは次の段階で積み重なる。
- 入力を読む間隔:ゲームは入力をフレームごとに 1 回読む。読んだ直後に押されたボタンは次に読むまで待つので、0〜1 フレーム遅れる。コントローラーも押されたことを決まった間隔で本体に伝えるので、その間隔の分も遅れる。
- ゲームの処理の順番:キャラクターを動かした後で入力を読む作りや、押されたことを印に残すだけで次のフレームに跳ばせる作りでは、そのたびに 1 フレーム遅れる。
- 描画を待つ間:描き終えた絵は画面を描き換える時刻まで待ってから出る。描き終えた絵を何枚もためてから順に出す作りでは、ためた枚数だけ遅れる。
- 表示の処理:テレビやモニターが映像に処理をかけると、その分も遅れる。この遅れはゲームの側では減らせない。
毎秒 60 回の更新なら 1 フレームは約 0.017 秒である。デモの下の段は、ゲームが押下を受け取るまでに遅れのフレーム数を足している。状態を進める処理は 2 つの段で同じである。画面に出るまでが遅れる場合も、押してから結果が見えるまでの時間が同じなら跳ぶ位置のずれ方は変わらない。
遅れのあいだに進む距離
遅れのあいだもキャラクターは動き続ける。デモのキャラクターは 1 秒に体の幅 8 個分ほど走るので、6 フレーム(0.1 秒)の遅れでは体の幅の 8 割ほど先へ進んでから跳ぶ。12 フレーム(0.2 秒)なら体の幅 1.7 個分になる。跳ぶ位置がずれる距離は走る速さと遅れの時間の積なので、速く走るゲームほど同じ遅れで大きくずれる。
遅れなしでデモの箱を越えられるのは、17 フレーム(約 0.28 秒)の幅のうちに押したときである。押すのが早すぎると箱の手前に降り、遅すぎると上がりきる前に箱の横にぶつかる。自動再生の最初の試行は越えられる最後のフレームの 4 フレーム前に押している。遅れが 4 フレームまでなら越えられ、5 フレームからは当たる。
早めに押して合わせられる場面
遅れが毎回同じなら、跳ぶ位置は押した位置から毎回同じ距離だけずれる。そのため、遅れの分だけ早めに押せば合わせられる。デモの 2 つ目の試行は下の段の遅れの分だけ早めに押している。遅れを 12 フレームにしても、下の段は箱を越えられる。越えられるフレームの幅は 17 フレームのまま、遅れの分だけ早い側へずれるだけだからである。
ただし、遅れが押すたびに変わると早めに押して合わせることもできない。遅れが 2〜8 フレームのあいだで毎回変わるなら、同じ時刻に押しても跳ぶ時刻は 6 フレームの幅でばらつく。越えられるフレームの幅が 7 フレームより狭い障害では、どの時刻に押しても失敗する回が出る。遅れは短くするだけでなく一定に保つ。
見えてから押すしかない場面
不意に出る障害や敵の攻撃は見えてから押すしかないので、早めに押して合わせられない。出る前には押す時刻を決める手がかりがないからである。
デモで箱の出方を「不意に出る」にすると、箱は遅れなしで越えられる最後のフレームの 18 フレーム(0.3 秒)前に出る。箱が見えてから押すまでの時間(反応時間)と遅れの和が 18 フレーム以下なら越えられる。反応時間が 15 フレーム(0.25 秒)なら遅れは 3 フレームまで、12 フレーム(0.2 秒)なら 6 フレームまでしか許されない。反応時間が 0.2〜0.3 秒(12〜18 フレーム)なら、遅れがなければ越えられる。
敵の攻撃を見てよけるときも同じである。「予備動作」は、反応時間とよけて範囲の外へ出るまでの時間に遅れを足した長さより長くする。
遅れの減らし方
ゲームの中の遅れは 1 フレームの処理の順番で決まる。入力をフレームの初めに読み、そのフレームの処理で使う。動かした後の状態は同じフレームのうちに描く。
// 1 フレームごとに、読む、動かす、描くの順に行う
function frame() {
const input = readInput(); // フレームの初めに入力を読む
update(state, input); // 読んだ入力をこのフレームの処理で使う。跳ぶ速さもここで与える
draw(state); // 動かした後の状態を描く
}
入力を読む前に動かす処理を呼んだり、押されたことを印に残すだけで次のフレームに跳ばせたりすると、そのたびに 1 フレーム遅れる。この順番を守れば、ゲームの中の遅れは入力を読むまで待つ 0〜1 フレームだけになる。
描いた絵を出すまでの待ちも増やさない。描き終えた絵をためておく枚数は、絵が途切れずに出せる範囲で少なくする。フレームレートも保つ。遅れはフレームの数で積み重なるので、1 フレームが長くなるとその分伸びる。毎秒 30 回の描画では 1 フレームが約 0.033 秒になり、3 フレームの遅れは 0.05 秒から 0.1 秒になる。
作ったゲームの遅れの測り方
遅れはゲームの中の分と画面に出るまでを含めた分に分けて測る。ゲームの中の分は、押下を読んだフレームとキャラクターの状態が最初に変わったフレームの番号をログに出せば数えられる。押下を読んだフレームのうちに状態が変われば、ゲームの中で足している遅れはない。
画面に出るまでを含めた遅れは、ボタンを押す指と画面を同じ映像に撮って数える。1 秒に 240 コマ撮れるスロー撮影なら、毎秒 60 回の更新の 1 フレームが 4 コマに映る。指がボタンを押し込んだコマから、画面の絵が最初に変わったコマまでを数える。押す瞬間がフレームの中のどこに来るかで 0〜1 フレームの差が出るので、10 回ほど測って平均する。
似た感じを生むほかの原因
「走り出しがもっさりしている」という感想は、入力遅延でも「加速と減速」の加速が長い場合でも出る。入力遅延では押してからしばらく画面が何も変わらない。加速が長い場合は押してすぐに動き出し、速くなるまでに時間がかかる。押した直後の数フレームをスロー再生や映像のコマ送りで見れば区別できる。
攻撃やジャンプの前に構えの動き(踏み込みや振りかぶり)を付けた場合も、押してから攻撃が出るまでに間がある。構えの最初の絵を押したフレームに出し、同時に音を鳴らせば、動き出しが遅くても押したことは伝わる。ただし、描画を待つ間や表示の処理による遅れは、構えの最初の絵にも同じだけかかる。押した瞬間の反応で埋められるのは、ゲームの側で動き出しを遅らせている分だけである。
キーボードのキーを押し続けると、文字を入力するときと同じく、1 回目の後に少し間をおいてから同じ入力が繰り返し届く。この繰り返しの入力でキャラクターを動かすと、押した瞬間に少し動いて一瞬止まり、それから動き続ける。この一瞬の止まりが遅れのように感じられる。キーが押されているかどうかを毎フレーム読んで動かす。
猶予の仕組みとの関係
「先行入力」と「コヨーテタイム」は、早すぎたり遅すぎたりした押下を捨てずに受け付ける仕組みで、押してから跳ぶまでの時間は縮めない。遅れがあると、足場の端で押したジャンプが足場を離れてから届くことがある。コヨーテタイムがなければこのジャンプは捨てられ、プレイヤーはボタンを押したのにジャンプしなかったと感じる。コヨーテタイムがあれば跳べるが、遅れの分だけ端より先の低い位置から跳ぶ。猶予の長さは遅れを減らしてから決める。遅れが変わると、同じ押し方でも押下が届く時刻が変わるからである。