UnityでScriptableObjectを使ってみた、NPOIを使用してExcelデータを読み込んでみた

2022.4.27 9日目　昨日の投稿忘れていたので、再開です。

## 目標
今回はUnityのScriptableObjectというものを使ってマスタデータを作成していきます。

## 参考資料
https://moon-bear.com/2021/01/02/use-scriptable-object/
https://ymgsapo.com/2021/03/01/unity-scriptable-object/
https://www.urablog.xyz/entry/2017/03/28/235739
https://hiyotama.hatenablog.com/entry/2019/08/27/110000

## どんな場面で使用するものなのか
#### ・共通データの管理
→敵キャラの最大HPなど、共通のデータを持つものに対して使用できる

#### ・シーンをまたぐデータの保持
→シーンをまたぐデータを保持したいときは、「DontDestroyOnLoadしたゲームオブジェクトに値を持たせる」方法が見受けられるそうです。
一方で、このような場合にはScriptableObjectを使うと便利です。理由は、
 ・ScriptableObjectはどのシーンからでも参照することができる
（ゲームオブジェクトのようにシーンに依存しない）
・ScriptableObjectはあらかじめインスペクターに登録することができる（シリアライズが可能）

#### ・イベントの管理

## 実践
では実際にUnityでScriptableObjectを使用していきます。

### assetファイルの作成

どのようなデータを持たせるのかを記載したスクリプトを書いていきます。
```C#
//ScriptableObject作成

using System;

//ScriptableObject作成

[CreateAssetMenu( fileName = "MissionInfo")]
public class ScriptableTest: ScriptableObject {
    public List<Mission> missionList = new List<Mission>();
}

[Serializable]
public class Mission {
    //ミッションID
    public int id;
    //次のミッション
    public int nextMissionId;
    //ミッション内容
    public string missionDetail;
}
```
ここからはスクリプトの説明です。
```C#
[CreateAssetMenu( fileName = "MissionInfo")]
```
スクリプトの説明後にある、Projectを右クリック～　の動作を実現できるのがこの一文らしいです。この一文を追加することで右クリック＞Create　にスクリプト名（このタブ名は変更可能、とのこと！）が追加され、assetファイルを作成することができるそうです。

```C#
public class ScriptableTest: ScriptableObject {
```
次に、「ScriptableObject」を継承します。
（要は使えるようにします。（私の解釈で申し訳ありません＞＜。）

```C#
[Serializable]
public class Mission {
```
参考にさせていただいたサイトに、[Serializable]とあり、なんぞやと思ったので調べてみると、「ここでのシリアライズは「直列化」と訳され、メインメモリ上に存在しているオブジェクトなどのデータを文字列やバイト列に変換することを指します。これには、ファイルとして保存したり、ネットワークで送受信したりできるようになるというメリットがあります。

逆に、シリアライズされたデータをもとの状態に復元することをデシリアライズと言います。」　だそうです。

https://www.fenet.jp/dotnet/column/language/4515/

クラスの中は、含めたいデータを変数として宣言しておきます！

説明は以上です。

スクリプトを作成したら、Projectを右クリック＞Create＞作成したスクリプト名　と選択していきます。
![bandicam 2022-04-27 12-21-45-101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940156/028e2fa5-aaea-461a-420e-07beb8f0b798.jpeg)

すると以下のようなassetファイルが作成されます
![bandicam 2022-04-27 14-41-40-334.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940156/8d808690-bffa-53d8-841d-583d9dbd3407.jpeg)

これでScriptableObjectの作成はできたかと思います。

### 別のスクリプト上での呼び出し方

方法はいくつかあるそうですが一番オーソドックスな方法で行きます。

単純にSerializeFieldでInspecterにアタッチして使用する方法です。
```C#
[SerializeField] private ScriptableTest m_infomation = null;
```
（ただアタッチして使用するのは、色々な場所で参照することになると大変そうですね…）

実際に呼び出してみた↓
```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MasterDataController: MonoBehaviour {

    [SerializeField] private ScriptableTest m_infomation = null;

    // Start is called before the first frame update
    void Start() {
        foreach( var mission in m_infomation.missionList ) {
            Debug.Log( "ID:" + mission.id + " " + "mission:" + mission.missionDetail + " " + "NextMissionID:" + mission.nextMissionId );
        }
        
    }

    // Update is called once per frame
    void Update() {

    }
}
```

ScriptableObjectのinspector↓
![bandicam 2022-04-27 14-56-45-780.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940156/c8cd3b40-ecdc-2679-6f22-d9be867605a2.jpeg)

実行結果↓
![bandicam 2022-04-27 14-56-34-136.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940156/cf88a31d-f250-9324-ea9c-e3747be7005d.jpeg)

となりました。かなり簡単に呼び出しができました。

## Excelからデータの読み込み

まずはExcelからデータを読み込んでみます。
今回はNPOIを使用していきます。

### 準備
NPOIのインポートをしていきます。
ダウンロードすると、拡張子が「.nupkg」となっていると思います。そのままだと解凍できないので、「.zip」とすると解凍できるようになります）

https://www.nuget.org/packages/NPOI/2.5.1

（解凍したフォルダ内lib/net45内のもの全て）

https://www.nuget.org/packages/Portable.BouncyCastle/

（解凍したフォルダ内lib/net40内のもの全て）

https://www.nuget.org/packages/SharpZipLib/

（解凍したフォルダ内lib/net45内のもの全て）

入れると以下のようになっているはずです。
（今回はAsset下にEditer/npoiフォルダを作成して、そこにインポートしています）
![bandicam 2022-04-27 17-42-22-993.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940156/19eea665-f62e-e1f8-1ec7-2f40e7626861.jpeg)

これで準備完了です。

### Excelデータの読み込み
こちらを参考にさせていただきました。

https://resanaplaza.com/%E3%80%90c%E3%80%91npoi%E3%81%A7excel%E7%B0%A1%E5%8D%98%E6%93%8D%E4%BD%9C%EF%BC%88%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E4%BB%98%E3%81%8D%EF%BC%89/

```C#
using System.IO;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.Util;
using NPOI.SS.Util;
using UnityEngine;

public class ExcelToScriptableObject: MonoBehaviour {

    // Start is called before the first frame update
    void Start() {

        if( !File.Exists( @"C:\StudyUnity\ScriptableObjectStudy\Assets\Script\MissionMasterData.xls" ) ) {
            return;
        }
        //Excelブックを開く
        IWorkbook book = WorkbookFactory.Create( @"C:\StudyUnity\ScriptableObjectStudy\Assets\Script\MissionMasterData.xls" );

        CellReference reference = new CellReference( "B5" );
        IRow row = book.GetSheetAt( 0 ).GetRow( reference.Col );
        ICell cell = row.GetCell( reference.Col );
        var str = cell.StringCellValue;

        Debug.Log( str );

    }
```

まずは試しに↑のようなコードを書いてみました。（読み込みのみしてみました）A1形式で読み込みをしております。

以下コードの説明です。

```C#
using System.IO;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.Util;
using NPOI.SS.Util;
using UnityEngine;
```
必要なusingディレクティブを追加します。


```C#
if( !File.Exists( @"C:\StudyUnity\ScriptableObjectStudy\Assets\Script\MissionMasterData.xls" ) ) {
   return;
}
```
ここで読み込むExcelデータがあるかどうかを検索して、無ければ関数を抜ける処理をしています。（必要ないとは思いますが念のためかいてあります）


```C#
IWorkbook book = WorkbookFactory.Create( @"C:\StudyUnity\ScriptableObjectStudy\Assets\Script\MissionMasterData.xls" );
```
読み込むExcelデータを開きます。

```C#
CellReference reference = new CellReference( "B5" );
```
A1形式で読み込むセルを指定します。

```C#
IRow row = book.GetSheetAt( 0 ).GetRow( reference.Col );
ICell cell = row.GetCell( reference.Col );
```
book.GetSheetAt( 0 )→どのシートを指定するか
GetRow( reference.Col )→どのセルか
ICell cell = row.GetCell( reference.Col );→セルの情報を読み込み

```C#
var str = cell.StringCellValue;
```
cell.StringCellValue 今回はStringを読み込んだのでこのように書きましたが、どのような値を読み込むかで変わってくるようです。

これを実行すると以下のようになります。（MasterDataに使用するExcelによって変わります）
![bandicam 2022-04-27 18-01-12-536.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940156/701f14a9-cc5a-270b-e86e-44cedfc120e6.jpeg)


明日は続きをやっていきます。