【超簡単！】Netcode for GameObjectsでマルチプレイを実装する

# 概要
Netcode for GameObjectsで位置, アニメーションの同期を行います。
この記事では実装手順のみを紹介します。
初学者向けに細かい操作も書いておきます。

# TL;DR
NetworkManagerとPlayerを用意してStartHost, StartClientする。
PlayerにはNetworkObjectともろもろ同期用のNetworkBehaviourを継承したクラスを付ける。
後は感覚で行ける。

# 1. プロジェクトを用意する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/d3a58007-0f2a-04c6-baee-1eb98320665b.png)
3Dテンプレートを選択し、プロジェクトを作成

# 2. パッケージをインストールする
Unity Registry -> Netcode for GameObjects
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/c58ae591-ab69-4356-44c6-20ac552bc43f.png)
※以前はUnity Transportを手動で入れる必要があったが自動で入れてくれるようになった。

# 3. シーン上にNetworkManagerを配置する
CreateEmptyして...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/9396fe4a-34c3-d16d-2527-9e46626ff3ff.png)
名前をNetworkManagerにしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/b395650e-f62f-bfc0-f711-5e6a58e50a44.png)
作ったオブジェクトにNetworkManagerコンポーネントを付ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/2886ba0e-34a3-9d9f-9494-a3e4575d4e72.png)

# 4. Playerオブジェクトを用意する
ユニティちゃんを使う。
ダウンロードしてきたものをインポート。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/6f060b62-4be1-f57a-b10b-309f8eec7fbf.png)

一回シーンにおいて、AnimatorControllerを交換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/ae4b1def-271f-c8b7-0aaa-598a0d8c5df0.png)

このままだとピンクなので....
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/96bb933a-68ac-ba91-6ae9-7bcfc0831206.png)

とりあえず描画できるStandardに設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/f817fcdf-e847-887d-7779-dcd874c8f3c0.png)


ここから...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/191cc535-7970-39ba-577c-86a178d359b8.png)

NetworkObject, NetworkAnimator, NetworkTransform, NetworkRigidbody,NewScriptからPlayerControllerを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/d3e16353-11cd-89ad-35b4-462fe58dc18f.png)

NetworkAnimatorにAnimatorをセット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/4d99e0ae-e223-3238-4903-4dcb1afa9112.png)

CapsuleColliderを追加して、いいかんじに調整
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/a2edd404-4e54-a459-1a24-0e4be9c8ec9b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/ee25bfe9-2602-af7b-9680-3627ac4f3c62.png)

RigidbodyのFreezePositionとFreezeRotationを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/ebac8b25-1c79-8d37-8674-0f399935e6f1.png)

PlayerControllerに以下のコードを記載
```csharp
using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

public class PlayerController : NetworkBehaviour
{
    [SerializeField] float speed = 1f;
    Animator animator;
    
    void Start()
    {
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        if (IsOwner)
        {
            var h = Input.GetAxis("Horizontal");
            var v = Input.GetAxis("Vertical");
            // サーバー(ホスト)のメソッドを呼び出す
            MoveServerRpc(h, v);
        }
        
        if (IsServer)
        {
            // ステージから落ちたら戻してあげる
            if (transform.position.y < -10.0)
            {
                transform.position = new Vector3(Random.Range(-3, 3), 3, Random.Range(-3, 3));
            }
        }
    }
    
    [ServerRpc]
    void MoveServerRpc(float vertical, float horizontal)
    {
        // ここはサーバー(ホスト)でだけ処理される
        var moveInput = new Vector3(horizontal, 0, vertical);
        if (moveInput.magnitude > 0f)
            transform.LookAt(transform.position + moveInput);

        transform.position += moveInput * Time.deltaTime * speed;
        animator.SetFloat("Speed", moveInput.magnitude);
    }
}
```

# 5. 床を用意
Plane作って...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/a344570f-3059-d206-13c2-902920f16af0.png)

でっかくする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/33877e5c-9799-1387-edb4-6b0b1e74e54d.png)

# 6. NetworkManagerの設定
TransportをUnityTransportに設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/d9bf19b4-5299-33b3-30e1-1d2bde738801.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/cca9102d-af78-ebd4-7fd6-222591a42fdc.png)

PlayerPrefabを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/7a96e1de-6f12-1990-c726-cb70b46c1c89.png)

# 7. ボタンを追加
先ほど作ったNetworkManagerオブジェクトにAddCompornent -> NewScriptからNetworkManagerControllerを追加
NetworkManagerControllerの中に以下のコードを入れる
```csharp
using Unity.Netcode;
using UnityEngine;

public class NetworkManagerController : MonoBehaviour
{
    void OnGUI()
    {
        GUILayout.BeginArea(new Rect(10, 10, 300, 300));
        if (GUILayout.Button("Host")) NetworkManager.Singleton.StartHost();
        if (GUILayout.Button("Client")) NetworkManager.Singleton.StartClient();
        if (GUILayout.Button("Server")) NetworkManager.Singleton.StartServer();
        GUILayout.EndArea();
    }
}
```

# 8.ビルド
Add Open Scenesを押して、Build And Runする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/59c48f6d-8b55-bbc7-9da4-e6a144aee82b.png)

# 9.実行
Build And Runが完了したら勝手にゲームが起動する。
↑これとエディタで位置とアニメーション同期を確認する

片方でHost、もう片方でClientを押すと、シーン上にキャラクターが2体出てくる。
AWSDや矢印キーで動ける。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/84cd63b9-1e1e-a908-cef0-e3b7e74b1950.png)

完成！

# まとめ
今回は簡単な位置同期とアニメーション同期を試してみました。
簡単とはいえマルチプレイをこれだけの作業で実装できるのは嬉しいです。
ただ、このままだと同じPC上でしか動きません。
NetworkManagerからIPを直接設定することでローカルネットワーク内で通信出来たり、Relayを使うことでインターネットの海を飛び越えることが出来たりします。
是非いろいろ試してみてください。


# 参考
以下を参考にしています。
本当に分かりやすく丁寧に説明してくださっているので是非見てみてください！！！
 - Unity Netcode for GameObjectsを使ったオンラインマルチプレイゲーム開発Tips
https://media.colorfulpalette.co.jp/n/n08799dd4ae7e
 - Netcode for GameObjectsを使ってみよう - Unityステーション
https://www.youtube.com/watch?v=GRUtGLL8iMQ&t=50s&ab_channel=UnityJapan
 - How to use Unity Relay, Multiplayer through FIREWALL! (Unity Gaming Services)
https://www.youtube.com/watch?v=msPNJ2cxWfw&t=1095s&ab_channel=CodeMonkey
 - COMPLETE Unity Multiplayer Tutorial (Netcode for Game Objects)
https://www.youtube.com/watch?v=3yuBOB3VrCk&ab_channel=CodeMonkey
 - Unityの「Netcode for GameObjects」のサンプルで学ぶ co-opゲームの作り方
https://www.youtube.com/watch?v=-XQkv5Ugeq4&t=2067s&ab_channel=UnityJapan