Asobiai SDK

オンライン対戦

AIGame.joinRoom で部屋に入るだけで、ほかのプレイヤーとリアルタイムに遊べます。サーバーは同じ部屋の人にメッセージを届けるだけなので、ゲームの判定はゲームの中(ホスト)で行ってください。

v2.4.0ゲームの中からは window.AIGame?.version で確認できます。更新履歴

まんがでわかる オンライン対戦
  1. アソビ「ひとりで遊ぶのもいいけど、だれかと対戦したいな」
  2. アイ「これを呼ぶだけで、オンライン対戦の部屋に入れるよ!」(AIGame.joinRoom())
  3. アソビ「合言葉で、友だちとも同じ部屋に入れるんだね」
  4. アソビ「勝った〜!」 アイ「もう一回!次は負けないよ」

使い方

js
// 空いている部屋に入る (クイックマッチ。2〜16人)
const room = await window.AIGame.joinRoom({ maxPlayers: 2 });
// 友だちと同じ部屋に入るなら合言葉を渡す: joinRoom({ maxPlayers: 2, code: "ABCD" })

room.me;        // 自分 { id, name }
room.players;   // 部屋にいる人 (自分も含む)
room.isHost;    // いちばん先に入った人が true (判定や開始はホストがするとよい)

room.on("join", (player) => { /* だれか入ってきた */ });
room.on("leave", (player) => { /* だれか抜けた */ });
room.on("message", (data, from) => { /* ほかの人から届いた */ });

room.send({ type: "move", x: 3, y: 1 });   // 自分以外の全員に送る
room.send({ type: "hello" }, player.id);    // 1人にだけ送る
room.send({ type: "team" }, [a.id, b.id]);  // 何人かにだけ送る (1通として数える)
room.leave();
  • Asobiai のゲームページで遊んでいるときだけ使えます(ほかのサイトへの埋め込みや、ファイルを直接開いたときは joinRoom がエラーになります)。
  • ログインしている人はアカウントの名前、ゲストは「ゲスト1234」のような名前になります。
  • 1部屋 16人まで、メッセージ1つ 16KB まで、1人あたり 毎秒60通まで(超えた分は届きません。何人かにまとめて送るのは1通です)。動きは毎フレームではなく、操作したときや1秒に数回だけ送るのがおすすめです。
  • ゲームの編集画面の「オンライン」で 対戦(相手と競う)か 多人数(みんなで遊ぶ・協力)かと 想定人数 を選ぶと、ゲームページとカードに「オンライン多人数・4〜8人」のように出ます。ゲーム一覧でも対戦・多人数で絞り込めます。
  • サーバーはメッセージを配るだけなので、ズルを完全には防げません。気軽な対戦向けです。

切断からの復帰・状態の保存・互換バージョン

スマホの画面ロックや回線の切り替えで通信が切れても、同じ席に自動で戻ります(タブを閉じたときは、すぐに退出したことになります)。室長は部屋の状態をサーバーに保存でき、室長が抜けたら次の室長が続きから進められます。人ごとの秘密(役割・手札など)は、その人と室長しか読めません。

js
// 部屋に入るときの設定
const room = await window.AIGame.joinRoom({
  maxPlayers: 8,
  code: "ABCD",
  protocol: "3",     // 通信の互換バージョン。違う人は同じ部屋に入れない (メッセージの形を変えたら上げる)
  reconnect: 90,     // 通信が切れても、この秒数は同じ席に自動で戻る (0〜300。ふだん60)
});

// 通信の様子
room.on("reconnecting", () => { /* 自分の通信が切れた。自動でつなぎ直し中 */ });
room.on("reconnected", () => { /* 戻れた。room.loadState() で最新の状態を読むとよい */ });
room.on("disconnected", (reason) => { /* 戻れなかった ("timeout" / "expired") */ });
room.on("away", (player) => { /* ほかの人の通信が切れた (席はまだある) */ });
room.on("back", (player) => { /* その人が戻ってきた */ });
room.on("leave", (player, reason) => { /* 席が空いた ("left" = 本人が出た / "timeout" = 戻らなかった) */ });
room.on("host", (player) => { /* 室長が変わった。自分なら loadState() して続きから進める */ });

// 状態の保存 (室長だけ)。players は人ごとの秘密 (その人と室長だけが読める)、host は室長だけ
await room.saveState({
  public: { round: 3, scores },
  host: { answer, deck },
  players: { [aliceId]: { role: "spy" }, [bobId]: { role: "detective" } },
});

// 読む: 自分の分 (mine) と全員向け (public)。室長なら host と players も
const { generation, public: pub, mine, host } = await room.loadState();
  • 状態は 256KB まで、保存は部屋ごとに 毎秒5回まで。全員が抜けても 10分は残ります。generation(世代)が今より古い保存は断られるので、古い室長が状態を巻き戻すことはありません。
  • 室長のブラウザがゲームを進める仕組みなので、室長の端末からは秘密を完全には隠せません。気軽な対戦・協力向けです。
  • 部屋に入っているあいだに送ったスコアは、ひとりのときとは別の「オンライン」のランキングに入ります(ランキングのページを見てください)。
AIに伝えるときの文面

オンライン対戦にしてください。window.AIGame.joinRoom({ maxPlayers: 2 }) で部屋に入り、room.send(データ) で相手に送り、room.on("message", (data, from) => …) で受け取ります。room.on("join") と room.on("leave") で人の出入りがわかります。ゲームの開始や判定は room.isHost が true の人がしてください。合言葉で友だちと遊べるよう joinRoom({ maxPlayers: 2, code }) にも対応してください。送るのは操作や状態の変化だけにして、毎フレーム送らないでください。公開するときは、遊び方ごとの人数を online_modes に入れてください (例: 協力2〜8人と対戦4〜8人なら [{"mode":"party","min":2,"max":8},{"mode":"versus","min":4,"max":8}])。通信が切れても同じ席に戻れるので、room.on("reconnected") と room.on("host") で room.loadState() を呼んで続きから進め、室長は進行のたびに room.saveState({ public, host, players }) で状態を保存してください。メッセージの形を変えたら joinRoom の protocol を上げてください。公開したら check_game でエラーや読み込めない画像がないか確かめてください。