Photon Unity Networking 2(PUN2) とは
Unity でマルチプレイが簡単にできるようになるアセット。
最近バージョン2.6が出て、以前の PUN とはだいぶ勝手が違うものになっていたので、勉強がてら記事に残しておきます。
動作環境
- Unity2017.4.19f1
- PUN 2 - FREE
それぞれダウンロードしてインポートしておいてください。
また PUN2 のセットアップも完了させておいてください。
シーンのセットアップ
ゲームオブジェクトのオーナーが誰にあるのか一目でわかるシーンを作りましょう。
今回は赤い Plane の上に白い Cube を1個だけ置き、これを操作できるか否かでオーナー権限の確認とします。
また MainCamera はこれらの直上に配置して Cube が動いているか確認しやすくします。
シーン完成予想図はこんな感じです。
Game ウィンドウには Cube の現在のオーナーID、前回のオーナーID、自分のID、そしてオーナー権限を取得するボタンを配置します。
Game ウィンドウ完成予想図はこんな感じです。
Cube を操作できるようにする
簡単なスクリプトを Cube につけて移動できるようにします。
今回は Cube に Rigidbody をアタッチして、その Velocity を変えることで移動しているように見せます。
public class KeyToMove : MonoBehaviour
{
[SerializeField] private Rigidbody _rigidbody;
[SerializeField] private int _speed = 100;
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.RightArrow))
{
_rigidbody.velocity = Vector3.right * _speed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
_rigidbody.velocity = Vector3.left * _speed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
_rigidbody.velocity = Vector3.forward * _speed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.DownArrow))
{
_rigidbody.velocity = Vector3.back * _speed * Time.deltaTime;
}
}
}
このスクリプトを Cube にアタッチすれば、矢印キーで操作できるようになります。
キューブがコロコロ pic.twitter.com/1eMayiWgM1
— karukaru👑@白魔導技士 (@_karukaru_) 2019年1月31日
PUN2 に接続して同期する
PUN2 のネットワークに接続して Cube の位置や回転、速度などを同期しましょう。
まず Cube に PhotonView 、 PhotonTransformView 、 PhotonRigidbodyView をアタッチします。
そして PhotonView の ObservedComponents に PhotonTransformView と PhotonRigidbodyView を追加します。
次に Cube のオーナー権限を要求されたときにどのような挙動をとるか指定します。
これは PhotonView の Owner にあるプルダウンから選択できます。
今回の場合は、要求を受けたら即オーナー権限を渡して通知を受け取りたいので、Takeover を指定します。
現在 Cube にアタッチされているスクリプトはこんな感じになっているかと思います。
これで Cube の同期設定は完了しましたが、肝心のPUN2に接続するスクリプトをまだ書いていません。
PUN2 の公式ドキュメントなどを見ながらさらっと書いてしまいましょう。
ちなみにですが、PUN2 で新しくなったAPIリファレンスも存在するので活用しましょう。
public class PUN2LoginEvent : MonoBehaviourPunCallbacks
{
[SerializeField] private Text _myId;
// Use this for initialization
void Start()
{
_myId.text = "";
PhotonNetwork.ConnectUsingSettings();
}
public override void OnConnectedToMaster()
{
Debug.Log("Master Connected!");
PhotonNetwork.JoinOrCreateRoom("ROOM1", null, null);
}
public override void OnCreatedRoom()
{
Debug.Log("Create Room!");
}
public override void OnJoinedRoom()
{
Debug.Log("Join Room!");
//プレイヤーナンバー設定
//オーナー譲渡したときにPlayer情報がすべてnullになってしまって判別が困難なのを防ぐため
int id = PhotonNetwork.CountOfPlayers;
PhotonNetwork.LocalPlayer.SetPlayerNumber(id);
_myId.text = id.ToString();
}
}
このスクリプトを適当なオブジェクトにアタッチすることで PUN2 のネットワークに接続することができます。
オーナー権限を要求されたときの処理を書く
次に Cube のオーナー権限を要求されたときの処理を書きます。
ここが旧バージョンの PUN と大きく違っている点で、PUN2 ではコールバックがすべてインターフェイスで宣言されています。
そのためコールバックを受け取りたいクラスでは、対象のコールバックが宣言されているインターフェイスを継承しつつクラス内で実装する必要があります。
新しく実装されたコールバックインターフェイスの一覧は先ほどの公式ドキュメントに載っています。
今回はオブジェクトのオーナー権限を要求したときのコールバックが欲しい為、 IPunOwnershipCallbacks
を継承します。
このインターフェイスでは void OnOwnershipRequest(PhotonView targetView, Player requestingPlayer)
と void OnOwnershipTransfered(PhotonView targetView, Player previousOwner)
の実装を要求しているため、空でもいいのでとにかく実装してあげます。
public class PUN2OwnershipEvent : MonoBehaviourPunCallbacks, IPunOwnershipCallbacks
{
[SerializeField] private PhotonView _photonView;
[SerializeField] private Text _currentOwnerText;
[SerializeField] private Text _previousOwnerText;
private bool _initializedText = false;
// Use this for initialization
void Start()
{
_currentOwnerText.text = "";
_previousOwnerText.text = "";
}
// Update is called once per frame
void Update()
{
if (!_initializedText && PhotonNetwork.InRoom)
{
_currentOwnerText.text = _photonView.Owner.GetPlayerNumber().ToString();
_initializedText = true;
}
}
//PhotonView.OwnershipTransfer == OwnershipOption.Request の時に呼ばれる
public void OnOwnershipRequest(PhotonView targetView, Player requestingPlayer)
{
}
//PhotonView.OwnershipTransfer == OwnershipOption.Takeover の時に呼ばれる
public void OnOwnershipTransfered(PhotonView targetView, Player previousOwner)
{
_currentOwnerText.text = _photonView.Owner.GetPlayerNumber().ToString();
_previousOwnerText.text = previousOwner.GetPlayerNumber().ToString();
}
}
これでオーナー権限を要求されたときの処理が書けました。
オーナー権限を要求する処理を書く
最後に Cube のオーナー権限を要求する処理を書きましょう。
といってもこれは従来の方法と何ら変わっておらず、対象オブジェクトの PhotonView.RequestOwnership() を叩くだけです。
先ほどのスクリプトの最後あたりに追加しておきましょう。
public void GetOwnershipButtonEvent()
{
_photonView.RequestOwnership();
}
この関数を UIButton の OnClick イベントに追加しておけば発火されるようになります。
動作確認
ここまで設定出来たらビルドして動作確認しましょう。多重起動して疑似マルチプレイの状態を作り出します。
キューブがコロコロ*2 pic.twitter.com/v8aiqnAV6b
— karukaru👑@白魔導技士 (@_karukaru_) 2019年1月31日
このようにボタンを押したらオーナー権限が移動するようになっているかと思います。
オーナー権限が移動する前に Cube を動かせるようになってしまっているので、実用の際は対象オブジェクトのオーナー権限が自分にあるかのチェックや、同期方法を変えて移動しないようにする、などの対策が必要かと思います。