ターン制オンラインゲーム(カタン)の作り方:RPC

今回はターン制オンラインゲームの作り方について、カタンボードゲーム)を例に紹介していきます。

自作オンラインカタン

カタンボードゲーム)の特徴

カタンのようなボードゲームの場合、アクションゲームのような高速同期システムは不要なので、ある程度はシステムをシンプルに作れます。だたし、ボードゲームでは1試合が長く多人数でプレイするため、プレイヤーのネットワーク切断を考慮に入れた設計をしなければゲームが成立しにくくなります。切断後に再接続を行っても、不整合が発生しないように注意する必要があります。

ターン制オンラインゲームに必要な2つの仕組み

実は、ターン制オンラインゲームで必要なシステムを最もシンプルに考えると、シングルプレイヤーゲームに追加するべきものは以下の2点のみです。

1.ルームシステム

2.RPCシステム

ルームシステム

まずは、ルームシステムです。マッチングシステムと言ってもいいです。ボードゲームなので、ルーム作成が基準になるでしょう。二人プレイならランダムマッチでもいいでしょうね。役割としては、連絡先の交換と通信の中継です。ルームシステムには、基本的にどこぞのサーバーを利用することになります。Unityで有名なPUNでは、最大人数に制限はありますが無料でサーバーを利用できますし、後述のRPCシステムも一緒に付いてきます。(ただPUNはもうレガシーでFusionが後継のようです。)システム作れるならもちろんマイサーバーでもいいですし、どこかのクラウドサーバーを使ってもいいですね。

UI以外は同じものが見える

RPCシステム

RPCとは、Remote Procedure Callの略で、遠隔コード実行です。簡単に言うと、相手クライアントに所定のコードを(引数指定して)実行させるということです。セキュリティの文脈でもたまに出てきますね。もし所定コードのではなくて、任意コードを実行できる状態になってたら脆弱性なので注意しましょう。

基本的に、ターン制オンラインゲームではほぼ全ての関数コールをRPCを通して行うことになるでしょう。カタンを例に紹介します。

  1. ルーム作成(一人目・マスター)
  2. 二人目以降入場(全プレイヤーが自己情報をRPCで通達)
  3. ゲーム開始・地形生成(マスターがRPCで通達)
  4. ダイスロール(RPC)
  5. アクション(RPC)

こんな具合に、全プレイヤーで共有しておくべき情報は全てRPCで行います。ここで、RPCは遠隔コード実行ですが、自分に対しても発動させることでコードを省略できます。

ダイスロールでいうと、プレイヤーがダイスロールボタンを押すと、RPCのDiceRoll関数にダイス結果の引数が与えられて実行されます。自分を含む全プレイヤーが同じダイス値のDiceRoll関数を実行するので、その通りに各自アニメーションなどで演出しましょう。

地形生成では、RPCでMapGenerate関数に乱数シードを与えて実行します。全プレイヤーで共通の乱数シードを使えば、乱数を使う場面でも全プレイヤーに同一の結果がでます。全プレイヤーが共通の回数で乱数を使うようにすればかなりの通信を節約できます。

ゲーム進行など、一人が代表して行うべき処理もあります、RPC関数内にてif (MasterClient) {} で分岐して処理しましょう。

自分のカタンでは、以下図のようにRPCとゲームフローを作成しています。

カタンのコントロールフロー

上記のコントロールフローに載っている事柄はRPCで実行しています(他にもある)。ひとつひとつの操作で、割と細かくRPCを実行しています。他プレイヤーへの通達のためと、自分の切断・復帰時の行動ログとしての役割もあります。

回線切断・復帰対策

回線切断で落ちた後、同一ルームに帰ってきたときに必要な処理は同期です。ここで、全プレイヤー分の行動ログの保存は、全てのRPCコールを保存しておくことで実現できます。復帰してきたプレイヤーは、RPCコールを古いものから全て順番に実行すると、切断前とほぼ同じ状態に復元できます。

ここで、復元の注意点について紹介します。

UI操作であってもRPCで実行する

相手プレイヤーにYes/Noダイアログを出すRPCがあることはわかると思います。そして、その返答もRPCで行われることもわかると思いますが、ここで、ダイアログの消去も返答のRPC上で行いましょう。もしダイアログ消去をRPC上で行わなかった場合、復帰してきたときに返答済みのダイアログが残ってしまいます。カタンではコントロールフロー上の「パネル消し」が相当します。

Yes/Noダイアログ

アニメーションは全て投げっぱなしで

もしアニメーション終了を起点に関数を実行しようとしているのならそれはやめておきましょう。復帰時にRPCコールとアニメーション時間の整合性が取れなくなるためです。アニメーションは時間指定で実行しておき、次のアニメーションが来た場合は即座に終了状態までアニメーション遷移してから次のアニメーションにとりかかるようにしましょう。

カタンでは、ダイス値を決めてダイスが動き始めるRPCの後、アニメーションと同じ時間が経った後ダイス値に応じたアクションを行うRPCが送られます。それでもアニメーション中にダイスを回したプレイヤーが落ちると破綻するので、もうひと工夫必要です。

全プレイヤーで情報共有する

もしマスタークライアントのみが知っている情報などがある場合、マスタークライアントが落ちると情報が消えてしまいます。また、マスタークライアントが落ちるとマスターが移譲されるシステムが多いでしょう。マスター以外必要ないようなゲーム進行情報だとしてもできるだけ共有しておきましょう。

RPCログ