EventSystemを使った、タッチされたオブジェクトの取得方法を以前紹介しましたが、この方法では1度に1つのオブジェクトしか取得できません。
そのためオブジェクト同士が重なっていると、最初にEventを取得した1つのオブジェクトしか取得することができません。また厄介なことに、取得できるオブジェクトは一番手前のオブジェクトであるとは限らないです。
なので違うアプローチで複数同時タッチに対応します。
実装方法
Raycastを飛ばして複数オブジェクトを取得します。
EventSysytemでタッチを取得する方法では古い方法と紹介しましたが、複数のオブジェクトを取得するにはこの方法しかないっぽいので前言撤回です。
大まかな手順
大まかな実装手順の流れは以下となります。
- タッチしたときの動作が書かれたスクリプトの作成
- タッチさせたいオブジェクトに上記のスクリプトをアタッチ
- タッチさせたいオブジェクトにコライダー追加
- タッチ動作を管理するスクリプトを作成
- 管理用にオブジェクトを作成し、上記のスクリプトをアタッチ
- メインカメラにRaycasterコンポーネントを追加
スポンサードサーチ
詳細な実装手順
今回の例では、画面上に配置したアイテムをタッチするスクリプトを実装します。
タッチさせたいオブジェクトの準備
スクリプトの作成
まず、タッチさせたいオブジェクト用のスクリプトを作成します。「ItemTest.cs」という名前で作成しました。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ItemTest : MonoBehaviour { public void onClickAct() { Debug.Log("たっぷされたアイテム"); } }
タッチされたときに動作する関数をPublicで用意しているだけのシンプルなスクリプトです。
オブジェクトの準備
タッチさせたいオブジェクトに上記で作ったスクリプトをアタッチします。
続けて、同じくタッチさせたいオブジェクトにコライダーを追加します。コライダーを付けることでRaycastに対する当たり判定が生まれます。
今回はシンプルに2Dサークルコライダーにしました。
さらに、タッチ操作の判別用にオブジェクトのタグを変更しています。今回は「Item」というタグを作成しオブジェクトに割り当てています。
タッチ動作を管理するオブジェクトの作成
タッチさせたいオブジェクトの準備はできました。次はタッチ動作そのものを管理するオブジェクト、スクリプトを作成します。
タッチ動作を管理するスクリプトの作成
まず、タッチ動作そのものを管理するスクリプトを作成します。「TouchTest.cs」という名前で作成しました。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TouchTest : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { bool onTouch = false; Vector2 touchPosition = new Vector2(0, 0); if (Application.isEditor) { //エディターでのクリック if (Input.GetMouseButtonDown(0)) { onTouch = true; touchPosition = Input.mousePosition; } } else { //端末でのタップ if (Input.touchCount > 0) { Touch touch = Input.GetTouch(0); onTouch = true; touchPosition = touch.position; } } if (onTouch) { TouchAct(touchPosition); } } /// /// タッチされていたときの処理 /// /// private void TouchAct(Vector2 pos) { Vector2 worldPoint = Camera.main.ScreenToWorldPoint(pos); foreach (RaycastHit2D hit in Physics2D.RaycastAll(worldPoint, Vector2.zero)) { //オブジェクトが見つかったときの処理 if (hit) { //タグがアイテムなら if (hit.collider.gameObject.CompareTag("Item")) { hit.collider.GetComponent<ItemTest>().onClickAct(); } } } } }
動作確認用にUnityエディター上でも動作するように「Application.isEditor」でアプリが動作しているのがエディターかどうかを判定しています。
「TouchAct」関数が今回のキモで、タッチされた場所にRayというビームのようなものを飛ばし、当たったオブジェクトがあった場合にオブジェクトにアタッチされているオブジェクト内のスクリプトを実行するようにしています。
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(pos);
タッチされた座標をワールド座標に変換しています。
foreach (RaycastHit2D hit in Physics2D.RaycastAll(worldPoint, Vector2.zero)) {
「Physics2D.RaycastAll」で指定したワールド座標にあるオブジェクトをすべて取得しています。
その取得したオブジェクトたちを「foreach」で1つずつ取り出して処理しています。
if (hit.collider.gameObject.CompareTag(“Item”)) {
hit.collider.GetComponent<ItemTest>().onClickAct();
}
“Item”というタグなら「ItemTest」がアタッチされているので、GetCompnentしてタッチされたときの関数を呼び出しています。
タッチ動作を管理するオブジェクトの作成
ヒエラルキーウィンドウで空のオブジェクトを作成し、上記で作成したスクリプトをアタッチします。(空のオブジェクトを作らなくても、どのオブジェクトにアタッチしても問題ありません)
メインカメラ設定
最後に、メインカメラに「Physics 2D Raycaster」を追加すればすべて完了です。3Dの場合は「Physics Raycaster」です。
メインカメラのインスペクターから「コンポーネントの追加 → イベント → Physics 2D Raycaster」で追加できます。
追加するのみで特に設定は不要です。
スポンサードサーチ
動作確認
実行して重なったオブジェクトをタッチしてみましょう。同時に重なった数だけログが出力されれば成功です。
EventSystemに比べるとほんのひと手間だけかかってしまいますが、同時に複数のオブジェクトをタッチできるようにするのは地味に重要です。
頑張って実装しましょう!