こんばんは、ちきなるです。
マウスをクリックした場所に、imageがあるかチェックしたい!!
(imageは、UIから追加できるやつです)
imageが有ったら、情報を取得して、
imageが無かったら、何もしない。
と、言うわけで、
Raycastで、imageを取得しようとしたら・・・。
(2Dゲームの話です)
補足。
Raycast(Physics2D.Raycast)とは、
指定のポイントから、指定の方向へRay(光線)を発射し、Rayが接触したColliderを返す(RaycastHit2D)関数です。
指定のポイント(マウスの位置など)にある、オブジェクトを取得するのに、使われます。
これを使って、image(GUI)を取得したい!!
と、言う話です。
Physics2D.RaycastAll
マウスがあるポイントに、Raycastだ!!
(Physics2D.RaycastAllで、全て取得)
//マウスのある位置を取得(スクリーン座標)
Vector3 MousePoint = Input.mousePosition;
//スクリーン座標をワールド座標に変換
MousePoint = Camera.main.ScreenToWorldPoit(MousePoint);
//マウスのある位置から、奥(0, 0, 1)に向かってRayを発射(ワールド座標)
RaycastHit2D[] hit2D = Physics2D.RaycastAll(MousePoint , Vector3.forward);
//Rayがhitしたオブジェクトに目的のオブジェクトがあるかチェック
foreach(RaycastHit2D hit in hit2D)
{
//中身の確認処理 hit.transform.gameObject.tagとかが便利
}
と、やったのですが・・・。
imageは、取得できませんでした。
ちなみに、
カメラの設定を透視投影(ProjectionをPerspective)に、している場合、z座標にカメラからの距離を入れてあげないと、上手くオブジェクトを取得できません。
画面の視覚情報と一致させたい場合は、対象のオブジェクトのz座標とカメラのz座標の距離を入力する必要があります。ScreenToWorldPoit前に。
対象オブジェクトのz座標が0の時
//マウスのある位置を取得(スクリーン座標)
Vector3 MousePoint = Input.mousePosition;
//対象オブジェクトとカメラの距離を入れる
MousePoint.z = 0 - Camera.main.transform.position.z;
//スクリーン座標をワールド座標に変換
MousePoint = Camera.main.ScreenToWorldPoit(MousePoint);
この後、Raycastをすると、オブジェクトが取れる。はず。
Physics2DのRaycastの対象は、Colliderです。
Rayが通過したポイントにあるColliderを取得する関数です。
つまり。
Colliderを持たないimageは、取得することが出来ません。
(imageに、無理やりColliderを付けて取得することも出来ますが、
それなら、imageではなく、Spriteを使った方が良いです)
EventSystem.current.RaycastAll
どうすれば、imageが、取得できるのか・・・。
と、調べたところ、
EventSystem.current.RaycastAll
と言うのが、ありました。
これを使うと、
ポイントに存在する、全てのUI(GUI)を取得することが出来ます。
//RaycastAllの引数(PointerEventData)作成
PointerEventData pointData = new PointerEventData(EventSystem.current);
//RaycastAllの結果格納用List
List<RaycastResult> RayResult= new List<RaycastResult>();
//PointerEventDataにマウスの位置をセット
pointData.position = Input.mousePosition;
//RayCast(スクリーン座標)
EventSystem.current.RaycastAll(pointData , RayResult);
foreach (RaycastResult result in RayResult)
{
//中身の確認処理
}
これで、
マウスがあるポイントのUIを全て取得できます。
ただし!!
Raycast Targetにチェックが付いているUIだけです。
ちょっとだけ、余談。
ワールド座標とスクリーン座標
Physics2D.RaycastAllは、ワールド座標が使われていましたが、
EventSystem.current.RaycastAllは、スクリーン座標が使われています。
要注意。
覚え方としては、
ゲーム内に存在するオブジェクトは、ワールド座標。
ユーザーに向けて作られたもの(UI)は、スクリーン座標。
これが、基本です。
(ワールド座標は、オブジェクトが存在するゲーム空間の座標。
スクリーン座標は、画面の座標。(左下が(0, 0))
(スクリーン座標とワールド座標では、値の大きさが違います(1≠1))
Physics2Dは、ゲームオブジェクト(Collider)が対象なので、ワールド座標。
EventSystemは、UIが対象なので、スクリーン座標。
まとめ
Raycastで、image(UI)を取得したい時は、
EventSystem.current.RaycastAll
を使う。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class RaycastTest : MonoBehaviour
{
//RaycastAllの引数
private PointerEventData pointData;
private void Start()
{
//RaycastAllの引数PointerEvenDataを作成
pointData = new PointerEventData(EventSystem.current);
}
private void Update()
{
//RaycastAllの結果格納用のリスト作成
List<RaycastResult> RayResult= new List<RaycastResult>();
//PointerEvenDataに、マウスの位置をセット
pointData.position = Input.mousePosition;
//RayCast(スクリーン座標)
EventSystem.current.RaycastAll(pointData , RayResult);
foreach (RaycastResult result in RayResult)
{
//中身の確認処理
}
}
}
(Raycast Targetが付いている全てのUIを取得します。
TextやPanelなども取得できます)
余談2。
EventSystemsで送られてきたPointerEventDataの場合、
pointerPressRaycast
を参照するとUIが取得できます(クリックされた時のUI)。
(マウスイベントOnBeginDragなどの引数で渡されたPointerEventDataの話)
マウスがクリックされた時、最前面に有るUIが、セットされているもよう。
(ソートを見る感じ、最前面かな?)
なので、
OnBeginDragなどで、UIを取得したい時は、eventData.pointerPressRaycastを見るのが良い。
と、思います。
ただし、
最前面だけなので、後ろにあるUIを取りたい時は、
RaycastAllで取得する必要があります。
次回。
コメント
コピペしたらエラーになりました。
Camera.main.ScreenToWorldPoint
が
Camera.main.ScreenToWorldPoit(Pointのnがない)
になってました。