メインコンテンツまでスキップ

マルチプレイヤー

複数の人で、1 つのシーンを同時に共有できます。メッセージを送り、値を共有し、全員向けにオブジェクトを生成し、ほかのプレイヤーをなめらかに動かしましょう。

ここで紹介する呼び出しは、プロジェクトでマルチプレイヤーがオンになっていて、しかもルームが開いているときだけ動きます。それ以外のときは何もしません。そのため、同じスクリプトが 1 人用のプレビューでもそのまま動き、2 つのバージョンを用意する必要はありません。

ルームにいる人​

ctx.net.id;        // この参加者の ID
ctx.net.peers(); // 今ルームにいる全員
ctx.net.onJoin((peer) => {});
ctx.net.onLeave((peer) => {});

自動で同期されるもの​

自動で同期されるのは、shared に設定した物理ボディの位置だけです。それ以外は、自分で送ります。

これは意図した動作です。木箱、ドア、ボールは、全員に同じ場所に見える 1 つのオブジェクトであるべきです。一方、プレイヤーキャラクターは共有してはいけません。共有すると、1 人が歩いたときに全員のアバターが動いてしまいます。→ 所有の設定

メッセージ​

メッセージは、誰かが得点した、ラウンドが始まった、ドアが開いた、といった出来事を伝えるときに使います。

ctx.net.send('score', { points: 10 });
ctx.net.on('score', ({ from, data }) => {
/* … */
});

メッセージは、自分以外の全員に届きます。届いたという確認は返ってきません。

共有ステート​

全員で同じ値を持つ必要があるときは、共有ステートを使います。シンプルなマップで、全員がそのコピーを持ちます。2 人が同じキーに書き込んだ場合は、最後の書き込みが残ります。

ctx.net.state.set(ctx.net.id, { name, colour, ready: true });
ctx.net.state.get(somePeerId);
ctx.net.state.all();
ctx.net.state.on(ctx.net.id, (value) => {});

プレイヤーごとに値を持たせるときは、ctx.net.id をキーにします。各自が自分の項目に書き込み、ほかの人の項目を読みます。

全員向けに生成する​

const id = ctx.net.spawn(props.bullet, { position, rotation });
ctx.net.despawn(id);

ID はすぐに受け取れますが、オブジェクトが表示されるのは少しあとです。ID は全員で同じです。

オブジェクトを削除できるのは、それを生成した人だけです。誰かがルームを抜けると、その人が生成したオブジェクトも削除されます。

ほかのプレイヤーをなめらかに動かす​

ここはいちばん失敗しやすいところなので、専用の呼び出しを用意しています。

ctx.net.follow(otherPlayerObject, { position, rotation });
ctx.net.unfollow(otherPlayerObject);

位置を受け取るたびに follow を呼び出します。1 秒に 10〜20 回が普通です。あとはオブジェクトが、最新の位置から少し遅れて、なめらかに動きます。

同じ位置で follow をもう一度呼び出しても、負荷はかかりません。そのため、手元にある最新の位置で毎フレーム呼び出してもかまいません。

受け取った位置をトランスフォームに直接書き込まないでください

更新が届く頻度はフレームよりずっと少ないので、オブジェクトは止まっては跳ぶ、を繰り返します。ほかのプレイヤーが、なめらかに歩かずにカクカクと進んでいるように見えます。最新の位置に向かってゆっくり近づける方法でも解決しません。更新と更新の間には新しい目標がないので、オブジェクトは止まってから急に動き出してしまいます。

うまくいく構成​

ゼロからつくるなら、次の構成でたいていのことはまかなえます。

  • 各プレイヤーは自分のキャラクターを操作します。キャラクターは local のボディで、本人の入力で動きます。
  • 自分の位置は、net.state かメッセージで、1 秒に 10〜20 回送ります。
  • ほかの人のキャラクターは follow で動かします。
  • ワールドのオブジェクトは shared のボディにします。同期は物理が自動で行います。
  • スコアとラウンドのステートは net.state に置きます。書き込むのは、その出来事を担当している人です。

次へ: トラブルシューティング — うまく動かないときの対処法。