2DでのLookAt

2Dでの制作の際にLookAt()を使ったらオブジェクトが見えなくなった。
よく考えたら3D空間でLookAt()されるので奥行きの方に倒れてしまって見えなくなっていたようだった。
LookAt()を使わずQuaternion.FromToRotation()を使ったら向くようになりました。

	public override void Update() {
		Vector3 diff = (this.targetGO.transform.position - this.transform.position).normalized;
		this.transform.rotation = Quaternion.FromToRotation(Vector3.up, diff);
	}

参考)
テラシュールブログ | UnityのベクトルとQuaternionによる回転について

Instantiate()時のiTweenのエラー

プレハブをInstantiate()する際にTweenのエラーが出てしばらくはまってしまった。

NullReferenceException: Object reference not set to an instance of an object
iTween.RetrieveArgs () (at Assets/iTween/Plugins/iTween.cs:6811)
iTween.Awake () (at Assets/iTween/Plugins/iTween.cs:6559)
UnityEngine.Object:Instantiate(Object)

インスペクタ上で生成したいプレハブを設定する際に、自身のプレハブと同じものを設定しました。
期待としては自身のプレハブが増殖することを期待していたんだけど、プレハブの状態ではなく自分のGameObjectの状態で複製された。
自身のGameObjectにはiTweenコンポーネントが追加されていたので、新たなGameObjectをInstantiate()する際にもiTweenコポーネントが追加された状態で生成されてしまっていたため上記のエラーがでていたようです。
そこで、今回は自身のGameObjectをDestroy()するものだったので、その前にiTweenもDestroyしてから複製してみました。
ただ、Destroyして即座にInstantiate(thisPrefab)してもダメだったので1フレーム待ってやってみたところエラーを回避できました。
なんとなくこんな感じです。

	public override void OnCollisionEnter2D(Collision2D collision) {
		base.OnCollisionEnter2D(collision);

		foreach (iTween tween in this.dividePrefab.GetComponents<iTween>()) {
			Destroy(tween);
			tween.enabled = false;
		}
		StartCoroutine(this.CreateDivide());
	}

	IEnumerator CreateDivide() {
		yield return new WaitForEndOfFrame();

		for (int i = 0; i < 4; ++i) {
			GameObject divideGO = (GameObject)Instantiate(this.dividePrefab);
		}

		Destroy(this.gameObject);
	}

Destroyしない場合はもう少し工夫が必要か、自身のプレハブとは別のプレハブを用意するなどが必要そうです。
自身のGameObjectのプレハブを取得する方法ってのはないんですかね??

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

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

`****’ 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…

Some objects were not cleaned up when closing the scene.

「Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)」
というエラーが出て、再生を止めたのにインスタンスがシーンに残ってしまった。
どうやら再生を停止する際にもOnDestroy()が呼ばれそこでエラーが出てしまいDestroyされず残っているようでした。
今回の原因はシングルトンで扱っていたクラスにOnDestroy()でアクセスしていたため、先にシングルトンとして生成されていたオブジェクトが削除されたためにエラーが出ていたようでした。

テクスチャのOffsetの設定

背景を表現する場合テクスチャをずらして表現する事がある。その際にSpriteを使ってしまうとテクスチャがいくつかまとまったシートになっているためOffsetなどは使えない。なのでQuadを使ってマテリアルを割り当てる。使うテクスチャは
[ Texture Type ] => Texture
[ Wrap Mode ] => Repeat
にしておき、その上でスクリプトの方で renderer.material.mainTextureOffsetを操作するとテクスチャをずらす事ができる。

void Update () {
	this.renderer.material.mainTextureOffset = new Vector2(Time.time, Time.time);
}

こちらでも詳しい説明が載ってます。

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]

UIButtonやUITweenerでのイベントの発行元

UIButtonのonClickやUITweenerのonFinishedのイベントの発行元の取得は

public UIButton button;
public UITweener tween;

void Start() {
	EventDelegate.Add(this.button.onClick, this.OnClick);
	EventDelegate.Add(this.tween.onFinished, this.OnTweenFinished);
}

void OnClick() {
	print(UIButton.current);
}

void OnTweenFinished() {
	print(UITween.current);
}

にて取得できる。