日付をタネにして地形を作る — 「今日のコース」の仕組み

公開: 2026年10月25日 ・ 筆者: Toshi(開発者)

バズ走の地形は毎日0時に変わり、その日のうちは世界中の全員が同じコースを走ります。これは「サーバーがその日の地形を配っている」のではなく、各自の端末が同じ計算式で同じ地形を作っているだけです。この記事では、その計算の中身を順に説明します。

なぜ完全ランダムをやめたのか

初期版は Math.random() で穴や壁を置いていました。テストを重ねるうちに、同じ腕前でも地形の引き次第でスコアが数倍変わることが分かり、「記録を比べても意味がない」という根本的な問題に行き当たりました。ランゲームの楽しさの半分は「友達より遠くまで行った」という比較にあるので、ここは譲れません。

そこで、乱数の種(シード)を日付から作る方式に切り替えました。種が同じなら、乱数列も同じ。乱数列が同じなら、地形も同じ。これで「今日のコース」が成立します。

種の作り方

種は日本時間の日付を YYYYMMDD 形式の整数にしたものです(例:2026年10月25日なら 20261025)。ランキングAPIの seed パラメータもこの値をそのまま使っていて、「今日のTOP10」は同じ種で走った記録だけを集めています。

ただし、日付の整数をそのまま種にすると、隣り合う日の種はほとんど同じビット列になり、乱数生成器によっては似た地形が続くことがあります。そこで種には定数 0x9E3779B9(黄金比に由来する値で、ハッシュの撹拌によく使われます)をXORしてから渡しています。これだけで連続する日の地形がはっきり変わります。

乱数生成器は mulberry32

JavaScriptの Math.random() は種を指定できないため、自前の擬似乱数が必要です。採用したのは mulberry32 という32ビットの生成器で、コードは数行、速度も十分、そして何よりどのブラウザでも同じ結果が出ます。ゲームの公平性にとって「環境によらず同じ列が出る」ことは、乱数の統計的な質よりも重要でした。

function mulberry32(a){
  return function(){
    a |= 0; a = a + 0x6D2B79F5 | 0;
    let t = Math.imul(a ^ a >>> 15, 1 | a);
    t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
}
let rand = mulberry32(DAILY_SEED ^ 0x9E3779B9);

ゲームをリスタートするたびに rand を同じ種で作り直しています。こうすることで、1日のうちは何回走っても1回目とまったく同じ地形になり、「穴の位置を覚える」という上達の道筋が生まれます。

1区画ごとに乱数を何回引くか

地形は画面の右端で少しずつ生成されます。1区画を作るたびに、乱数を決まった回数・決まった順序で引きます。

乱数用途
gapRollこの区画に穴を作るかどうか
gapSize穴の幅(距離が伸びるほど上限が広がる)
lvlRoll地面の高さを変えるかどうか
wRoll壁を置くかどうか・高さ
itemRoll / itemYRoll★(三段ジャンプ解禁)を出すか・その高さ

ここで大事なのは「使わない乱数も必ず引く」ことです。たとえば穴を作らない区画でも gapSize を引いておかないと、分岐によって乱数の消費数が変わり、同じ種でも地形がずれてしまいます。条件分岐の前に必要な乱数をすべて引く、というのが決定性を保つコツです。

速度と加速の設計値

地形が同じでも、速度の変化が端末によって違えば公平になりません。速度は時間ではなく走った距離で決まるようにしています。

項目値意味
初速340 px/秒50px = 1m なので約6.8m/秒
最高速度1,150 px/秒約23m/秒。ランキングAPIの不正判定にも同じ値を使用
加速(通常)9ゆっくり速くなる
加速(300m以降)16いわゆる「300mの壁」。ここから判断時間が短くなる

フレームレートが違う端末でも結果が揃うよう、1フレームの経過時間(dt)を掛けて更新し、タブが裏に回ったときはdtに上限を設けて「一気に進む」ことを防いでいます。

ランキングとの整合

ランキングに記録を送るとき、端末は distance(距離)と一緒に seed(その日の種)と elapsed(プレイ時間)を送ります。サーバー側では「最高速度23m/秒 × プレイ時間」を超える距離や、理論上の上限20,000mを超える申告を拒否しています。地形生成とスピードの設計値がサーバーの検証値と一致しているからこそできる、簡単で効果的な不正対策です。

この方式の副産物

次の記事:画像を1枚も使わずに世界を描く — Canvasだけの落書きグラフィック

⚽ いますぐ走る