Unityちゃんをはしごとバーに対して正しく干渉するようにする


[前回](http://qiita.com/mokemokechicken/items/fde9b7889f5971209c61)に続きまして、
ロードランナー風に下記のようなフィールドを作ってその中を動き回れるようにしてみます。

![demo1_unity_-_RoadRunner_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/6c3b99c5-406f-884a-ec5b-9e407aea0695.png "demo1_unity_-_RoadRunner_-_Web_Player.png")

Unityちゃんの制御コードやアニメーションなどは美しくないんですが、その辺は今後の課題にしようと思います。

ブロックの座標を調整する
===========

現時点で、ブロックやUnityちゃんが見た目的に調度良いようにするには微妙に座標を調整しないといけません。
例えば、ブロックが(x,y)=(0,0)で、Unityちゃんが(x,y)=(0,1)にいる状態だと下図のように間が開いてしまいます。

![demo1_unity_-_RoadRunner_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/7347feef-b373-aae3-a8a2-678f2c34da62.png "demo1_unity_-_RoadRunner_-_Web_Player.png")

ブロックを(0,0.5)に配置すればちょうどよいのですが、今後ステージ配置するときにいちいちそういう微調整をしたくありません。
一工夫してみることにします。

空Objectにぶら下げて相対座標をずらす
--------------------

[GameObject] -> [CreateEmpty] で空のObjectを作ります。名前を`BlockPrefab`とします（後でPrefab化するので)。
そのBlockPrefabに対して、作っていた Cube をドラッグアンドドロップして子どもとしてぶら下げます。
こんな感じになります。
![demo1_unity_-_RoadRunner_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/edd9a401-1310-cbb6-16ef-58ba3dc02dab.png "demo1_unity_-_RoadRunner_-_Web_Player.png")

そして、その子供のCubeの属性をInspectorでPositionを(0, 0.5, 0)と設定します。これは親の`BlockPrefab`に対する相対座標になります。
＃ そしてPrefab化しておきましょう。

![demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png](https://qiita-image-store.s3.amazonaws.com/0/11124/360b15b4-d71b-617b-8435-727c08fe0b2c.png "demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png")

こうしておくことで、このBlockを(0,0)に配置したときにUnityちゃんとぴったりくっついて見えるようになります。

んー他に良い方法あるのかなぁ。


はしごを作る
==========

同様に空Objectを一つ作り、そこにいくつかCylinderオブジェクトを並べます。

![demo1_unity_-_RoadRunner_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/f37626e4-3939-cd3a-7d3e-20b07a6195b5.png "demo1_unity_-_RoadRunner_-_Web_Player.png")

んーこういうのはAssetStoreとかにあるのかな。

Tagを付ける
----------

はしごは今後の当たり判定のときに識別したいので、Tagを付けておきます。`Ladder`としておきましょう。
下記の部分から [Add Tag]から付け加えたあと、再度選択すればOKです。

![demo1_unity_-_RoadRunner_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/ebb4934e-01dc-f24c-f673-2d7d5569cd52.png "demo1_unity_-_RoadRunner_-_Web_Player.png")

当たり判定をTriggerに切り替える
-------------

親の子供として、ぶら下がっているObjectは当たり判定を持っています。しかし、力学的な相互作用をさせたくありません（はしごに衝突して押し戻されるというのはおかしい)。そういう場合は、下記のように`isTrigger`をチェックしておきます。またここのTagも`Ladder`にしておきます（不要かな・・？）。

![demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png](https://qiita-image-store.s3.amazonaws.com/0/11124/a898a39b-b258-86d7-321a-d6fd202e2106.png "demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png")


バーを作る
==========

![demo1_unity_-_RoadRunner_-_Web_Player.png](https://qiita-image-store.s3.amazonaws.com/0/11124/982224a5-505a-5636-751c-0082a31804af.png "demo1_unity_-_RoadRunner_-_Web_Player.png")

同様にBarを作ります。

* Tagを`Bar`として付加します。
* isTrigger を Trueにします
* Barにはぶら下がっているような位置関係にしたいので、このColliderの座標をずらしておきます。
	* 下記の図ではXのScaleが0.05なので 14というのは 0.7 を表しています（たぶん）

![demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png](https://qiita-image-store.s3.amazonaws.com/0/11124/db44b2aa-75c5-4cea-c1e7-f4e76381d365.png "demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png")

位置関係などの微調整は実際に動かしながら確認するのが良いと思います。


フィールドを配置する
===============

適当にフィールドに配置します。冒頭の画像のようにしてみました。

Unityちゃんを小さくする
================


![demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png](https://qiita-image-store.s3.amazonaws.com/0/11124/b0407a87-c33a-5b59-e884-0119544442c7.png "demo1_unity_-_RoadRunner_-_Web_Player_と_Unityちゃんをはしごとバーに対して正しく干渉するようにする.png")

Unityちゃんの大きさが少し大きいので小さくします。 Scaleを全て0.6にするくらいでちょうど良いでしょうか。


スクリプトを更新する
==========

UnityChanDemo1スクリプトを以下のように更新します。
「落下」「はしご」「バー」「地面」という状態によっていろいろ振る舞いを変えないといけません。
なんかフラグがいっぱいになっていて美しくないですね。
Animator側の使い方も併せて今後の課題です。

```cs:UnityChanDemo1.cs
using UnityEngine;
using System.Collections;

public class UnityChanDemo1 : MonoBehaviour {
	private const string LADDER = "Ladder";
	private const string BAR = "Bar";
	private const string BLOCK = "Block";

	private Animator animator;

	public int ladderEnter = 0;
	public int barEnter = 0;
	public bool isFalling = false;

	// Use this for initialization
	void Start () {
		animator = GetComponent<Animator>();
	}
	
	// Update is called once per frame
	void Update () {
		bool is_running = false;
		if (!isFalling) { // If Not Falling, can move to Left/Right
			if (Input.GetKey("right")) {
				transform.position += new Vector3(0.05f, 0, 0);
				transform.rotation = Quaternion.Euler(new Vector3(0, 90, 0));
				is_running = true;
			} else if (Input.GetKey ("left")) {
				transform.position += new Vector3(-0.05f, 0, 0);
				transform.rotation = Quaternion.Euler(new Vector3(0, -90, 0));
				is_running = true;
			}
		}
		animator.SetBool("is_running", is_running);

		// if entering in any ladder collision, can move Up/Down
		if (Input.GetKey("up") && ladderEnter > 0) {
				transform.position += new Vector3(0, 0.05f, 0);
		} else if (Input.GetKey("down") && ladderEnter > 0) {
			transform.position += new Vector3(0, -0.05f, 0);
		} else if (Input.GetKey("down") && barEnter > 0) { // if entering in bar and KeyDown, bar are released.
			barEnter = 0;
		}

		// if entering in any ladder or bar, gravity is off
		if (ladderEnter > 0 || barEnter > 0) {
			rigidbody.useGravity = false;
			rigidbody.velocity = Vector3.zero;
		} else {
			rigidbody.useGravity = true;
		}

		// if Velocity.y reach some degree, Falling is True
		if (rigidbody.velocity.y <  -0.05f) {
			isFalling = true;
		} else {
			isFalling = false;
		}
	}

	void OnTriggerEnter(Collider other) {
		switch(other.gameObject.tag) {
		case LADDER:
			ladderEnter += 1;
			break;
		case BAR:
			barEnter += 1;
			break;
		}
	}

	void OnTriggerExit(Collider other) {
		switch(other.gameObject.tag) {
		case LADDER:
			ladderEnter -= 1;
			break;
		case BAR:
			if (barEnter > 0) {
				barEnter -= 1;
			}
			break;
		}
	}
}
```

今回作ったもの
========

[ここにWebPlayerでPublishしてみました](https://dl.dropboxusercontent.com/u/21300511/UnityRoadRunner/demo1c/demo1c.html)。

見ての通り、動くには動きますが、キャラクターのアニメーションなどはかなりおかしいです。
いろいろいじっているんですが、なかなか思い通りにならなくて、元に戻したんですよね。。。
んー、精進せねば。。。