【続】Unityでデータベースと連携させたい！（Firebase編）

# 前回 Firebase とのやりとり部分を Rest Client for Unity というAssetStoreでDLできるライブラリを利用して記述しましたが、今回はその部分を Unity が提供している UnityEngine.Networking クラスの関数(UnityWebRequest,DownloadHandlerBuffer) を使って書き換えてみました！

![forqiiita3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463891/b6a71cfd-79a3-1532-8077-9663995072fc.png)


## 環境
PC: MacBook Air

## 前回記事
[Unityでデータベースと連携させたい！（Firebase編）](https://qiita.com/kana_omori/items/3d52701145c4ccef5bb1)

## 参照記事
[UnityWebRequestの使い方【Unity】](http://kan-kikuchi.hatenablog.com/entry/UnityWebRequest)
[UnityWebRequest](https://docs.unity3d.com/ja/2019.1/ScriptReference/Networking.UnityWebRequest.html)
[DownloadHandlerBuffer](https://docs.unity3d.com/ja/2019.1/ScriptReference/Networking.DownloadHandlerBuffer.html)
[UnityWebRequest HTTP POST to Cloud Functions for Firebase](https://stackoverflow.com/questions/43609350/unitywebrequest-http-post-to-cloud-functions-for-firebase)
[UnityWebRequestでJSONをPOSTする方法](https://qiita.com/s-sanosuke/items/3e0cd02ddc1b61de6cde)
[【C#】クラス名<T>って何？ジェネリッククラスについて。](https://blog.websandbag.com/entry/2018/08/11/230001)
[C#のラムダ式【=>】って何？](https://araramistudio.jimdo.com/2017/12/19/c-%E3%81%AE%E3%83%A9%E3%83%A0%E3%83%80%E5%BC%8F-%E3%81%A3%E3%81%A6%E4%BD%95/)
[C# の delegate : メソッドの引数にメソッドを渡して使用する方法と、JavaScript の function(){} と同じ使用方法( 匿名 )](http://ginpro.winofsql.jp/article/292539736.html)
[Unityで覚えるC#](https://www.slideshare.net/lucifuges/unityc)
[UnityのJsonUtilityの細かい10の疑問をいまさら検証した](https://qiita.com/keidroid/items/24e03f82d74560dc557a)

---

:baby_tone2:以下作業内容:baby_tone2:

- `PlayerScores.cs`を書き換える

```diff
- 削除した部分
+ 追記した部分
```



```diff
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
- using Proyecto26;
+ using UnityEngine.Networking;

public class PlayerScores : MonoBehaviour
{
    public Text scoreText;
    public InputField nameText;

    private System.Random random = new System.Random();

    User user = new User();

    public static int playerScore;
    public static string playerName;

    public GameObject targetObject;

    // Start is called before the first frame update
    void Start()
    {
        playerScore = random.Next(0, 101);
        scoreText.text = "Score: " + playerScore;
    }

    public void OnSubmit(){
        playerName = nameText.text;
        PostToDatabase();
    }

    public void OnGetScore(){
        RetrieveFromDatabase();
    }

    private void UpdateScore(){
        scoreText.text = "Score: " + user.userScore;
        ChangeColorName(user.userScore);
    }

    private void PostToDatabase(){
        User user = new User();
-       RestClient.Put("https://forunity-e2ac2.firebaseio.com/"+ playerName +".json",user);
+       string jsonStr = JsonUtility.ToJson(user);
+       StartCoroutine(Put("https://forunity-e2ac2.firebaseio.com/"+ playerName +".json", jsonStr));
        ChangeColorName(user.userScore);
    }

    private void RetrieveFromDatabase(){
-       RestClient.Get<User>("https://forunity-e2ac2.firebaseio.com/"+ nameText.text +".json").Then(response =>
-       {
-       user = response;
-       UpdateScore();
-       });
+       StartCoroutine(GetUserDat("https://forunity-e2ac2.firebaseio.com/"+ nameText.text +".json"));
    }

    private void ChangeColorName(int score){
        //Debug.Log(score);
        if(score < 25){
            // red
            targetObject.GetComponent<Renderer>().material.color = Color.red;
        } else if (score < 50){
            // yellow
            targetObject.GetComponent<Renderer>().material.color = Color.yellow;
        } else if (score < 75){
            // green
            targetObject.GetComponent<Renderer>().material.color = Color.green;
        } else {
            // blue
            targetObject.GetComponent<Renderer>().material.color = Color.blue;
        }
        
    }
+
+   //SendWebRequest
+   private IEnumerator Put(string url, string jsonStr){
+       //UnityWebRequestを生成する
+       UnityWebRequest request = UnityWebRequest.Put(url, jsonStr);
+
+       //SendWebRequestを実行して送受信開始
+       yield return request.SendWebRequest();
+
+       //エラー判定
+       if(request.isHttpError || request.isNetworkError){
+           //エラーログ
+           Debug.Log(request.error);
+       } else {
+           //結果確認
+           Debug.Log(request.downloadHandler.text);
+       }
+   }
+   private IEnumerator GetUserDat(string url){
+       //UnityWebRequestを生成する
+       UnityWebRequest request = UnityWebRequest.Get(url);
+       request.downloadHandler = new DownloadHandlerBuffer();
+
+       //SendWebRequestを実行して送受信開始
+       yield return request.SendWebRequest();
+
+       //エラー判定
+       if(request.isHttpError || request.isNetworkError){
+           //エラーログ
+           Debug.Log(request.error);
+       } else {
+           // json -> c# で使える形式に直さないとならない...
+           user = JsonUtility.FromJson<User>(request.downloadHandler.text);
+           UpdateScore();
+            
+           //結果確認ログ
+           Debug.Log(request.downloadHandler.text);
+       }
+   }
}

```

### その１
####  必要なusingを宣言
`using Proyecto26;`はRest Client for Unityライブラリ用の記述なので削除し、`using UnityEngine.Networking;`を代わりに追記します

```PlayerScores.cs
using UnityEngine.Networking;
```

### その２
####  登録・更新するファンクションを準備する
登録・更新は　UnityWebRequest.Put　を使います

```PlayerScores.cs
    private IEnumerator Put(string url, string jsonStr){
        //UnityWebRequestを生成する
        UnityWebRequest request = UnityWebRequest.Put(url, jsonStr);
 
        //SendWebRequestを実行して送受信開始
        yield return request.SendWebRequest();
 
        //エラー判定
        if(request.isHttpError || request.isNetworkError){
            //エラーログ
            Debug.Log(request.error);
        } else {
            //結果確認
            Debug.Log(request.downloadHandler.text);
        }
    }
```

### その３
#### 取得するファンクションを準備する
取得は　UnityWebRequest.Get と DownloadHandlerBuffer を使います

（Get結果を使用するために SendWebRequest() する前に DownloadHandlerBuffer のインスタンスを生成しておかないとならないのと、jsonで取得してきたリクエスト結果をC#で使える形に変換しなければならないところで詰まって結構時間かかりました。。poz）

```PlayerScores.cs
    private IEnumerator GetUserDat(string url){
        //UnityWebRequestを生成する
        UnityWebRequest request = UnityWebRequest.Get(url);
        request.downloadHandler = new DownloadHandlerBuffer();
 
        //SendWebRequestを実行して送受信開始
        yield return request.SendWebRequest();
 
        //エラー判定
        if(request.isHttpError || request.isNetworkError){
            //エラーログ
            Debug.Log(request.error);
        } else {
            // json -> c# で使える形式に直さないとならない...
            user = JsonUtility.FromJson<User>(request.downloadHandler.text);
            UpdateScore();
             
            //結果確認ログ
            Debug.Log(request.downloadHandler.text);
        }
    }
```

### その４
#### 準備したファンクションを呼び出すように書き換える

Rest Client for Unity の関数を使っていた部分をそれぞれ準備したファンクションに書き換えます
その際、コルーチンとして扱って呼び出します（Unityはフレームごとにスレッドがすぎていってしまうので、フレームを跨いで処理を中断・再開させることが出来る仕組みであるコルーチンを利用）

Putするデータはjson型で渡したいので、JsonUtility.ToJsonをかましました

```PlayerScores.cs
    private void PostToDatabase(){
        User user = new User();
        string jsonStr = JsonUtility.ToJson(user);
        StartCoroutine(Put("https://forunity-e2ac2.firebaseio.com/"+ playerName +".json", jsonStr));
        ChangeColorName(user.userScore);
    }

    private void RetrieveFromDatabase(){
        StartCoroutine(GetUserDat("https://forunity-e2ac2.firebaseio.com/"+ nameText.text +".json"));
    }
```


修正はこれだけです


### (※最終的な`PlayerScores.cs`)

```PlayerScores(修正後).cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;

public class PlayerScores : MonoBehaviour
{
    public Text scoreText;
    public InputField nameText;

    private System.Random random = new System.Random();

    User user = new User();

    public static int playerScore;
    public static string playerName;

    public GameObject targetObject;

    // Start is called before the first frame update
    void Start()
    {
        playerScore = random.Next(0, 101);
        scoreText.text = "Score: " + playerScore;
    }

    public void OnSubmit(){
        playerName = nameText.text;
        PostToDatabase();
    }

    public void OnGetScore(){
        RetrieveFromDatabase();
    }

    private void UpdateScore(){
        scoreText.text = "Score: " + user.userScore;
        ChangeColorName(user.userScore);
    }

    private void PostToDatabase(){
        User user = new User();
        string jsonStr = JsonUtility.ToJson(user);
        StartCoroutine(Put("https://forunity-e2ac2.firebaseio.com/"+ playerName +".json", jsonStr));
        ChangeColorName(user.userScore);
    }

    private void RetrieveFromDatabase(){
        StartCoroutine(GetUserDat("https://forunity-e2ac2.firebaseio.com/"+ nameText.text +".json"));
    }

    private void ChangeColorName(int score){
        //Debug.Log(score);
        if(score < 25){
            // red
            targetObject.GetComponent<Renderer>().material.color = Color.red;
        } else if (score < 50){
            // yellow
            targetObject.GetComponent<Renderer>().material.color = Color.yellow;
        } else if (score < 75){
            // green
            targetObject.GetComponent<Renderer>().material.color = Color.green;
        } else {
            // blue
            targetObject.GetComponent<Renderer>().material.color = Color.blue;
        }
        
    }

    //SendWebRequest
    private IEnumerator Put(string url, string jsonStr){
        //UnityWebRequestを生成する
        UnityWebRequest request = UnityWebRequest.Put(url, jsonStr);

        //SendWebRequestを実行して送受信開始
        yield return request.SendWebRequest();

        //エラー判定
        if(request.isHttpError || request.isNetworkError){
            //エラーログ
            Debug.Log(request.error);
        } else {
            //結果確認
            Debug.Log(request.downloadHandler.text);
        }
    }
    private IEnumerator GetUserDat(string url){
        //UnityWebRequestを生成する
        UnityWebRequest request = UnityWebRequest.Get(url);
        request.downloadHandler = new DownloadHandlerBuffer();

        //SendWebRequestを実行して送受信開始
        yield return request.SendWebRequest();

        //エラー判定
        if(request.isHttpError || request.isNetworkError){
            //エラーログ
            Debug.Log(request.error);
        } else {
            // json -> c# で使える形式に直さないとならない...
            user = JsonUtility.FromJson<User>(request.downloadHandler.text);
            UpdateScore();
            
            //結果確認ログ
            Debug.Log(request.downloadHandler.text);
        }
    }
}
```

→　問題なく登録・更新・取得できました！！

---
##### :alien:振り返り:alien:

前回 Rest Client for Unity というライブラリを使った Firebase とのやりとり部分を Unity提供の関数を使ったらどんな記述になるのかな、と思い立って書き換えてみましたが、
そもそもC#に不慣れなので、コルーチンやらラムダ式やらも調べつつで丸一日費やし、Unityの先生に助言もいただき、なんとか書き換えることができました。。。prz

感想としては、便利なライブラリはとってもありがたいものなんだな、です！
これからは便利ライブラリをバンバン使って実装時間を短縮して作りたいものを早く作る方に重点を置いて行きたいなと思いました！

以上！