Colyseusを使ったリアルタイムマルチプレイヤー
「create game」を選択し、新しいゲームを立ち上げます。床のいずれかをクリックしてオブジェクトを移動します。
このチュートリアルでは、次のことを学びます:
- Colyseusサーバーの設定
- サーバーとクライアント間での状態同期
- クライアントとサーバー間でのメッセージ交換
- マッチメイキング: ゲームの作成、参加、利用可能なゲームのリストアップ
必要なもの
開始する前に
前提知識
- 基本的なPlayCanvasの知識 (PlayCanvas開発者リソースを参照してください)
- 基本的なJavaScript/TypeScriptの理解 (TypeScript Handbookを参照してください)
- 基本的なNode.jsの理解 (Introduction to Node.jsを参照してください)
ソフトウェア要件
サーバーの作成
プレイヤーの状態を保持するために、基本的なサーバーをローカルに作成します。変更はクライアントと自動的に同期されます。
新しいColyseusサーバーを作成するには、コマンドラインから以下を実行します:
npm init colyseus-app ./playcanvas-demo-server
次にnpm start
を実行して、ローカルでサーバーを動かすことができるか確認しましょう。
cd playcanvas-demo-server
npm start
成功すれば、コマンドラインに以下のような出力が表示されます。
> my-app@1.0.0 start
> ts-node-dev --respawn --transpile-only src/index.ts
✅ development.env loaded.
✅ Express initialized
🏟 Your Colyseus App
⚔️ Listening on ws://localhost:2567
Colyseus JavaScript SDKのインポート
PlayCanvasにColyseus JavaScript SDKを追加する必要があります。
"PlayCanvasプロジェクトの設定"を使用して、"外部スクリプト"として追加できます。
**「メニュー」→ 「設定」**を開いてください:
設定パネルから、**「外部スクリプト」を展開し、「URL」**の数を増やします。
新しい**「URL」**フィールドに、CDNからColyseus JavaScript SDKを含めてください:
https://unpkg.com/colyseus.js@^0.15.0-preview.2/dist/colyseus.js
これにより、PlayCanvasスクリプトの Colyseus
JavaScript SDK を使用できます。
クライアント - サーバー接続の確立
新しいPlayCanvasスクリプトから、Colyseus.Client
インスタンスを作成しましょう(「新しいスクリプトの作成方法」を参照してください)。
このスクリプトは、「NetworkManager」という新しい空のエンティティにアタッチできます。
var NetworkManager = pc.createScript('networkManager');
NetworkManager.prototype.initialize = async function () {
//
// SDKをインスタンス化します
//(接続はまだ確立されていません)
//
this.app.colyseus = new Colyseus.Client("ws://localhost:2567");
//
// ルーム「my_room」を作成または参加するようにリクエストします
//(サーバーとの接続を確立します)
//
this.room = await this.app.colyseus.joinOrCreate("my_room");
}
ここで、ローカルの
ws://localhost:2567
エンドポイントを使用しています。他の人とオンラインでプレイするには、 サーバーをデプロイして、公共のインターネットを使用する必要があります。Glitchを使ってサーバーを公開することもできます。
PlayCanvasプロジェクトを**「起動」**すると、クライアントはサーバーと接続し、サーバーは必要に応じてmy_room
という部屋を作成します。
my_room
は、Colyseusサーバーのデフォルトのルーム識別子です。 arena.config.ts
ファイルでこの識別子を変更することができます。
クライアントがルームに正常に参加したことを意味するサーバーログに以下のメッセージが表示されます。
19U8WkmoK joined!
ルーム状態とスキーマ
Colyseusでは、共有データを Schema
構造を使用して定義します。
Schema
はColyseusからの特別なデータ型で、その変更/変異を_増分的に_エンコードする能力があります。エンコードとデコードのプロセスはフレームワークとそのSDKによって内部的に行われます。
ステート同期のループは次のようになります。
- 状態の変更(変異)は、サーバー→クライアント間で自動的に同期されます。
- クライアントは、ローカルの_読み取り専用_の
Schema
構造体にコールバックをアタッチすることで、状態の変化を観察し、それに対応することができます。 - クライアントは任意のメッセージをサーバー に送信することができます - それが何をするかはサーバーが決定します - そして状態を変化させることができます(ステップ**1.**に戻ります)
サーバーコードを編集して、サーバー側でのルーム状態を定義しましょう。
複数の Player
インスタンスを処理する必要があります。各 Player
には、 x
、y
、z
座標があります。
// MyRoomState.ts
import { MapSchema, Schema, type } from "@colyseus/schema";
export class Player extends Schema {
@type("number") x: number;
@type("number") y: number;
@type("number") z: number;
}
export class MyRoomState extends Schema {
@type({ map: Player }) players = new MapSchema<Player>();
}
スキーマ構造についてもご覧ください。
次に、サーバーサイドで onJoin()
メソッドを変更して、ルームとの新しい接続が確立されるたびに Player
インスタンスを作成します。
// MyRoom.ts
// ...
onJoin(client: Client, options: any) {
console.log(client.sessionId, "joined!");
// create Player instance
const player = new Player();
// place Player at a random position
const FLOOR_SIZE = 4;
player.x = -(FLOOR_SIZE/2) + (Math.random() * FLOOR_SIZE);
player.y = 1.031;
player.z = -(FLOOR_SIZE/2) + (Math.random() * FLOOR_SIZE);
// place player in the map of players by its sessionId
// (client.sessionId is unique per connection!)
this.state.players.set(client.sessionId, player);
}
// ...
}
また、クライアントが切断された場合には、プレイヤーをプレイヤーマップから削除するようにしましょう。
// MyRoom.ts
// ...
onLeave(client: Client, consented: boolean) {
console.log(client.sessionId, "left!");
this.state.players.delete(client.sessionId);
}
// ...
サーバーサイドで行った状態変化は、クライアントサイドで 観察できます 。次のセクションでやることです。
同期のためのシーンのセットアップ
このデモ用に、シーンに2つのオブジェクトを作成する必要があります。
- 床を表す Plane
- プレイヤーを表す Capsule。新しいプレイヤーがルームに参加するたびに複製します。
Planeの作成
スケール8
のPlaneを作成しましょう。