敵NPCの出現処理をホストに任せる
目次
概要
敵の出現処理を「ホスト」だけが行なうように変更する
「ホスト」がどのクライアントであっても、敵の最大出現数を一定に保つ
なぜ「敵キャラクタの動作」に不一致が出てしまったのか?
「オフラインゲーム開発」と「オンラインゲーム開発」の、もう1つの大きな障壁にぶつかりました。
なぜ「敵キャラクタの動作」において不一致が発生してしまったのでしょうか?
答えは先のサンプルを見ればわかる通り、「各々のクライアントで、各々の敵キャラクタの挙動ロジックを動かしているから」です。
まったく同期させていなければ一致するわけがありませんよね。
敵キャラクタやNPCを同期させるための一般的な手法として、以下のようなものがあります。
1. サーバが管理し、サーバ側で動かした結果を各クライアントに反映させる。
一般的な、MMO/MOBAタイプのゲームであればこの手法が用いられる。
2. ルーム内の誰か1クライアントが管理し、その1クライアントが動かした結果を他のクライアントに反映させる。
MOを始めとしたP2P型ゲームであればこの手法が用いられる。
MUNは完全なクライアントサイドの通信エンジンであるため、1. の手法を取るのは相応のテクニックを要します。
そのため、今回はこのうち 2. の手法を取ることにします。
ネットワークゲーム上の「管理役」として、ホストを利用する
クライアントサイドの通信の場合、非プレイヤーの挙動については「ホスト」に任せるのが一般的です。
現在のサンプルには、この「ホストに任せる」処理が入っていませんので、これを導入していきましょう。
ホストとは、ルームの「管理役」として定義されるもので、
ルーム内のクライアントのうちのいずれか1つのクライアントが、サーバより選ばれます。
(原則的に、ルーム作成者が最初のホストとして選ばれます。)
ホストの役割には、非プレイヤーの挙動管理の他に、
ゲームルールの監視(制限時間の管理、スコアの管理、勝敗の管理、etc...)などがあります。
敵の出現処理を「ホスト」だけが行なうように変更する▲
NPC_Spawner で管理している「Spawn」を開く
まずは Hierarchy から NPC_Spawner をクリックします。
NPC_Spawner に含まれている Spawner のスクリプトを、ダブルクリックして開きます。
該当するクラスの Update() について、MonobitEngine.MonobitNetwork.isHost による実行可否判定を入れる
Spawner の 17 行目から、以下のコードを記述します。
// ホスト以外は処理をしない
if( !MonobitEngine.MonobitNetwork.isHost )
{
return;
}
MonobitEngine.MonobitNetwork.isHost が、「自身がホストか?」を示す、ホスト権限のフラグです。
ここでは単純に、「ホスト権限を持たないクライアントでは、Update() を処理させない」というロジックを適用させます。
「ホスト」がどのクライアントであっても、敵の最大出現数を一定に保つ▲
敵出現に関し、ホスト側で管理するようにロジックを組みなおす
敵の出現数に関しても、ロジックを組みなおす必要があります。
というのも、先ほどのサンプルまでは分かりづらかったかも知れませんが、
各々のクライアントでネットワーク越しに登場させていたため、ルームに入室しているプレイヤー人数に応じて、敵キャラクタが増えています。
1クライアントにつき50体表示させるので、ルーム内のプレイヤー人数×50体のテディベアが襲ってきていました。
これはこれでゲームバランスが取れるのかもしれませんが、意図した動きではないので修正しましょう。
該当するクラスの Update() で実行している newNPC に対する設定箇所を変更する
まず、Spawner.cs の 35 行目~37行目(以下の赤枠部分)について、コードから削除します。
この設定箇所については、
・NPC_Spawner の子として NPC を生成する(位置情報の相対位置が NPC_Spawner に依存する)
・NPC をアクティブにする
という処理ですが、これは MonobitNetwork.isHost 以外のユーザーに対しても、
プレハブが Instantiate された後で適用しなければなりません。
先の条件分岐で処理が除外されてしまいますので、ここで設定するのを断念し、
別の場所に定義するようにします。
全てのクライアントでキャラクタの数を同期する
このままではホスト以外、m_CurrentSpawnCount が更新されなくなってしまいますので、更に調整を加えます。
Spawner.cs の 15 行目付近に以下の Start() メソッドを定義し追記してください。
public void Start()
{
m_CurrentSpawnCount = transform.GetChild(0).childCount;
}
NPCオブジェクトの生成場所(親オブジェクト)に登録されている子オブジェクトの数を m_CurrentSpawnCount に代入します。
この上で更に、Spawner.cs の 28行目付近に記述されている「出現条件」を以下のように変更します。
if (m_IsSpawning && transform.GetChild(0).childCount < m_CurrentSpawnCount + SpawnCount)
NPCの出現個数を SpawnCount に設定した値を超えないよう、
ネットワーク越しに作成されたオブジェクトに対してもきちんと同期するように制御します。
ネットワークで同期するのは(GetChildを使用するよりも)全体的な高負荷や遅延が発生しますので、こういったテクニックを用います。