Unity4.6オープンβでチュートリアルのShoothing Game作ってみる その参


##やる事
2Dシューティングチュートリアルのモバイル編やる！
はずだったんですが、第04回まではサクッと終わってしまいました。

が。。。

その第04回が問題で、Asset Store経由で落としてくる素材の中にGUI Textureがあるので、
その辺りの代替案とか考えないといけない。
というか、Asset Store経由の物Gitしちゃうとアウトだと思うので、I/Fは自作しました！

という事で、

- スマホ用I/F自作
- Waveデータのネットワーク取得

辺りをやっていきます！

##第04回 バーチャルスティック対応代替自作I/F
そもそも僕的にバーテャルスティックというのが、あんまり好きじゃない上に、
そのまんま再現するのはあんまりな〜と言う感じだったので、
シューティングで良くある画面ドラッグで移動する仕様にしました。
実際にはこんな感じ

```c#:Player.cs
	void Update ()
	{
		// 右・左
		float x = Input.GetAxisRaw ("Horizontal");
		
		// 上・下
		float y = Input.GetAxisRaw ("Vertical");
		
		// 移動する向きを求める
		Vector2 direction = new Vector2 (x, y).normalized;
		
		// 移動の制限
		Move (direction);
		
	}
```
このメソッド内を大胆に一新して

```c#:Player.cs
	void Update ()
	{
		if (Input.touches.Length > 0) {
			Touch touch = Input.touches [0];
			switch (touch.phase) {
			case TouchPhase.Began:
				offset = touch.position;
				break;
			case TouchPhase.Moved:
				Vector2 move = touch.position;
				Vector2 diff = offset - move;
				Move(diff / -transferResistance);
				offset = move;
				break;
			case TouchPhase.Ended:
			case TouchPhase.Canceled:
				offset = Vector2.zero;
				break;
			}
		}
	}
```

こんな感じにしてみました。
スマホでのタッチイベントはInput.touches配列の中にTouchクラスとして格納されるようなので、
１本目（touchesと言うだけあって、マルチタッチすると複数入ってくるもよう）のTouchクラスの状態（phaseパラメータ）を監視、
Beganで基準座標とって、Movedで動いた分の差分をMove関数に渡してるって仕組み
ちなみに、transferResistanceはpublic float値でインスペクターから設定できるようにしてあります。この値で移動値を割ってあげないと自機がマッハですっ飛んで行くので、適当な値で調整必須です。

## Waveデータをネットワーク越しに取得する
前回の記事で書いたけど、チュートリアルの第12回に置いてあるWave.unitypackageをそのまま使った場合、
Enemy Prefabが衝突しちゃうようなので、一から一つ一つ設定するのもめんどいなーと思い、
サーバーから位置情報取得すれば良いという答えに辿り着きました。

まず、wave情報が記述されたjsonを作る

```php:wave.php
<?php
$json = array(
	array(
	    array('x' => "0", 'y' => "0"),
    	array('x' => "0.5", 'y' => "1"),
    	array('x' => "-0.5", 'y' => "1"),
    	array('x' => "1", 'y' => "2"),
    	array('x' => "-1", 'y' => "2"),
	),
	array(
	    array('x' => "1", 'y' => "0"),
    	array('x' => "-1", 'y' => "0"),
    	array('x' => "0.5", 'y' => "1"),
    	array('x' => "-0.5", 'y' => "1"),
    	array('x' => "0", 'y' => "2"),
	),
);
 
header("Content-Type: application/json; charset=utf-8");
echo json_encode($json);
exit();
?>
```
折角の機会だったので、phpで書いてみました。
なんか、もっと効率的な書き方あるんでしょうけど、門外漢なんでわかりません。。。
まぁ、出来はともかく、これをサーバーに設置して
Initialize.csを生成、Main Cameraにくっつけて、そこからデータを取得するようにする事に。
今回、jsonファイルのパースが必要になるので、今回[MiniJSON](https://gist.github.com/darktable/1411710)のライブラリを活用させて頂きました。

```c#:Initialize.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using MiniJSON;

public class Initialize : MonoBehaviour {
	
	public GameObject emitter;

	// domain値は自身のテストサーバーのドメインを指定して下さい。
	public static string domain = "http://192.168.40.24/";

	void Start () {
		StartCoroutine (ConnectWave(domain + "wave.php"));
	}
	
	// Update is called once per frame
	void Update () {
		
	}

	private IEnumerator ConnectWave(string url) {
		Debug.Log (url);
		WWW www = new WWW (url);
		yield return www;
		if (www.error == null) {
			IList json = (IList)Json.Deserialize (www.text);
			List<List<Vector2>> list = new List<List<Vector2>> ();
			foreach (IList l in json) {
				List<Vector2> positions = new List<Vector2> ();
				foreach (IDictionary item in l) {
					// ここfloat値で直接取れればもっと簡単な文になりそうなのに。。。自作phpぇ。。。
					float x = float.Parse ((string)item ["x"]);
					float y = float.Parse ((string)item ["y"]);
					positions.Add (new Vector2 (x, y));
				}
				list.Add (positions);
			}
			Emitter e = emitter.GetComponent<Emitter> ();
			e.waves = list;
		} else {
			Debug.Log(www.error.ToString());
		}
		yield break;
	}

}
```

取得出来たjsonデータをパースしてVector2のListに変換、Emitterクラスにそのリストを渡して上げるって流れです。
今回、WaveはPrefabではなく、jsonから生成になるので、Emitter.csも書き換え

```c#:Emitter.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Emitter : MonoBehaviour {
	
	public GameObject enemy;
	public GameObject managerObject;
	[HideInInspector]
	public List<List<Vector2>> waves;
	
	void Start ()
	{
		StartCoroutine (createWave ());
	}
	
	private IEnumerator createWave ()
	{
		int current = 0;
		Manager manager = managerObject.GetComponent<Manager> ();
		while (true) {
			while(manager.IsPlaying() == false) {
				yield return new WaitForEndOfFrame ();
			}
			List<Vector2> positions = waves[current];
			foreach (Vector2 pos in positions) {
				GameObject e = (GameObject) Instantiate(enemy, new Vector3(pos.x, pos.y, 0), Quaternion.identity);
				e.transform.parent = transform;
			}
			while (transform.childCount != 0) {
				yield return new WaitForEndOfFrame ();
			}
			if (waves.Count <= ++current) {
				current = 0;
			}
		}
	}
}
```
Wave Prefab郡は全部必要なくなったので、全部消してしまいましょう。
再生して、エラーなく動けば完成です！

##まとめ
今回でタッチイベント、ネットワーク同期、GameObject動的生成とかなり本格的？な実装になりました。
途中、不細工なphpとか出てますが、直接.jsonファイル作っちゃった方が早いので、
急いでいる方はそちらの方法でも問題無いと思います。
次回があればネットワーク使ってランキングとか作りたいですね。