\カタカタカタカタ/

↑一人でマルチプレイをするマイケルの図

マイケル
いや〜楽しいな〜〜〜


エレキベア
何してるクマ??

マイケル
よくぞ聞いてくれたねエレキベア

マイケル
実は前作っていたゲームにPUN2を導入して
マルチプレイができるようにしたのさ!
マルチプレイができるようにしたのさ!

エレキベア
そういえばPUN2の導入についても勉強したクマね
※前回作ったゲームの記事について
【Unity】オンライン3Dアクションゲームの作り方をまとめる! (前編)
※PUN2導入と基本的な使い方について
【PUN2】ネットワーク管理にPhotonを使ってみる 〜導入からルーム・ロビー管理まで〜

マイケル
そう、あれから
エレキベアを倒すゲームに改造したり
PUN2を導入してネットワーク対応したり
いろいろ進んだんだよ!
エレキベアを倒すゲームに改造したり
PUN2を導入してネットワーク対応したり
いろいろ進んだんだよ!
↑プレイヤーをリンチするエレキベア

エレキベア
我ながら恐ろしい絵クマ

マイケル
おいてけぼりのドラゴンがかわいそうだぜ

マイケル
そんな感じで、進めてた参考書の路線は外してしまったわけだけど、
ネットワーク対戦までできるようになるという目標はクリアしたので
これからはオリジナルゲーム作成をしていくぜ!
ネットワーク対戦までできるようになるという目標はクリアしたので
これからはオリジナルゲーム作成をしていくぜ!

エレキベア
ついにオリジナルに踏み出すクマね

マイケル
とりあえず今回は一番苦労したPUN2を使ったマルチプレイ化についてメモとして残しておくよ!

エレキベア
燃えてきたクマ〜〜
PUN2を使ったマルチプレイゲーム化

マイケル
すでに一人用で作ったゲームにPUN2を導入する程で、
大きく以下の手順について解説していきます!
大きく以下の手順について解説していきます!
・ ネットワーク上のオブジェクト作成と破棄
・ RPCでの呼び出し
・ 同期処理の設定
・ コールバックについて

エレキベア
やったるクマ〜〜〜〜
ネットワーク上のオブジェクト作成と破棄

マイケル
まずはネットワーク上にオブジェクトを生成しないといけないですね・・・

マイケル
生成方法については、オブジェクトにPhotonViewスクリプトをアタッチして、
通常使用する「Instantiate()」メソッドをPhotonNetworkクラスから呼び出すようにすればOKです!
通常使用する「Instantiate()」メソッドをPhotonNetworkクラスから呼び出すようにすればOKです!
// プレイヤーを登場させる
if (player == null && networkManager.isClosed)
{
Vector3 shiftVector = new Vector3(PhotonNetwork.CountOfPlayers * 1.5f, 0, 0);
player = PhotonNetwork.Instantiate("player", startPoint.position + shiftVector, startPoint.rotation, 0) as GameObject;
・・・略・・・
}
↑PhotonViewスクリプトのアタッチ

マイケル
ちなみにオブジェクトの破棄も同様に、「Destroy()」メソッド をPhotonNetworkから呼び出すようにすればOKです!

エレキベア
これはクマでもわかるクマ
RPCでの呼び出し

マイケル
次にメソッドの呼び出し方についてだ!
ネットワーク上にオブジェクトが複数あるというのは下の図のような状態になる。
ネットワーク上にオブジェクトが複数あるというのは下の図のような状態になる。

マイケル
これまで一人で完結していたのが増えるわけだから、
全員の処理を呼び出したり、特定のユーザの処理を呼び出したりなど、
処理の実行範囲を指定するようにしないといけないんだ!
全員の処理を呼び出したり、特定のユーザの処理を呼び出したりなど、
処理の実行範囲を指定するようにしないといけないんだ!

エレキベア
複数プレイヤーいることを考慮して実行しないといけないクマね

マイケル
その通り!
そこで使うのがRPCという機能で、これを使ってメソッド呼び出しを指定することでメソッドの呼び出し範囲を指定することができるんだ!
そこで使うのがRPCという機能で、これを使ってメソッド呼び出しを指定することでメソッドの呼び出し範囲を指定することができるんだ!

マイケル
ここではよく使う3パターンについて紹介するよ!
1. 自分含めた全ユーザの処理を実行する場合


マイケル
まずはゲームクリアの通知など、全体に対して送りたい時の呼び方について!
public void GameEnd()
{
・・・略・・・
// 全てのユーザに結果を送信する
photonView.RPC("GameEndOnNetwork", RpcTarget.AllBuffered, winPlayerName);
}
}
[PunRPC]
void GameEndOnNetwork(string winPlayerName)
{
・・・略・・・
}

マイケル
上記のように引数に呼び出したいメソッド名と「RpcTarget.AllBuffered」を指定してRPCメソッドを呼び出すと全体に送ることができます!

マイケル
RPCで呼び出すメソッドには「[PunRPC]」を付けないといけないので注意してください。

エレキベア
これがRPCでの呼び出し方なのクマね
2. オーナーの処理のみを実行する場合


マイケル
次にオーナーのメソッドのみを呼び出したい場合の呼び方です!

マイケル
敵のオブジェクトなどは全体で一つのオブジェクトになるため、代表でオーナーが作成するというのが一般的です。
そのような、共通のオブジェクトに対して処理を行う場合に使います!
そのような、共通のオブジェクトに対して処理を行う場合に使います!
void Damage(AttackArea.AttackInfo attackInfo)
{
・・・略・・・
// 管理オブジェクトのDamageMineを呼び出す
if (photonView.IsMine)
{
DamageMine(attackInfo.attackPower);
} else
{
photonView.RPC("DamageMine", photonView.Owner, attackInfo.attackPower);
}
}
[PunRPC]
void DamageMine(int damage)
{
status.HP -= damage;
if (status.HP <= 0)
{
status.HP = 0;
// 体力0なので死亡ステートへ
ChangeState(State.Died);
}
}

マイケル
上記のようにphotonView.Ownerを指定して呼び出します。
ちなみに「photonView.IsMine」では自身の作成したオブジェクトかを判定しています!
ちなみに「photonView.IsMine」では自身の作成したオブジェクトかを判定しています!

エレキベア
自身のオブジェクトはRPCを使わずにメソッドを呼び出すクマね
3. 特定のプレイヤーの処理のみ実行する場合


マイケル
そして最後に特定のユーザにの処理のみ呼び出す場合です。
// 他のプレイヤーが接続してきたらサーバのコンピュータで呼び出される
public override void OnPlayerEnteredRoom(Player player)
{
photonView.RPC("SetRemainTime", player, timeRemaining);
}
[PunRPC]
void SetRemainTime(float time)
{
timeRemaining = time;
}

マイケル
こちらは引数としてPlayerを渡すことで指定します!
また、上記の処理内容はプレイヤーがルームに入室した差異に呼ばれるコールバック処理になります。
また、上記の処理内容はプレイヤーがルームに入室した差異に呼ばれるコールバック処理になります。

マイケル
以上、よく使う3つのパターンについて記述しましたが、
RPCに指定するターゲットは上記以外にも複数あるので気になる方はリファレンスを参照してください。
RPCに指定するターゲットは上記以外にも複数あるので気になる方はリファレンスを参照してください。
[参考]
Photon Unity Networking 2 Public API

エレキベア
たくさんあってわからんクマ
同期処理の設定

マイケル
次に同期の設定をしていきます。
オブジェクトを作成しただけでは自分以外のプレイヤーの動き等が反映されないため、
PhotonViewの「Observed Components」に同期する情報を設定することで同期します!
オブジェクトを作成しただけでは自分以外のプレイヤーの動き等が反映されないため、
PhotonViewの「Observed Components」に同期する情報を設定することで同期します!


マイケル
位置を同期させたいだけなら上記の様にTransformを指定してあげるだけでいいのですが、自身のスクリプト等を同期させたい場合には同期するスクリプトを作成してあげなければいけません。

マイケル
下記は一例で「CharacterStatus.cs」の変数を同期させるスクリプトです。
作成したスクリプトを「Observed Components」に指定してあげることで同期が可能になりなります!
作成したスクリプトを「Observed Components」に指定してあげることで同期が可能になりなります!
// IPunObservableインターフェイスを実装
public class CharaSynchronizer : MonoBehaviour, IPunObservable
{
// キャラクターステータス
CharacterStatus status;
// 同期処理
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
// 送信
// 位置と向き
Vector3 pos = transform.position;
Quaternion rot = transform.rotation;
stream.Serialize(ref pos);
stream.Serialize(ref rot);
if (status != null)
{
// CharacterStatus: HP
int hp = status.HP;
stream.Serialize(ref hp);
}
}
else
{
// 受信
// 位置と向き
stream.Serialize(ref position);
stream.Serialize(ref rotation);
if (status != null)
{
// CharacterStatus: HP
int hp = 0;
stream.Serialize(ref hp);
status.HP = hp;
}
}
}
}
↑作成したスクリプトを設定

マイケル
これでスクリプトの内容も同期する様になるはずです!

エレキベア
いい感じに同期するクマ〜〜〜〜〜
コールバックについて

マイケル
最後はコールバック処理について!
特定の処理をしたあとのコールバック処理を行うには、それぞれにあったクラスを継承しなければいけません。
特定の処理をしたあとのコールバック処理を行うには、それぞれにあったクラスを継承しなければいけません。

エレキベア
導入のときにもいろいろコールバック処理があったクマ

マイケル
それと同じ様なイメージだよ!
ここでは例として二つ紹介します!
ここでは例として二つ紹介します!
・クライアントのルーム入室時のコールバック処理
継承クラス: MonoBehaviourPunCallbacks
コールバックメソッド: OnPlayerEnteredRoom()
public class GameRuleCtrl : MonoBehaviourPunCallbacks
{
・・・略・・・
// 他のプレイヤーが接続してきたらサーバのコンピュータで呼び出される
public override void OnPlayerEnteredRoom(Player player)
{
photonView.RPC("SetRemainTime", player, timeRemaining);
}
}
・ネットワークオブジェクト作成時のコールバック処理
継承クラス: IPunInstantiateMagicCallback
コールバックメソッド: OnPhotonInstantiate()
public class DropItem : MonoBehaviour, IPunInstantiateMagicCallback
{
・・・略・・・
// ネットワーク越しにインスタンス生成された時に呼び出される
void IPunInstantiateMagicCallback.OnPhotonInstantiate(PhotonMessageInfo info)
{
if (!info.photonView.IsMine)
{
Destroy(GetComponent<Rigidbody>());
}
}
}

マイケル
継承クラスを間違えただけでほんとに何も起こらなくなるので気をつけてください!

マイケル
また、その他のコールバックの処理については下記リファレンスを参照してください。
[参考]
Photon Unity Networking Photon.PunBehaviour Class Reference

エレキベア
これもいろいろ種類がありすぎてわからんクマ
おわりに

マイケル
以上、マルチプレイ実装のための簡単な機能説明でしたがいかがだったでしょうか。

エレキベア
少しはネットワーク処理に詳しくなった気がするクマ

マイケル
俺もネットワークは全然詳しくないけど、
使ってたら慣れてくるし、マルチプレイで遊べる様になるのはすごく楽しいので
みなさんもまずは是非使ってみてください!
使ってたら慣れてくるし、マルチプレイで遊べる様になるのはすごく楽しいので
みなさんもまずは是非使ってみてください!

エレキベア
拙者も自作ゲームでマルチプレイしてみたいクマね

マイケル
それじゃ俺の作ったゲームで対戦しようぜ!

エレキベア
自分を倒すのはコリゴリクマ・・・
【Unity + PUN2】オンライン3Dアクションゲームの作り方をまとめる! (後編) 〜完〜
コメント