週刊SleepNel新聞

SleepNel所属のぽうひろが日々の個人開発で気になったことを綴ります。

Unity Photon(PUN+) の使い方 オブジェクト位置同期編(4/5)

f:id:pouhiroshi:20160609081810p:plain
途中でアーバンチャンピオンを作ろうネタを挟んでしまったため、ご無沙汰になってしまい申し訳ありません。

以前はPhotonのロビー・ルーム作成・ルーム入室について解説しました。
sleepnel.hatenablog.com

今回はUnity Photon(PUN+) オブジェクト位置同期のやり方を説明します。

Photonの公式ブログも参考になりますので、ぜひご覧になってはいかがでしょう。
blog.photoncloud.jp
blog.photoncloud.jp

さて、ここからは私なりの説明をしていきたいと思います。

PhotonではオブジェクトにPhotonViewというコンポーネントをつけ、
そのオブジェクトの位置情報をルーム間でやり取りして同期を行います。
f:id:pouhiroshi:20160609081505p:plain
同期するオブジェクトにPhotonViewをつけます。
f:id:pouhiroshi:20160609081539p:plain

Observed Componentsに自分自身のTransformをドラッグにしてTransformをセットします。
このままだと動きがあまりないのでRigidbodyもつけておきましょう。
f:id:pouhiroshi:20160609081656p:plain

できたらAssets/Resoucesフォルダを作って、そこにCubeオブジェクトをドラッグしてPrefab化します。
(あとでPhotonNetwork.Instantiateするための準備です)
f:id:pouhiroshi:20160609081635p:plain

ルーム内でPhoton.Instantiateすれば同期が始まります。

では同期オブジェクトを作りましょう。
ルームに入ったら作成しますので、PhotonManagerのOnJoinedRoom内でやりましょう。
同期オブジェクトを作成するには
PhotonNetwork.Instantiate (Prefab名, 初期位置,角度,グループNo)
です。グループNoはまだちょっと使ったことがないのでわからないのですが、とりあえず0にしておきます。

private GameObject cube;
    //ルーム入室した時に呼ばれるコールバックメソッド
    void OnJoinedRoom() {
        Debug.Log ("PhotonManager OnJoinedRoom");
        GameObject.Find("StatusText").GetComponent<Text>().text
           = "OnJoinedRoom";

        Vector3 initPos = new Vector3 (6.34f, 3f, 7.17f);
        cube = PhotonNetwork.Instantiate ("Cube", initPos,
                              Quaternion.Euler(Vector3.zero),0);

    }

f:id:pouhiroshi:20160609081810p:plain
ステージにCubeが出てきましたね。

後から別端末で部屋に入ってみましょう。


先にいたプレイヤーのCubeも見えるし、自分が作ったCubeもステージ上に登場しました。

では自分が作ったオブジェクトを動かして、別端末でちゃんと動くか確認してみましょう。


PC上で動かしたものが、端末側で動いて見えるのが確認できました。

でもちょっとカクツキが激しいですね。

そんなときは同期オブジェクトにPhoton Transform Viewを追加し、
PhotonViewでObserved Componentsで監視させます。
f:id:pouhiroshi:20160609081852p:plain


ちょっとスムーズになりましたね。

さらにスムーズにするために、オブジェクトのVelocity(速度情報)を同期するという技があります。
PhotonTransformViewのInterpolateOption,ExtrapolateOptionをSynchronize Valuesにします。
これによって後述のphotonTransformView.SetSynchronizedValuesによるVelocityによる位置同期になります。
さらに位置情報を同期するScriptを作り(ここではCubeScriptとします)ます。
f:id:pouhiroshi:20160609081959p:plain

CubeScriptは以下のように書きます。

using UnityEngine;
using System.Collections;

public class CubeScript : Photon.MonoBehaviour {

    private PhotonView photonView;
    private PhotonTransformView photonTransformView;

    // Use this for initialization
    void Start () {
        photonTransformView = GetComponent<PhotonTransformView>();
        photonView = PhotonView.Get(this);
    }

    // Update is called once per frame
    void Update () {
        if (photonView.isMine) {
            //現在の移動速度
            Vector3 velocity = gameObject.GetComponent<Rigidbody> ().velocity;
            //移動速度を指定
            photonTransformView.SetSynchronizedValues (velocity, 0);
        }
    }
}

現在の移動速度をRigidbodyのvelocityで取得し、
Vector3 velocity = gameObject.GetComponent ().velocity;
PhotonTransformViewに移動速度をセットしてあげます。
photonTransformView.SetSynchronizedValues (velocity, 0);
if (photonView.isMine) { が大事で自分が所有しているオブジェクトじゃないとこれは使えないようでisMineでないものに対してSetしようとするとエラーが出るようです。

では、これで実行してみましょう!!


少し飛んだ部分がありますが、かなりスムーズに動くようになりました!

この技はCubeの位置情報を同期するのではなく、Velocity(移動速度)を同期することで、カクツキを補完するやり方です。
DodgeWarsもこの方法を使ってボール位置の同期を行っています。

あまりオブジェクトが激しく動き回らないゲームの時(Turnbased ユーザが順番に操作を行うカードゲームみたいなやつ)は、普通にTransformやPhotonTransformViewの同期をすれば十分です。
DodgeWarsのように同期オブジェクトが激しく動き回るようなゲームの場合は、最後に紹介したVelocity同期をお勧めします。

次回は、オブジェクト以外の変数同期方法について解説したいと思います。

PUN+はこちらで購入できます!


ではでは、良いインディー開発ライフを!