Caputchin
カスタムゲーム開発

セルフホストのゲームを作る

このチュートリアルの終わりまでに、本物の Caputchin のゲームを持っていることでしょう。ウィジェットのサンドボックス化された iframe で走り、ゲーム SDK を通じてホストと話し、サーバーが再実行できる トレース を報告する JavaScript のバンドルです。手動モード と違い、セルフホストのゲームは サイトキーをゲートできます。そのラウンドがリプレイ可能だからです。このチュートリアルはゲームの構築とホスティングを扱います。リプレイとゲート が、実際にゲートをオンにするアーティファクトを扱います。

これがどこに合うかは 自分のゲームを動かす を読んでください。静的な JavaScript ファイルをホストする場所(どの CDN か静的ホスト)と、あなたのページのウィジェットが必要です。

セルフホストのゲームの形

セルフホストのゲームは、次をする 1 つの自己完結した JavaScript のバンドルです:

  1. @caputchin/game-sdkregister 関数をインポートし、単一の ゲームファクトリー を登録します。
  2. ウィジェットがファクトリーに渡すコンテナに、それと一緒に渡される解決済みの言語、スキン、構成を使ってレンダリングします。
  3. ラウンドごとのシードのもとで決定論的にプレイし、プレイを トレース として記録します。
  4. 勝ったら、その記録とともに bridge.pass({ trace }) を呼びます。

ウィジェットはあなたのバンドルをその iframe に読み込み、あなたのファクトリーを呼びます。ファクトリーが呼ばれること 開始のシグナルです(待つべき別の開始イベントはありません)。

1. ゲームファクトリーを登録する

SDK をインストールし、あなたのファクトリーで register を一度呼びます。マニフェストは渡し ません。サーバーがプリセットを解決してファクトリーに渡します。

import { register } from "@caputchin/game-sdk";

register((container, bridge, ctx) => {
  // container — a DOM element inside the sandboxed iframe; render into it.
  // bridge    — push-only channel to the host (pass / error / setSize).
  // ctx       — the per-round context (seed + resolved locale/skin/config).

  const cleanup = startGame(container, bridge, ctx);

  // Return an optional cleanup function; the widget calls it on unmount.
  return cleanup;
});
npm install @caputchin/game-sdk

2. ラウンドごとのコンテキストを読む

ファクトリーの 3 つ目の引数 ctx は、この訪問者のためにゲームが必要とするすべてを運びます:

  • ctx.seed:ラウンドごとのリプレイのシード。すべてのランダム性をこれから導きます。 ゲームが検証済みのセッションの外で走るときは null。
  • ctx.locale:解決済みの言語オブジェクト:ctx.locale._lang に加えてあなたの翻訳された文字列キー。
  • ctx.skin:解決済みのスキンオブジェクト:ctx.skin._theme(常に lightdark)に加えてあなたの色とアセットのキー。
  • ctx.config:解決済みのゲームプレイの構成(または null)。

これらは、あなたのダッシュボードで定義した スキーマとプリセット から Caputchin が生む、この訪問者のための 解決済みのプリセット です。あなたは自分のキーをそれらから読み取ります。あなた自身は何も解決しません。

レイアウトに明示的なサイズが要るなら、最初の描画の後に一度ホストに伝えます:

bridge.setSize(360, 480);

3. プレイを決定論的にする

これがゲームをゲート可能にするルールです:ゲームは、シードとプレイヤーの入力が与えられれば決定論的でなければなりません。 結果に影響する何かのために Math.random() を呼んだり、壁時計を読んだりしないでください。すべてのランダムな選択を ctx.seed から導いてください。サーバーは、同じシードと同じ記録されたトレースのもとであなたのロジックを再実行し、同じ判定に達しなければなりません。

// A tiny seeded PRNG; feed it ctx.seed so the server reproduces the run.
function makeRng(seed) {
  let s = hashToInt(seed);
  return () => (s = (s * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff;
}

結果を駆動する入力(プレイヤーがどのターゲットを、どの順で当てたか、関係するならタイミングつき)を、プレイしながら記録します。その記録を文字列にシリアライズします。その文字列があなたのトレースです。

4. トレースとともに pass する

訪問者が勝ったら、ホストにトレースを渡します。pass は単一の trace 文字列を持つオブジェクトを取ります:

function onWin(traceString) {
  bridge.pass({ trace: traceString });
}

トレースは プラットフォームには不透明 です。それは、あなたのロジックがシードと組み合わさって結果を再現するような、あなたのゲームだけが定義する任意の文字列です。ゲームはここでスコアを報告しません。スコアリングは、もしあるなら、あなた自身の iframe 内の関心事です。

ブリッジの事実をあと 2 つ:

  • 最初の pass がラウンドを引き換えます。失敗または放棄されたラウンドは、単に pass呼ばない ことで知らされます(このブリッジに fail メソッドはありません)。
  • bridge.error({ code, message }) は、ゲーム内部の失敗(アセットの読み込み失敗、例外)のためで、プレイヤーの敗北のためではありません。それはホストに error イベントを表に出します。

ホストが pass を引き換えた後、それはウィジェットのトークンを解放し、あなたのバックエンドが そのトークンを検証 します。いつもどおりです。

5. サンドボックスのためにバンドルする

ウィジェットはちょうど 1 つのスクリプト URL を読み込むので、すべてがその単一のファイルに入っていなければなりません。1 つの自己完結した出力のために、バンドラー(esbuild、rollup、vite、webpack。どれでも)を設定してください:

  • アセット(スプライト、音、フォント)をデータ URL としてインライン化する。
  • コード分割を無効にする。
  • WASM を使うなら、base64 として埋め込み、バイトからインスタンス化する。

サンドボックスの中で 動かない パターン。iframe が不透明オリジンで厳格な CSP を持つからです:

  • パス相対の fetch('./sprite.png'):取得する元のパスがありません。
  • 動的な import('./chunk.js'):2 つ目の URL がブロックされます。
  • new Worker('./worker.js'):代わりにインラインの Blob URL から worker を生成してください。
  • 実行時の外部 CDN のフェッチ:connect-src がそれらをブロックします。

6. バンドルをホストし、ウィジェットをそれに向ける

ビルドしたファイルを、あなた自身の静的ホストから https 越しに提供し(ループバックの http はローカル開発で許可されます)、それからウィジェットをそれに向けます:

<caputchin-game
  sitekey="cpt_pub_..."
  game-src="https://cdn.example.com/my-game/game.js"
></caputchin-game>

ウィジェットはあなたのバンドルをそのサンドボックス化された iframe に読み込み、コンテキストとともにあなたのファクトリーを呼び、あなたの pass を待ちます。この時点でゲームは走って検証しますが、まだキーを ゲート することは許されていません。

7. ゲート可能にする

セルフホストのゲームを検証ゲートとして使うには、あと 2 つのことが必要で、どちらも次に扱います:

  1. ダッシュボードで カスタムゲームとして登録 し(あなたが選ぶ id)、コンテキストが本物の locale/skin/config を運ぶよう、そのフィールド スキーマとプリセット を定義します。
  2. リプレイアーティファクトをアップロード します。サーバーがシードとトレースから判定を再導出するために走らせる、あなたのゲームロジックのヘッドレスビルドです。リプレイとゲート を参照してください。

リプレイアーティファクトがアップロードされてセルフチェックを通るまで、カスタムゲームは リプレイ不可 と表示され、ゲートできません。

あわせて読む

このページの内容