PUNで動的にAnimator込みの同期オブジェクトを同期する

## やりたいこと => PhotonObjectをスクリプトから生成する
PhotonObjectをスクリプトから生成するやり方、あまり記事がひっかかりません。
みんなPhotonNetwork.Instantiate()でResourcesから引っ張ってきてるんでしょうか？
とりあえず以下の先人の記事を読んでください。

[Photon Unity Networkingで動的に同期オブジェクトを生成する方法](https://qiita.com/_karukaru_/items/f90fe4f269a72d2b46d0)

この記事はそれにPhotonAnimationViewを追加して使い回せるようそれっぽくメソッド化したものです。
無茶苦茶やってるので解説読んでから使ってください。

### コード

```c#:Dresser.cs
    public static GameObject DressAsPhotonObject(GameObject plainObject, int viewId, int ownerId)
    {
        // PhotonView.
        PhotonView photonView = plainObject.AddComponent<PhotonView>();
        photonView.viewID = viewId;
        photonView.ownerId = ownerId;
        photonView.synchronization = ViewSynchronization.UnreliableOnChange;
        photonView.ObservedComponents = new List<Component>();

        // Transform.
        PhotonTransformView photonTransformView = plainObject.AddComponent<PhotonTransformView>();
        photonTransformView.m_PositionModel.SynchronizeEnabled = true;
        photonTransformView.m_RotationModel.SynchronizeEnabled = true;
        photonTransformView.m_ScaleModel.SynchronizeEnabled = true;

        // Animator.
        PhotonAnimatorView photonAnimatorView = plainObject.AddComponent<PhotonAnimatorView>();
        Animator animator = plainObject.GetComponent<Animator>();
        // Animator layer
        for (var count = 0; count < animator.layerCount; count++)
        {            
            photonAnimatorView.SetLayerSynchronized(count, PhotonAnimatorView.SynchronizeType.Discrete);
        }
        // Animator Parameter
        foreach (AnimatorControllerParameter animatorControllerParameter in animator.parameters)
        {
            photonAnimatorView.SetParameterSynchronized(animatorControllerParameter.name,
                (PhotonAnimatorView.ParameterType) animatorControllerParameter.type,
                PhotonAnimatorView.SynchronizeType.Discrete);
        }

        // add list
        photonView.ObservedComponents.Add(photonTransformView);
        photonView.ObservedComponents.Add(photonAnimatorView);

        return plainObject;
    }
```

#### こんな感じで使う
```c#

[SerializeField] private GameObject _prefab;

    public enum RaiseEventType : byte
    {
        Create = 1,
    }

    void Start()
    {
        PhotonNetwork.OnEventCall += CreatePhoton;
        var sendData = new int[2];
        sendData[0] = PhotonNetwork.AllocateViewID();
        sendData[1] = PhotonNetwork.player.ID;
        var option = new RaiseEventOptions
        {
            CachingOption = EventCaching.AddToRoomCache,
            Receivers = ReceiverGroup.All,
        };
        PhotonNetwork.RaiseEvent((byte) RaiseEventType.Create, sendData, true, option);
    }


    private void CreatePhoton(byte eventCode, object content, int senderId)
    {
        if (eventCode == (byte) RaiseEventType.Create)
        {
            var receiveData = content as int[];
            var plainObjects = Instantiate(_prefab);
            PhotonDresser.DressAsPhotonObject(plainObjects, receiveData[0], receiveData[1]);
        }
    }
```

## 解説

### PhotonView

```c#

// まずは大本のPhotonView.
PhotonView photonView = plainObject.AddComponent<PhotonView>();
// PhotonNetwork.AllocateViewID()で用意してもらったviewID
photonView.viewID = viewId;
// とりあえず作ったplayerのIDぶちこんどく
photonView.ownerId = ownerId;
// デフォルトがoff.わたしはこれでしにました
photonView.synchronization = ViewSynchronization.UnreliableOnChange;
// newしとかないとしぬ
photonView.ObservedComponents = new List<Component>();

```

### PhotonTransFormView

```c#

// Transform.
// インスペクタ上で見られる設定は対応する~Modelに設定できるメソッドやプロパティがある.
// 見ればわかるが各Modelクラスはただのデータクラス.あまりクセがないので特に言うことがない。
PhotonTransformView photonTransformView = plainObject.AddComponent<PhotonTransformView>();
photonTransformView.m_PositionModel.SynchronizeEnabled = true;
photonTransformView.m_RotationModel.SynchronizeEnabled = true;
photonTransformView.m_ScaleModel.SynchronizeEnabled = true;

```

### PhotonAnimatorView

```c#

// Animator.
PhotonAnimatorView photonAnimatorView = plainObject.AddComponent<PhotonAnimatorView>();
Animator animator = plainObject.GetComponent<Animator>();

// 特定のレイヤーだけ同期する、みたいな用途はあまり考えづらいが……。普通は全部同期する気がする.
// もちろん実際に使う場合は「layerIndexはどうせ0,1,2...なんだろ？　死ねぇ！」とループでブチ回すのではなく、
// ちゃんとAnimator.GetLayerIndex(レイヤー名)で取るべき.
// しかしそうなるとこのメソッドの汎用性がなくなる…….
for (var count = 0; count < animator.layerCount; count++)
{
    photonAnimatorView.SetLayerSynchronized(count, PhotonAnimatorView.SynchronizeType.Discrete);
}

// パラメータなんざ全部同期しときゃいいんだよ！　オラァ！
foreach (AnimatorControllerParameter animatorControllerParameter in animator.parameters)
{
    // AnimatorControllerParameterType = PhotonAnimatorView.ParameterType
    // 別のenumだが両方 int enum で定義値が一緒なので直にキャストしても動く.
    // 変更することがあるとも思えないのでそのまま使う.
    // そのままAnimatorControllerParameterType使ったらよかったのでは？
    photonAnimatorView.SetParameterSynchronized(animatorControllerParameter.name,
        (PhotonAnimatorView.ParameterType) animatorControllerParameter.type,
        PhotonAnimatorView.SynchronizeType.Discrete);
}

```

### return

```c#
// PhotonViewに渡しとかないと同期されない.
photonView.ObservedComponents.Add(photonTransformView);
photonView.ObservedComponents.Add(photonAnimatorView);

// 余談だが動的に生成したPhotonObjectはリストとかに入れて管理するより
// タグつけて適宜GameObject.FindGameObjectsWithTag(TAG)で取得したほうがいいような気がする.
// リストに死んだの入ってたらめんどくさいし.
return plainObject;

```

## 結論
適宜よいように改変して使ってください。
Photonは公式ドキュメントが__絶妙にふわふわ__しているので、ある程度それらしいことを検索してわからなかったらコード読んだほうが早いです。PhotonViewとかPhotonNetworkとか。
また、こうして動的にPhotonObjectを生成するには各クライアントで実行する必要があります。[PunRPC]はあまり使わないでサンプルで書いたみたいにRaiseEventでやったほうがいいです。
慣れるとRaiseEventばっかり使うようになってきます。キャッシュ管理とかいろいろべんり。
CustomPropertiesにブチ込んでそのコールバックで……みたいな手もなくは……ないんですが……？
一応動いてはいるんですが、なんかやばそうな気がするのでやめたほうがいいです、多分。

## 参考資料
[Photon Unity Networkingで動的に同期オブジェクトを生成する方法](https://qiita.com/_karukaru_/items/f90fe4f269a72d2b46d0)

[Photonでオブジェクトをスポーンする方法の調査およびIPunPrefabPoolとUniRx.Toolkit.ObjectPoolを使ったオブジェクトプールのサンプル](https://qiita.com/su10/items/4bae56bc814c4e6a2bc0)

[【Unity】僕もPhotonを使いたい #10 RaiseEvent](https://www.urablog.xyz/entry/2016/09/22/220312#使い方その弐-RaiseEventを呼ぶ)


# ほんとうにいいたかったこと

__あんちゃん！　[なんか2出てる](https://assetstore.unity.com/packages/tools/network/pun-2-free-119922)けど何が変わったのかよくわからんから調べといて！__