【Unity】CSVとScriptableObjectどちらの形式でマスターデータを管理したほうが読み込み速度が高速になるか検証しました

現在開発中のゲームでマスターデータをCSVで管理しているのですが、
マスターデータをCSVで管理する方法と
ScriptableObjectで管理する方法のどちらがより高速に
データを読み込むことができるのかが気になったので調査してみました

## 検証環境

- Unity：5.3.1f1  
- OS：Android  
- モデル番号：Nexus 7  
- Androidバージョン：5.0.1 

## マスターデータ

今回は下記のようなマスターデータを管理するクラスを用意しました

```cs
// タイプを管理する列挙型
public enum TYPE
{
}

// ステータスを管理するクラス
[Serializable]
public class Status
{
    public int      dex_no              ; // 図鑑 No.
    public string   name                ; // 名前
    public TYPE     type1               ; // タイプ 1
    public TYPE     type2               ; // タイプ 2
    public string   ot                  ; // 親
    public int      id_no               ; // ID No.
    public int      exp_points          ; // 現在の経験値
    public int      exp_to_next_lv      ; // 次のレベルまでに必要な経験値
    public int      hp_current          ; // HP 現在値
    public int      hp_max              ; // HP 最大値
    public int      attack              ; // 攻撃
    public int      defense             ; // 防御
    public int      attack_sp           ; // 特攻
    public int      defense_sp          ; // 特防
    public int      speed               ; // 素早さ
    public int      arena_trap_name     ; // 特性名前
    public int      arena_trap_detail   ; // 特性詳細
}
```

## 読み込む方法

### CSV から読み込む方法

ResourcesフォルダからCSVを読み込んで
Statusクラスのインスタンスを生成します

![alt](http://cdn-ak.f.st-hatena.com/images/fotolife/b/baba_s/20160110/20160110102244.png)

```cs
var list = new List<Status>();
var textAsset = Resources.Load<TextAsset>( "status_master" );
var text = textAsset.text;
var row = text.Split( '\n' );
for ( int i = 0; i < row.Length; i++ )
{
    var column = row[ i ].Split( ',' );
    var status = new Status
    {
        dex_no              = int.Parse( column[ 0 ] ), 
        name                = column[ 1 ], 
        type1               = ( TYPE )( int.Parse( column[ 2 ] ) ), 
        type2               = ( TYPE )( int.Parse( column[ 3 ] ) ), 
        ot                  = column[ 4 ], 
        id_no               = int.Parse( column[ 5 ] ), 
        exp_points          = int.Parse( column[ 6 ] ), 
        exp_to_next_lv      = int.Parse( column[ 7 ] ), 
        hp_current          = int.Parse( column[ 8 ] ), 
        hp_max              = int.Parse( column[ 9 ] ), 
        attack              = int.Parse( column[ 10 ] ), 
        defense             = int.Parse( column[ 11 ] ), 
        attack_sp           = int.Parse( column[ 12 ] ), 
        defense_sp          = int.Parse( column[ 13 ] ), 
        speed               = int.Parse( column[ 14 ] ), 
        arena_trap_name     = int.Parse( column[ 15 ] ), 
        arena_trap_detail   = int.Parse( column[ 16 ] ), 
    };
    list.Add( status );
}
```

### ScriptableObject から読み込む方法

ResourcesフォルダからScriptableObjectを読み込んで
Statusクラスの配列を取得します

![alt](http://cdn-ak.f.st-hatena.com/images/fotolife/b/baba_s/20160110/20160110102252.png)

```cs
[CreateAssetMenu]
public class StatusMaster : ScriptableObject
{
    public Status[] statuses;
}
```

```cs
var statusMaser = Resources.Load<StatusMaster>( "status_master" );
var list = new List<Status>( statusMaser.statuses );
```

## 読み込み時間(秒)の比較

|形式|1,000件|10,000件|100,000件|
|:--|:--|:--|:--|
|CSV|<span style="color: #d32f2f">0.027252200</span>|<span style="color: #d32f2f">0.2178650000</span>|<span style="color: #d32f2f">2.258942000</span>|
|ScriptableObject|<span style="color: #1464b3">0.003875732</span>|<span style="color: #1464b3">0.0001525879</span>|<span style="color: #1464b3">0.001434326</span>|

## まとめ

ScriptableObjectの方がCSVよりも読み込む速度が早いことがわかりました
CSVの場合は特定のインスタンスに変換するために
文字列操作したり型変換する必要がありますが
ScriptableObjectの場合は特定のインスタンスの要素を
そのまま保持しておけるためだと思います

## 検証用のスクリプト

https://gist.github.com/baba-s/08b18249a857d648dd36
https://gist.github.com/baba-s/d6b46fe4baac6a162695

## 検証用のUnityパッケージ

https://dl.dropboxusercontent.com/u/52568393/koganeblog/csv_vs_scriptable_object.unitypackage