UnityでButton的な何かを作る


# はじめに

Unityでボタンを使う場合、OnGUI()関数を使うやり方があるが、そうではなくGameObjectをタッチしたときになんらかのアクションを起こすようにしたい。
そのためのスクリプトを書いてみた。

# 基本方針

画面をタップするのは指１本（複数の場合もあるがここでは考えない）なので、Rayを撃つのは１回のみにとどめたい。
具体的には、前に書いた記事：[Unityで画面をタップした時のRayの撃ち方を考えてみた](http://qiita.com/JunSuzukiJapan@github/items/1698a21323558e246c4f)の仕組みをそのまま使って、ボタン以外のものをタッチしたときと同じ仕組みで動作するようにする。

# 実装

実際に書いたスクリプトが以下。

## 必要なスクリプトをプロジェクトに準備しておく

あらかじめプロジェクトに、以下の２つのスクリプトを含めておく。

TapBehaviourは前の記事で書いたものとほぼ同じ。ButtonBehaviourが新たに書いたもの。

```csharp:TapBehaviour.cs
using UnityEngine;

public interface TapBehaviour {
	// タッチしたときに呼ばれる。
	void TapDown(ref RaycastHit hit);
	// タッチを離したときに呼ばれる。
	void TapUp(ref RaycastHit hit);
}
```

```csharp:ButtonBehaviour.cs
public interface ButtonBehaviour {
	void TouchDown();
	void TouchUp();
}
```

## MainCameraにスクリプトを貼り付ける

MainCameraからRayを撃って、タップされた場所にTapBehaviourインターフェースを持つオブジェクトがあれば、イベントハンドラを呼び出すようにするために、MainCameraに次のスクリプトを貼り付けておく。

TouchHandlerも前の記事とほぼ同じもの。

```csharp:TouchHandler.cs
using UnityEngine;
using System.Collections;

public class TouchHandler : MonoBehaviour {
	public float distance = 100; // Rayの届く距離
	
	void Update () {
		// タッチされたとき
		if(Input.GetMouseButtonDown(0)){
			// メインカメラからクリックしたポジションに向かってRayを撃つ。
			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hit = new RaycastHit();
			
			if (Physics.Raycast(ray, out hit, distance)) {
				GameObject selectedGameObject = hit.collider.gameObject;
				TapBehaviour target = selectedGameObject.GetComponent(typeof(TapBehaviour)) as TapBehaviour;
				if(target != null){
					target.TapDown(ref hit);
				}
			}
			
			// 指を離したとき
		}else if(Input.GetMouseButtonUp(0)){
			// メインカメラからクリックしたポジションに向かってRayを撃つ。
			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			RaycastHit hit = new RaycastHit();
			
			if (Physics.Raycast(ray, out hit, distance)) {
				GameObject selectedGameObject = hit.collider.gameObject;
				TapBehaviour target = selectedGameObject.GetComponent(typeof(TapBehaviour)) as TapBehaviour;
				if(target != null){
					target.TapUp(ref hit);
				}
			}
			
		}
	}
}
```

## ButtonにしたいGameObjectにスクリプトを貼り付ける

次に、実際にボタンにしたいGameObjectに、以下の２つのスクリプトを貼り付ける。
GameObjectはタッチに反応する前提なので、なんらかのColliderを持っている必要がある。

```csharp:Button.cs
using UnityEngine;

public class Button : MonoBehaviour, TapBehaviour {

	private ButtonBehaviour handler = null;

	// タッチしたときに呼ばれる。
	public void TapDown(ref RaycastHit hit) {
		if(handler != null){
			handler.TouchDown();
		}
	}

	// タッチを離したときに呼ばれる。
	public void TapUp(ref RaycastHit hit) {
		if(handler != null){
			handler.TouchUp();
		}
	}

	void Start(){
		handler = gameObject.GetComponent(typeof(ButtonBehaviour)) as ButtonBehaviour;
	}
}
```

Button.csは常に同じもので良いので、変更の必要はない。

```csharp:SomeButtonBehaviour.cs
using UnityEngine;
using System.Collections;

public class SomeButtonBehaviour : MonoBehaviour, ButtonBehaviour {
	public void TouchDown(){
        // ここにボタンが押されたときの処理を書く。
	}

	public void TouchUp(){
        // ここにボタンが離されたときの処理を書く。
	}
}
```

こちらのSomeButtonBehaviour（名前は変えてかまわない）が、実際の処理を担当する部分。
各ボタンごとにスクリプトを用意してやって、やりたい処理を書いていく。

# 補足

このままだと、TapBehaviourを使うのと大差ないが、
・テキストを表示して、押されたら背景色が変わるボタン
や
・テクスチャを表示して、押されたらテクスチャを変化させるボタン
など、一度作れば再利用可能なボタンを作るのが目的。