[UNITY] World Space Canvas에 Ray 이용 충돌 감지 및 링크 연결 이벤트 발생

Doorbals·2022년 9월 9일
0

UNITY

목록 보기
3/4

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; // UI에 Raycast를 이용해 충돌 감지하게 해줌
    private List<RaycastResult> raycastResults; // Raycast의 충돌 결과들을 담는 리스트
    private PointerEventData ped; // Canvas 상의 포인터 정보를 담음
    public Camera cam;

    protected override void Start()
    {
        cam = Camera.main;
        ped = new PointerEventData(null);
        raycastResults = new List<RaycastResult>();
    }

    void Update()
    {
        ped.position = input.mousePosition; // Cursor 고정되어 있으므로 스크린 중앙에 ped의 position 고정됨.
        gr.Raycast(ped, raycastResults);  // ped 위치에 Raycast하여 결과 값 저장

        if(raycastResults.Count > 0) //  Canvas 내에서 충돌한 UI가 있으면
        {
        	// 충돌한 각 UI들에 대해 for문 안의 내용 실행
            foreach(RaycastResult raycastResult in raycastResults)
            {
            	// ped 위치의 gameObject에 대해 입력 및 종료 이벤트 처리
                HandlePointerExitAndEnter(ped, raycastResult.gameObject);
                if(Input.GetKeyDown(KeyCode.Mouse0))
                   Application.OpenURL("http://unity.com"); // 이미지 클릭 시 URL 연결
            }
        }
        else // 충돌한 UI가 없으면 
        {
        	// ped 위치에 감지되는 UI 없으면 이벤트 처리 종료
            HandlePointerExitAndEnter(ped, null);
        }
        raycastResults.Clear();
    }

    // 상속 받아야 에러 발생 X
    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() {}
}
profile
게임 클라이언트 개발자 지망생의 TIL

0개의 댓글