LoginSignup
6

More than 5 years have passed since last update.

【PUN】アバター生成・同期

Last updated at Posted at 2017-12-23

Photon Unity Networkの基本機能メモ

【PUN】ログイン
【PUN】アバター生成・同期
【PUN】ゲーム終了判定


開発方法

Unity Collaborateでプロジェクトを共有して、PCを2台並べて開発するのがおすすめ。
(3台で見たい場合はアプリでビルド)

アバター生成

PhotonNetwork.Instantiate
https://doc.photonengine.com/ja-jp/pun/current/gameplay/instantiation
生成するゲームオブジェクトはResources以下にプレファブとして格納
生成対象はクライアント間通信の橋渡しであるPhotonViewコンポーネントをもつことが必須

シーンにローカルプレイヤー用のオブジェクトを置いておいて、配下にアバターを生成する

Player.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Player : MonoBehaviour {

    void OnJoinedRoom(){
        CreateAvatar ();
    }

    void CreateAvatar() {
        Debug.Log ("Player: 自分のアバターを生成");

        // 自分のアバターを他のクライアントにも生成
        GameObject avatar = PhotonNetwork.Instantiate ("Avatar", new Vector3(0f,1f,0f), Quaternion.identity, 0);
        avatar.transform.parent = transform;

        GameObject camera = transform.Find ("Camera").gameObject;
        camera.transform.parent = avatar.transform;
    }
}

Transformの同期

アバターにPhotonTransformViewコンポーネントをアタッチ
PositionとRotationを同期にチェック
PhotonViewコンポーネントのObservedComponentsに登録して監視対象にする

2017-12-23 (2).png

MonoBehaviourの同期

Avatar.csを作成、アバターにアタッチ
MonoBehaviourからPhoton.MonoBehaviour(自身のスクリプトが紐づくオブジェクトにアタッチされているPhotonViewコンポーネントへのアクセスを提供するヘルパークラス)に変更
PhotonViewコンポーネントのObservedComponentsに登録して監視対象にする

using UnityEngine;
using System.Collections;

public class Avatar : Photon.MonoBehaviour {

    [SerializeField] int m_healthPoint = 100;
    [SerializeField] GameObject m_BulletPrefab;
    [SerializeField] GameObject m_DamageEffectPrefab;

    PhotonView m_photonView;

    void Start() {
        m_photonView = GetComponent<PhotonView> ();
        if(m_photonView.isMine) {
            // 初期設定
            SetPlayerName ("Player-Id: " + PhotonNetwork.player.ID);
            SetHealthPoint (m_healthPoint);
        }
    }

    void SetPlayerName(string name) {
        this.gameObject.name = name;
        transform.Find ("NameUI").gameObject.GetComponent<TextMesh> ().text = name;
    }

    void SetHealthPoint(int num) {
        m_healthPoint = num;
        transform.Find ("HealthPointUI").gameObject.GetComponent<TextMesh> ().text = num.ToString();
    }

    // ストリーム同期
    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
        if (stream.isWriting) {
            // 自分の情報を送る
            string myName = this.gameObject.name;
            int myHealthPoint = m_healthPoint;
            stream.SendNext (myName);
            stream.SendNext (myHealthPoint);
        } else {
            // 他人の情報を受け取る
            string otherName = (string)stream.ReceiveNext();
            int otherHealthPoint = (int)stream.ReceiveNext();
            SetPlayerName (otherName);
            SetHealthPoint (otherHealthPoint);
        }
    }

    // イベント同期
    [PunRPC]
    void Shoot(Vector3 i_pos, Vector3 i_angle) {
        // 全クライアントの中の自分が一斉に弾丸を発射する
        Quaternion rot = Quaternion.Euler (i_angle);
        GameObject bullet = GameObject.Instantiate (m_BulletPrefab ,i_pos ,rot);
        bullet.GetComponent<Rigidbody> ().AddForce (transform.forward * 20, ForceMode.VelocityChange);
        Destroy(bullet, 3);
    }

    void OnTriggerEnter(Collider i_other) {
        if(i_other.tag == "bullet"){
            // ダメージを受ける
            SetHealthPoint (m_healthPoint - 10);
            Instantiate (m_DamageEffectPrefab, transform.position, Quaternion.identity);
            Destroy (i_other.gameObject);

            if(m_healthPoint <= 0){
                if (m_photonView.isMine) {
                    // gameover
                }
            }
        }
    }

    void Update () {

        if(m_photonView.isMine == false){
            return;
        }

        if (Input.GetKeyDown (KeyCode.Space)) {
            // 自分自身の弾丸でトリガーを引かないようにやや手前から発射
            Vector3 pos = transform.position + transform.forward * 2f;
            Vector3 angle = transform.eulerAngles;
            // 処理が重いのでPhotonViewを付けずに位置と角度を渡す
            m_photonView.RPC ("Shoot", PhotonTargets.AllViaServer, pos, angle);
        }

        // 自分のアバターだけを動かす
        var v = Input.GetAxis ("Vertical");
        Vector3 velocity = new Vector3 (0, 0, v);
        velocity = transform.TransformDirection (velocity);
        velocity *= 5f;
        transform.localPosition += velocity * Time.fixedDeltaTime;

        var h = Input.GetAxis ("Horizontal");
        transform.Rotate (0, h * 3f, 0);
    }

}

ストリーム同期 / OnPhotonSerializeView

OnPhotonSerializeView
定期的に呼ばれ、パラメータを送信・受信する

202 2 連続的な値の同期方法

イベント同期 / RPC

PhotonView.RPC
他クライアントのメソッドを実行する

[PunRPC]
void Method(){}
メソッドを定義する際に[PunRPC]属性をつける

202 3 離散的な値の同期方法

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6