Unityでのイデアをどう記述するのか?

なんとなく、某、中2病的な記事を書くかもしれません。

# イデア

Unityでは、シーンがあり、それはオブジェクトで構成されています。そして、オブジェクトはゲームにおける「もの」を表現します。ゲームの世界で「存在しているモノ」です。しかし、ゲームは「その世界に存在しているモノ」だけで成りたつものでは無く、むしろ、**目に見えない概念**があります。たとえば、「**得点**」や「**ルール**」「**システム**」「**時**」などです。そして、それをここでは「**イデア**」と呼びましょう。(哲学的な思索は他の人にまかせます) 

# イデアはどう記述されるか?

さて、ゲームにおいて、イデアを記述するにはどうすれば良いでしょうか? ここでは、ゲームにおいて「**得点**」を表現することを考えてみましょう。つまり、得点はどこに記述すれば良いのでしょうか?

それにはいくつか方法が考えられるでしょう。先の[12/16日のadvent calendarの記事](http://d.hatena.ne.jp/komiyak/20141216/1418760578)にもあるように

* 得点をゲームオブジェクトとして扱かい、それをFindする方法。
* シングルトン

があると思います。ただし、僕はもう一つあって、

* Scriptableオブジェクトを使う

があるように思えます。さて、ここではそれぞれを考察して行きましょう。そして、最後にScriptableオブジェクトを利用してMVC的なアプローチを考えたいと思います。


## 得点をゲームオブジェクトとして扱かい、それをFindする方法。

### 実装

さて、まず、得点オブジェクトを作ります。

![スクリーンショット 2014-12-19 16.29.30.png](https://qiita-image-store.s3.amazonaws.com/0/31381/62b4de68-285b-843d-fcd7-279488c1116e.png)

さて、このScoreオブジェクトに、次のようなScriptComponentを追加します。

```csharp
using UnityEngine;
using System.Collections;

public class Score : MonoBehaviour { 
	private int point;

	// Use this for initialization
	void Start () {
		this.point = 0;
	}

	public void AddScore(int p){
		this.point += p;
	}

	public void showScore(){
		Debug.Log (this.point);
	}

}

```

そうしてできた、Scoreオブジェクトを、Findを使い探せば良いのですね。マウスをクリックしたら、得点することにしましょう。

```csharp
using UnityEngine;
using System.Collections;

public class PointGetter : MonoBehaviour {
	private Score score;
	// Use this for initialization
	void Start () {
		this.score = GameObject.Find("Score").GetComponent<Score>();
	}
	
	// Update is called once per frame
	void Update(){
		if( Input.GetMouseButtonDown(0) ){
			this.score.AddScore(1);
			this.score.showScore();
		}
	}

}

```

### 考察

さて、この方法は実は僕はあまり好きではありません。その理由は2つあります。

1つめに、**Unityのシーンのオブジェクトの階層構造に依存している**ということにあります。たとえば、間違って、Scoreオブジェクトをシーンの階層から削除してしまったり、名前を変えてしまったり、名前が重複したりすれば、途端にゲームは例外を吐いて、得点が動かなくなったりするかもれません。

2つめに、**そもそも、得点がゲーム内のモノではないにもかかわらず、ゲームのオブジェクトとなっている**ということです。先程言いましたが、得点は**イデア**であり「そのゲームの世界のモノ」では無く、概念であるということです。得点をScoreオブジェクトとして、シーンに取り入れることは、**得点という概念をモノ化**しているということです。そしてそれは、**モノであるために余計が情報が付加**されており、とても気持ちが悪いということです。**得点が座標を持っているなんてキモチワルイ**と思いませんか?


これが、もし1人か小規模の人数の短期の開発であれば、このようなやりかたは有効でしょう。しかし、もし長期で、多人数で、エンジニア以外(コードを書かない人)がUnityで作業するときには、あまり良くない方法だと思います。


## シングルトンを使う方法

### 実装

得点をシングルトンで表現しましょう。

```csharp
using UnityEngine;

public class Score  { 
	private int point;

	private static Score instance = new Score();

	public static Score GetInstance(){
		return instance;
	}

	private Score (){
		this.point = 0;
	}

	public void AddScore(int p){
		this.point += p;
	}

	public void showScore(){
		Debug.Log (this.point);
	}

}

```

さて、このオブジェクトにアクセスするには、クラスから辿れば良いですね。

```csharp
using UnityEngine;
using System.Collections;

public class PointGetter : MonoBehaviour {
	private Score score;
	// Use this for initialization
	void Start () {
		this.score =  Score.GetInstance();
	}
	
	// Update is called once per frame
	void Update(){
		if( Input.GetMouseButtonDown(0) ){
			this.score.AddScore(1);
			this.score.showScore();
		}
	}

}

```

### 考察

先程の、Findを使う実装よりかは、マシだと個人的には思います。Unityのシーンの階層構造に依存せずに、**得点計算がスクリプトのみで完結している**というのが個人的には好きです。

しかし一方で欠点もあります。それは、シングルトン自体の、問題です。

* 基本的にグローバル変数と似たようなものであり、依存性が分かりづらい。
* 密結合になりやすい
* テストがしにくい

などなど、たぶんここらへんは、オブジェクト指向の設計をやっていれば大抵は理解できるでしょう。

また、**そもそもイデアは一つだとは限らない**ということです。シングルトンパターンは、その**オブジェクトが確実に一つだと分かる**時に使うべきです。

## Scriptableオブジェクトを使う方法

### 実装

さて、得点をscriptableオブジェクトにしてみましょう。

```csharp
using UnityEngine;

public class Score  : ScriptableObject { 
	public int point = 0;

	public void AddScore(int p){
		this.point += p;
	}

	public void showScore(){
		Debug.Log (this.point);
	}

}
```

さて、次に、Scriptableオブジェクトを生成します。次のコードはassetsに置けば勝手に実行し、スクリプタブルオブジェクトができます。

```csharp
using UnityEngine;
using UnityEditor;

[InitializeOnLoad]
public class NewBehaviourScript {
	static NewBehaviourScript (){
		Score item = ScriptableObject.CreateInstance<Score>();
		
		string path = AssetDatabase.GenerateUniqueAssetPath("Assets/" + typeof(Score) + ".asset");
		
		AssetDatabase.CreateAsset(item, path);
		AssetDatabase.SaveAssets();
	}

}

```

さて、あとは使いましょう。

```csharp
using UnityEngine;
using System.Collections;

public class PointGetter : MonoBehaviour {
	public Score score;

	// Update is called once per frame
	void Update(){
		if( Input.GetMouseButtonDown(0) ){
			this.score.AddScore(1);
			this.score.showScore();
		}
	}

}

```

そして、ScoreのScriptableオブジェクトを追加しておきます。

![スクリーンショット 2014-12-19 17.24.23.png](https://qiita-image-store.s3.amazonaws.com/0/31381/ef2af98e-d08c-3807-feaf-758e2478d903.png)

### 考察

うーん、これも微妙な気がします。**得点をゲームオブジェクト化するよりかは、余計な情報が無い**のは利点ですが、**コードのみで完結しません**。

おそらく、Scriptableオブジェクトの管理をうまくやればこのようなやり方は一番良いのでは?と思います。

それには、**Scriptableオブジェクトを含んだプレハブ化**が有効な気がしています。なぜなら、比較的にシーンの状態よりAssetの状態の変更が少なく、プレハブ化によって、Scriptableオブジェクトとコンポーネントの**依存関係が壊れにくいのでは?**とは思います。


# MVC的なアプローチ

そもそも、**ゲームにおけるイデアはつまり、MVCのモデル**に相当するのではないかと勝手に思っています。

とすれば、過去にあるMVCの設計をそのまま、ゲームに持ち込めば良いのではと思います、ので、その実装を考えてみましょう。

### 実装

まず、モデルクラスを実装してみましょう。

```csharp
using UnityEngine;

public delegate void UpdateHandler();

public class Score : ScriptableObject { 
	public int point;
	public event UpdateHandler Update;

	public Score(){
		this.point = 0;
	}

	public void AddScore(int p){
		this.point += p;
		this.Update();
	}
}
```

さて、ここでオブザーバーパターンを使っています。なので、delegateで、状態の変更をViewに通知するってことになります。

さてViewを作りましょう。

```csharp
using UnityEngine;
using System.Collections;

public class PointViewer : MonoBehaviour {
	public Score score;
	// Use this for initialization
	void Start () {
		this.score.Update += PointShow;	
	} 

	void PointShow(){
		Debug.Log (this.score.point);
	}
}
```

一応、コントローラーです。先程の実装から変わってません。

```csharp
using UnityEngine;
using System.Collections;

public class PointGetter : MonoBehaviour {
	public Score score;

	// Update is called once per frame
	void Update(){
		if( Input.GetMouseButtonDown(0) ){
			this.score.AddScore(1);
		}
	}

}
```

そして最後に、繋げましょう。

![スクリーンショット 2014-12-19 18.18.42.png](https://qiita-image-store.s3.amazonaws.com/0/31381/bf044da0-d875-cdb7-f1c3-8f70f3ae74b5.png)

## 考察

これを実装しながら思うには、結局のところ**初期化処理をコードでやるか、UnityEditorでやるか**の違いがあるように思えました。



## まとめ。

なんか上手く行かないにゃあー。