UniRx

最近になって、Reactive Extensions通称Rxというのが気になってたのですがUnityにもUniRxというのがあるので試してみた。
C#で実装されている機構なんだけどこの機能はLINQとの関連が深いのでまずはLINQをある程度理解していないといけない。
そもそもC#でデータの問い合わせをするにはLINQ以前は

IEnumerable<Character> q =
	from c in Characters
	where c.hp >= 100
	select c;

こんな感じでプログラムとは分離されたSQL的な書き方をしていたらしい。
それがLINQを使うと

IEnumerable<Character> q = this.Customers
				.Where(c => c.City == "London")
				.Select(c => c);

こんな感じで、見やすいメソッドになる。
データベースに限らずデータの集合(XMLやJSON)なども同じ機構で扱えるようにしたのがLINQ to XMLやらLINQ to JSONというものらしい。
C#のIEnumerable<T>の型に対してLINQが適応できて、例えばListのようなデータに対して偶数(Where)のものを3つ(Take)取得するとすると。

List<int> list = new List<int>(){1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
IEnumerable<int> numsEnumerable = list.Where(_ => _ % 2 == 0).Take(3);
foreach (int num in numsEnumerable) {
	Debug.Log(num); // 2, 4, 6
}

こんな感じになる。
データの最大値を取得したり、平均を算出したりなどデータ群に対して抽出や操作ができる。
参考)
地平線に行く | LINQの拡張メソッド一覧と、ほぼ全部のサンプルを作ってみました。

C#の強みはLINQと言われているくらいなんだけど、どうもUnityではiOSに書き出した際に落ちることがあるらしい。詳細はこちら
Qiita | やっぱりUnityでもC#なんだからLINQが使いたい!

LINQはデータ群を扱う為のものですが、「イベントもタイムライン上で順番に並べるとそれも一つの配列と見なせ、LINQのような機構をつかってイベントをフィルタリングやデータを操作できますよね。」っていう変態的な考えを誰かが考えた!それがReactive Extensions。
JavaScriptですがこちらの記事がわかりやすい。
LIG Inc | 「RxJS」初心者入門 – JavaScriptの非同期処理の常識を変えるライブラリ

最初にMicrosoft DevLabsに2009年に登場したようでまだ新しい技術ですね。これがだんだんとjsやphpなどでも広がっていき言語を超えた機構として広まっているみたいです。

LINQもまったく使ったことがなかったので、LINQも含め幾つかのサンプルを作ってUniRxを試してみた。
(1つ落ちるサンプルがあるけど、なにか間違っているのかな…?)
あとは開発者さんのところで開催された勉強会の資料なんかも読むと良さそうです。

第一回UniRx勉強会を開催しました+スライドまとめ

LINQのSelectManyは理解に時間がかかったけど、こちらを参考に勉強した。
[C#・LINQ]九九だけじゃない!アプリ開発にもゲーム開発にも使える、SelectMany!
Rxの場合はSelectManyはストリームの流れを変えるようなときに使われるって感じでしょうか。

Continue…

動的にボタンにデータを持った機能を加える

※)15.06.06 一番下に追記あり

動的にボタンを作成したときに、それぞれのボタンに対して情報を分けた処理をさせたい。
ラムダ式でパラメータ渡そうと思ったけどうまく行かない。

using UnityEngine;
using UnityEngine.UI;
using System;

public class Test : MonoBehaviour {
	// ボタンのプレハブ
	public GameObject buttonPrefab;

	// Start.
	void Start () {
		for (int i = 0; i < 10; ++i) {
			GameObject buttonGO = (GameObject)Instantiate(this.buttonPrefab);
			buttonGO.transform.SetParent(this.transform, false);

			Button button = buttonGO.GetComponent<Button>();
			button.onClick.AddListener(() => {
				this.DoSomething(i);
			});
		}			
	}

	// なにか処理する
	void DoSomething(int num) {
		print(num);
	}
}

Continue…

継承先から親クラスのイベントの発行

継承先から親クラスのイベントを発行しようとした際に

`****’ can only appear on the left hand side of += or -= when used outside of the type ` ****’

こんなエラーが出た。

どうも
event EventHandler MyEvent;
と定義をした際には実際には

private EventHandler _myEvent;

public EventHandler MyEvent {
	add(EventHandler handler) { 
		this._myEvent += handler;
	}
	remove(EventHandler handler) {
		this._myEvent -= handler;
	}
}

こんな展開がされているらしい。
ここで、_myEventはprivateなので継承先からは処理が呼べないらしい。
なので、継承元に

protected CallMyEvent() {
	this.MyEvent(this, EventArgs.Empty);
}

などを準備して、継承先から読んであげる必要があるようです。

参考)
devlog [naru design] | Unity3D:スーパークラスのeventをサブクラスから呼び出す
stackoverflow | Why can’t I invoke PropertyChanged event from an Extension Method?

LINQ

C#ではLINQという機能がありますがよく知らなかったので試してみました。
基本的にはSQLを文字列ではなく言語の持つ機能として作られたものがLINQ(統合言語クエリ)というもののようです。
Unityでは直接DBを扱う事というよりはコレクションを操作して別のコレクションを作るときに使えます。
例えばGameObjectのコレクションの中からposition.x > 0のものだけを選ぶ場合。

		List<GameObject> gameObjects = new List<GameObject>();

		for (int i = 0; i < 10; ++i) {
			GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
			go.name = "GameObject" + i.ToString();
			gameObjects.Add(go);
			go.transform.position = new Vector3(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10));
		}

		foreach (GameObject go in gameObjects.Where(go => go.transform.position.x > 0)) {
			go.renderer.material.color = Color.red;
		}

Continue…

値を持つイベント

値を持つEventArgsを作りたく、値も型に依存しないものにしたかったので調べたらこんなやり方があった。

[ EventValue Class ]

using System;

/// <summary>
/// 値を持つEventHandler。
/// </summary>
public class EventValue<T> : EventArgs {
	/// <summary>
	/// 値。
	/// </summary>
	public T value;

	/// <summary>
	/// コンストラクタ。
	/// </summary>
	public EventValue(T value) {
		this.value = value;
	}
}

使う側(EventValueにColorを保持)

using UnityEngine;
using System.Collections;

/// <summary>
/// EventValueのテスト。
/// </summary>
public class EventTest : MonoBehaviour {
	/// <summary>
	/// EventValueを使用したdelegateの定義。
	/// </summary>
	public delegate void EventColorHandler(object sender, EventValue<Color> evt);

	/// <summary>
	/// EventColorHandlerのイベント。
	/// </summary>
	public event EventColorHandler OnChangeColor;

	/// <summary>
	/// Start.
	/// </summary>
	void Start () {
		this.OnChangeColor += this.OnChangeColorTest;
		this.OnChangeColor(this, new EventValue<Color>(Color.red));
	}

	/// <summary>
	/// イベントを受け取る。
	/// </summary>
	void OnChangeColorTest(object sender, EventValue<Color> evt) {
		print(evt.value);
	}
}

base.Awake(), base.Start()などの呼び方

MonoBehaviour <= SuperClass <= SubClass この継承関係の場合、SubClassからSuperClassのAwake()を呼ぶため [unitycsharp] void Awake() { base.Awake(); } [/unitycsharp] これだとエラーになる。 SuperClassのAwakeをvirtualとし、SubClassのほうでoverrideを指定するとうまく呼べる。 [unitycsharp] public class SuperClass : MonoBehaviour { public virtual void Awake() { print("Super.Awake()"); } } public class SubClass : SuperClass { public override void Awake() { print("SubClass.Awake()"); } } SubClass sub = new SubClass(); sub.Awake(); [/unitycsharp]

コルーチンについて

あまり理解せずにコルーチンを使用していたので、もう少しちゃんと理解しようと見直してみた。
そもそもコルーチンとは。。。
以下Wikipediaより。

コルーチン(英: co-routine)とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞 co は協調を意味するが、複数のコルーチンが中断・継続により協調動作を行うことによる。
サブルーチンと異なり、状態管理を意識せずに行えるため、協調的処理、イテレータ、無限リスト、パイプなど、継続状況を持つプログラムが容易に記述できる。
コルーチンはサブルーチンを一般化したものと考えられる。コルーチンをサポートする言語には Modula-2、Simula、Icon、Lua、C#、Limbo などがある。マルチスレッドで原理的には同じことができるため、現在はそちらが使われるケースが多い。

ということで、処理を中断し再び呼び出すと続きから再開できるということのようです。
Continue…

ローディング

Unityでローディングをする際のテスト。基本的にはWWWクラスで簡単に処理ができる。FlashでいうURLLoaderのような感じだけどもう少し簡易的に扱える。
今回は画像ならGUI.Boxで画像を表示し、音ならAudioSourceで音を鳴らし、それ以外であればGUI.TextFieldにてテキストを表示させるようにしてみた。
音についてはUnityはmp3を外から取ってきて鳴らすというのはサポートされていないそうで非圧縮音源かoggフォーマットのみ。

基本的な部分はすごく簡単で

/**
 * データのロード。
 */
private IEnumerator LoadData(string url) {
	this.www = new WWW(url);

	yield return this.www;

	// ダウンロード後の処理
}

こんなメソッドを用意してあげて、あとは呼び出すだけ。
ローディング状況はWWW.progressで取れる。
エラーについてはWWW.errorがnullでなければエラーが発生している。
Flashと同様に別のドメインのファイルを見にいくときにはcrossdomain.xmlの設置が必要になってくる。
Continue…

UnityでXMLを扱う

前回のjsonに引き続きXMLの読み込みのテスト。
この辺はFlashと同じような扱いでできた。
XMLをDOMとして扱うのであればこれでいいんだけど、SAXとして扱う場合はXmlReader.Create()を使うと思う…けどよく分からなかったけどこの辺が参考になるのかしら。
Continue…

UnityでJsonを扱う

UnityでJsonを扱うにはいくつかライブラリがあるようです。
生存日記 | UnityのJSONパーサ
この中でJSON ObjectLitJSONを扱ってみました。

(2014.06.28 追記 : NGUIにもJsonを扱うNGUIJsonがあった

JSONObjectのライセンスはLGPL2.1と書いてあるんですが、DLしたものには特に明記はなく、Asset Storeに並んでいるものも特に明記はしていないのでこちらが適応されると思っていいんでしょうか…
LitJSONの方はパブリックドメインなので問題なく自由に使えるようです。
Continue…