World Space Canvas에 Ray 이용 충돌 감지
1. Graphic Raycaster
- Canvas에 Raycast를 하는 데에 사용. Canvas의 모든 그래픽스를 감지하여 그 중 하나에 충돌하였는지 여부를 결정.
- Ignore Reversed Graphics : Raycast가 후면 그래픽스(그래픽 뒷면)를 무시할지 여부
- Blocked Objects : 어떤 오브젝트의 Collider가 Raycast를 막을지 설정
- Blocking Mask : 어떤 Layer를 가진 오브젝트가 Raycast를 막을지 설정
- 해당 Canvas에 Raycast를 가능하게 할 Camera를 설정해주어야 한다.
2. RaycastResult
- UnityEngine.EventSystems의 class. Raycaster의 Hit 결과를 담고 있다.
3. PointerEventData
- 마우스 클릭 또는 터치하고 있는 상태에서의 Pointer에 대한 정보를 담고 있다.
- 일종의 Ray를 쏜다고 생각하면 될 듯.
- 이를 사용하기 위해서는 현재 class에 BaseInputModule을 상속 받아야 한다.
- BaseInputModule을 상속 받을 때 오류 발생하지 않도록 Process(), OnEnable(), OnDisable() 메서드를 override 해야 한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class DetectObject : BaseInputModule
{
public GraphicRaycaster gr;
private List<RaycastResult> raycastResults;
private PointerEventData ped;
public Camera cam;
protected override void Start()
{
cam = Camera.main;
ped = new PointerEventData(null);
raycastResults = new List<RaycastResult>();
}
void Update()
{
ped.position = input.mousePosition;
gr.Raycast(ped, raycastResults);
if(raycastResults.Count > 0)
{
foreach(RaycastResult raycastResult in raycastResults)
{
HandlePointerExitAndEnter(ped, raycastResult.gameObject);
if(Input.GetKeyDown(KeyCode.Mouse0))
Application.OpenURL("http://unity.com");
}
}
else
{
HandlePointerExitAndEnter(ped, null);
}
raycastResults.Clear();
}
public override void Process() {}
protected override void OnEnable() {}
protected override void OnDisable() {}
}
4. 여러 UI에 대한 링크 연결 처리
public class DetectUI : BaseInputModule
{
public GraphicRaycaster[] graphicRaycasters; // 각 UI Canvas를 배열에 추가해줘야 함.
private List<RaycastResult>[] raycastResults; // 하나의 리스트에 하나의 UI 결과 저장. { UI1[], UI2[], UI3[], ...}
private PointerEventData ped; // Canvas 상의 포인터 정보를 담음
public Camera cam;
protected override void Start()
{
cam = Camera.main;
ped = new PointerEventData(null);
raycastResults = new List<RaycastResult>[graphicRaycasters.Length]; // graphicRaycasters 개수(== UI 개수)만큼 배열에 리스트 추가
}
void Update()
{
ped.position = Input.mousePosition; // Cursor 고정되어 있으므로 스크린 중앙에 ped의 position 고정됨.
for (int i = 0; i < graphicRaycasters.Length; i++)
{
if (raycastResults[i] == null)
raycastResults[i] = new List<RaycastResult>();
graphicRaycasters[i].Raycast(ped, raycastResults[i]); // ped 위치에 Raycast하여 결과 값 저장. graphicRaycasters[i]에 저장된 UI의 Raycast 결과는 raycastResults[i]에 저장됨.
if (raycastResults[i].Count > 0) // Canvas 내에서 충돌한 UI가 있으면
{
// 충돌한 각 UI들에 대해 for문 안의 내용 실행
foreach (RaycastResult raycastResult in raycastResults[i])
{
// ped 위치의 gameObject에 대해 이벤트 처리 지속(호버링)
HandlePointerExitAndEnter(ped, raycastResult.gameObject);
if (Input.GetKeyDown(KeyCode.Mouse0))
{
// 각 UI에 연결할 링크 추가하는 부분
switch (raycastResult.gameObject.name)
{
case "Image":
Application.OpenURL("http://unity.com");
break;
case "Image2":
Application.OpenURL("http://naver.com");
break;
}
}
}
}
else // 충돌한 UI가 없으면
{
// ped 위치에 감지되는 UI 없으면 이벤트 처리 종료(호버링 종료)
HandlePointerExitAndEnter(ped, null);
}
raycastResults[i].Clear(); // RaycastResult 초기화 필수
}
}
// 상속 받아야 에러 발생 X
public override void Process() {}
protected override void OnEnable() {}
protected override void OnDisable() {}
}