← 投稿一覧

オンラインゲームでタイミングを合わせること

誰かとオンラインで "一緒に" 遊ぶというのは、思ったよりずっと複雑だ。見た目だけなら、お互いインターネットにつながっていて、データをやり取りすれば終わりに見える。でも実際はまったくそんなに単純ではない。難しくなる要素はいろいろあるけれど、その中でも一番大きいのは結局タイミングの問題だ。

普通は、自分が送ったデータは相手にすぐ届くと思いがちだ。ほとんど即時に届いているように感じるからだ。でも実際には "即時" ではなく、"即時に近い速さ" で届いているだけだ。

当たり前の話だけど、データも空間を移動しなければならない。そしてその速さには限界がある。どれだけ速くても光の速さは超えられないし、実際に使っている光ファイバーやネットワーク機器はそれより遅い。しかも経路も一直線ではない。

地図で見るとソウルからニューヨークまではだいたい11,000kmくらいある。これくらいの距離になると、往復の遅延は人が十分に体感できるレベルになる。現実には、光ファイバー内での伝搬速度の低下や経路の迂回、中継される機器の分まで入るので、200msを超えることも全然珍しくない。タイピングが速い人なら、その間に2文字くらい打ててしまう。

じゃあソウルからソウルなら大丈夫なのか。もちろんかなりマシではある。でも "同じ都市だからほぼ0に近い" というわけではない。普通のインターネット経路を通すと、通信会社の内部を回ったり、いくつもの機器を通ったりするので、だいたい数十msくらいは普通にかかる。ざっくり30msから50msくらいはよくある。一方で、AWSみたいに同じリージョン内でサーバー同士をまとめておけば、1桁msまで下がることもある。この差はかなり大きい。結局、オンラインゲームは自分が見ている相手の状態が "今この瞬間" ではなく、数十ms前の状態だという前提で作らないといけない。

自分が選んだ方法は、基準となる時間をひとつ置くやり方だった。ゲーム開始時刻を共通の基準にして、各クライアントでイベントが発生した時刻を一緒に記録する。自分が何かを選択したら、自分のクライアントでその時刻を打つ。相手も相手側のクライアントで発生した時刻を記録する。そして相手から届いたデータは、ただ到着した順番のまま処理するのではなく、そのイベントが実際に発生した時刻を基準にして、自分のイベントの間に差し込む。

こうすると、ネットワーク遅延があっても画面上の同期をずっと自然に見せられる。もちろん完璧ではない。たまに、自分が先に見たイベントよりも、実際には相手のイベントのほうが先に起きていたのに、転送が遅れてあとから届くことがある。

自分のゲームでは、これは致命的な問題ではなかった。ものすごく厳密な判定合わせが必要なジャンルでもないし、そういうケースの頻度も高くなかった。だからロジック全体を重くするより、見せ方の部分にだけ少し例外処理を入れる方を選んだ。この程度でも、ユーザー同士に "一緒に遊んでいる" という感覚を持たせるには十分だった。実際には数十ms前の相手と遊んでいるにもかかわらず。

投稿一覧