【Unity】MLAPIを使ったマルチプレイアプリの作り方


#サマリ
MLAPIを使ったマルチプレイアプリの作り方の基本をまとめました。

##環境
- Unity 2019.4.15f1
- MLAPI v12.1.7
- ユニティちゃん 1.2.1

##目次
1. プロジェクトの作成
1. MLAPIのインポート
1. ユニティちゃんの配置
1. MLAPIのNetworkManagerの作成
1. ユニティちゃんをネットワークオブジェクトとして設定
1. UIの作成
1. スクリプトの作成
1. ユニティちゃんスクリプトの修正
1. ビルド
1. 動作確認

#1.プロジェクトの作成
- 3Dアプリとしてプロジェクトを作成する。
![プロジェクト作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/4e2c85ba-8046-6023-7123-6b81c911e1d9.png)

#2.MLAPIのインポート
- 下記URLからMLAPIのunitypackageをダウンロードする。

[MLAPIリリースページ](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/releases)

![MLAPIダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/448eb9df-dc32-5711-37dd-8239183c3708.png)


- Assets > Import Package > Custom Package を選択する。
![インポート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/2c36f8a8-b314-f12a-65f4-0595a82dc504.png)

- ファイル選択ダイアログでダウンロードしたMLAPIのunitypackageを選択し、開くボタンを押す。
![ファイル選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/73dd2a9a-5fcb-ff58-4911-946b4f796364.png)

- パッケージのAssetsはすべて選択してImportボタンを押す。
![MLAPI2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/af5dc847-a8d7-c3f0-2e5c-5c36d1e87862.png)

- ProjectのAssetsにMLAPIがインポートされる。
![Project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/3640a34d-8e07-8c65-8775-404635693bdd.png)

#3.ユニティちゃんの配置
- 下記URLからユニティちゃんの3Dモデルデータをダウンロードする。

[ユニティちゃん 3Dモデルデータ](https://unity-chan.com/download/releaseNote.php?id=UnityChan)

- ユニティちゃんのAssetsをインポートする。
![インポート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/2c36f8a8-b314-f12a-65f4-0595a82dc504.png)

![ファイル選択_unitychan2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/2e657265-6969-5077-2f67-7a60a0b10675.png)

![unitychan_import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/366a1ec4-33e8-3edd-2b8c-e28914dfcbcc.png)

- HierarchyにCubeを追加、大きさを調整し地面を作成する。
![cube.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/866ceac0-7230-9f27-8b74-de187554f9a9.png)

- 適当に大きさを設定する。
![cube2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/8af51b5b-63fd-0b5e-8d63-5c750beddc41.png)

- 全景が映るようにカメラ位置を調整する。 
![camera.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/44ae45bc-c325-f0f0-b178-d44346ad7ca2.png)

- ユニティちゃんのPrefabをHierarchyに配置し、地面に埋まらないように位置を調整する。
![unitychan_haichi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/19c067dc-d8e5-0f17-78b4-3e788268e47d.png)

- 位置を調整。
![unitychan_position.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/99397ca6-22bb-60cc-3205-1dcc026e0437.png)

- ユニティちゃんの配置。
![unitychan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/617c7ad1-065e-7c15-40dd-0e009b9d7049.png)

#4.MLAPIのNetworkManagerの作成
- HierarchyにEmptyオブジェクトを作成し、名前をNetworkManagerに変更します。
![create_empty.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/0186921f-309d-ddc9-e1b8-d9627cb1864b.png)

- NetworkingManagerコンポーネントを追加する。
![add_networkingmanager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/9e721489-f836-b93b-78cb-91067b841235.png)

- Unet Transportコンポーネントを追加する。
![add_unettransport.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/98e0962e-581b-f0a9-9904-0b9cd5f8b4a4.png)

- NetworkingManagerのNetwork TransportにNetworkManager自身を設定します。
![set_networktransport.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/9d6b05fd-c2e3-58e8-3a68-4ec9109958ce.png)

#5.ユニティちゃんをネットワークオブジェクトとして設定
- ユニティちゃんのprefabにNetworkedObjectコンポーネントを追加する。
![add_networkedobject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/4258778b-15fd-0ad7-e875-4376c4a50147.png)

- NetworkManagerのNetworkedPrefabにユニティちゃんを設定する。
![set_prefab2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/8be30a70-ff63-a27d-078e-bf5954bad81f.png)


- NetworkManagerのNetworkedPrefabのDefault Player Prefabをチェックする。
![check_defaultprefab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/01645c72-9a50-7190-e167-5bc183f9240d.png)

- ユニティちゃんのprefabにNetworkedTransformコンポーネントを追加する。
![add_networkedtransform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/8da766ed-321f-64a1-273e-10c048235c1e.png)

- ユニティちゃんのprefabにNetworkedAnimatorコンポーネントを追加する。
![add_networkedanimator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/e59c4c97-a738-15ae-4179-655aeb9723a4.png)

- NetworkedAnimatorコンポーネントのAnimatorにユニティちゃん自身を設定する。
![set_animator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/88566007-ef06-c6cf-6197-48fd90cc5eb0.png)

- 同期するパラメタとしてSpeedを設定する。
![set_animator_speed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/157c0caa-dc97-bc1c-bef4-90a12b04c432.png)

- コンポーネントを追加したユニティちゃんのprefabをapplyする。
![apply_prefab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/2a8fcb06-a48a-2a1d-c2e8-1f383abe5271.png)


#6.UIの作成
- HierarchyにUI用Canvasを作成する。
![add_canvas.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/cc8e06bb-f470-b533-c39d-3f07656711c5.png)

- 作成したCanvasにButtonを追加する。
![add_button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/59cbb0db-d535-a626-8b73-2b06fb2e31d9.png)

- オブジェクト名と表示テキストをStartHostに変更する。
![change_starthost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/b984d2e2-36db-ea00-3a96-8fee2c2eae32.png)

- 同様にStartClientボタンを作成し、画面の端に移動する。
![button_rect_transform2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/c431f5cc-f54d-cda9-65e2-c0ee89bf978c.png)
![button_position.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/a748f188-987e-dc1b-583b-72a04467c249.png)

#7.スクリプトの作成
- 新規にスクリプトを作成する。
![create_scipt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/c622db10-8c52-98a8-b800-fde39185db7c.png)

- 作成したスクリプトに次のメソッドを追加する。

```cs
    public void OnClickStartHost()
    {
        Debug.Log("Start Host!!");
        MLAPI.NetworkingManager.Singleton.StartHost();
    }

    public void OnClickStartClient()
    {
        Debug.Log("Start Client!!");
        MLAPI.NetworkingManager.Singleton.StartClient();
    }
```

- StartHostボタンにスクリプトを設定する。
![add_script.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/9e9d81c2-39ec-0f4b-2321-ca9877290456.png)

- OnClick()のObjectにStartHostボタンを設定し、FunctionにOnClickStartHost()を設定する。
![set_StartHost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/7cabc825-5032-6cfe-a34d-7d1cbe03a34f.png)

- 同様にStartClientボタンにスクリプトを設定する。

#8.ユニティちゃんスクリプトの修正
- Assets > UnityChan > Scripts > UnityChanControlScriptWithRigidBodyを開く。
![unitychan_script.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/6ea205b8-b75c-d90f-f77a-3c8091082207.png)

- 基底クラスをMonoBehaviourからMLAPI.NetwotkedBehaviourに変更する。

```cs
	public class UnityChanControlScriptWithRgidBody : MonoBehaviour
	{
```
↓

```cs
	public class UnityChanControlScriptWithRgidBody : MLAPI.NetworkedBehaviour
	{
```

- 自分自身だけupdateするように、FixedUpdateメソッドの処理をIsOwnerの時だけ処理するようにif文で囲う。

```cs
		void FixedUpdate ()
		{
            if (this.IsOwner)
            {
                float h = Input.GetAxis("Horizontal");              // 入力デバイスの水平軸をhで定義
                float v = Input.GetAxis("Vertical");                // 入力デバイスの垂直軸をvで定義
            ＜省略＞
                // REST中の処理
                // 現在のベースレイヤーがrestStateの時
                else if (currentBaseState.nameHash == restState)
                {
                    //cameraObject.SendMessage("setCameraPositionFrontView");		// カメラを正面に切り替える
                    // ステートが遷移中でない場合、Rest bool値をリセットする（ループしないようにする）
                    if (!anim.IsInTransition(0))
                    {
                        anim.SetBool("Rest", false);
                    }
                }
            }
	    }
```

#9.ビルド
- 起動時にユニティちゃんは複製されるためHierarchyのユニティちゃんは削除する。

![delete_unitychan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/ac411bf0-fa3c-ee31-3ec4-b521277dec84.png)

- Project Settings > Player > Resolution and Presentation > Fullscreen Mode をWindowedに変更。
![screenmode2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/559ab59c-372b-5fa1-1656-b0ca8ec1965f.png)


- Project Settings > Player > Other Settings > Api Compatibility Level を.Net 4.xに変更。
![set_net_version2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/93c498da-18b1-7637-1f36-b97863dc3037.png)

- ビルドする。
![build.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/31c1d17a-d7de-3242-67c0-39645257021f.png)

- 適当にフォルダを作って選択。

![folder2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/5b3dd7c5-7d3f-abb8-6aed-cca9e2bb9aff.png)

#10.動作確認
- ビルドしてできたexeファイルを実行する。
![exec.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/aa9805af-b74c-1f12-386e-c4ae6d139cf9.png)

- 最初のウィンドウはStartHostボタンを押してHostとしてスタートする。
![starthost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/8d9ac242-b406-e6cc-c6b5-76b7a740a441.png)

- ユニティちゃんが出現する。
![実行host.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/e0752377-f3f5-2f2f-fa83-718a84c90a64.png)

- 二つめ以降のウィンドウはClientとして動作させる。再度exeファイルを実行し、StartClientボタンを押してClientをスタートする。
![実行client.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/f77f49af-3589-229e-50c8-25df68f31921.png)

- 二人目のユニティちゃんが出現する。それぞれの動きが同期されて表示される。
![実行client2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/a6814c96-5fe5-d3cd-ecd4-21ecad8e7964.png)

#　
チームハイエナ <img width="120" alt="hyaeninae_tomei.png"  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933978/99b448d3-7ff0-58f3-302b-8528cf339b8d.png">