[원하는 기능]
- 버튼을 눌렀을때 뒤에 있는 타일 안 눌리도록 하는 기능
[공부한 내용]
유니티에서 UI 요소가 클릭되었을 때, 뒤에 있는 타일이 클릭되지 않도록 하려면 GraphicRaycaster와 EventSystem이 올바르게 설정되어 있는지 확인해야 한다.
- Canvas 설정 확인
- Canvas 오브젝트가 있는지 확인한다. Canvas 오브젝트는 UI 요소들이 포함되어야 한다.
- Canvas 오브젝트에 GraphicRaycaster 컴포넌트가 추가되어 있는지 확인한다(기본적으로 포함되어 있다).
- Canvas 의 Render Mode 가 Screen Space - Overlay 또는 Screen Space - Camera 로 설정되어 있는지 확인한다.
- EventSystem 설정확인
- EventSystem 오브젝트가 있는지 확인한다(EventSystem은 UI 이벤트를 처리하는 데 필요함).
- 만약 EventSystem 오브젝트가 없다면, Hierarchy 창에서 우클릭하여 UI > Event System을 선택하여 추가한다.
- UI 요소의 Raycast Target 설정 확인
- UI 요소(버튼, 이미지 등)의 Raycast Target 속성이 활성화되어 있는지 확인한다.
- 버튼의 경우, Button 컴포넌트는 기본적으로 Image 컴포넌트를 포함하고 있으며, Image 컴포넌트의 Raycast Target 속성이 활성화되어 있어야 한다.
[코드]
private bool IsPointerOverUIObject()
{
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current)
{
position = new Vector2(Input.mousePosition.x, Input.mousePosition.y)
};
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;
}
void Update()
{
// 버튼 눌렀을 때 뒤에 있는 타일 못 누르도록 하기 위한 구문..
if (IsPointerOverUIObject()) return;
// 땅을 왼쪽 마우스키로 누르면..
if (Input.GetMouseButtonUp(0))
{
// 땅에 아무것도 안 한 상태는 plow 버튼을 갖고, 갈린 상태는 버튼으로 plant 버튼을 갖는다.
// 다른 땅을 클릭하면 전에 클릭한 땅의 버튼은 안 보여야 하므로 SetActive 로 안보이게 조정한다..
// 수확하기 버튼은 과일이 다 자라면 계속 보여야함..
if (farmEnableZoneTilemap.HasTile(prevSelectTile))
{
if (farmingData[prevSelectTile].currentState == "None" || farmingData[prevSelectTile].currentState == "plow")
{
farmingData[prevSelectTile].stateButton.gameObject.SetActive(false);
}
}
// 현재 마우스 위치를 게임 월드 위치로 바꿔서 저장
clickPosition = mainCamera.ScreenToWorldPoint(Input.mousePosition);
// 게임 월드 위치를 타일 맵의 타일 셀 위치로 변환
cellPosition = farmTilemap.WorldToCell(clickPosition);
foreach (Vector3Int pos in farmingData.Keys)
{
// 저장해놓은 타일 중에 현재 마우스로 클릭한 위치랑 같은 타일이 있으면
if (pos == cellPosition)
{
// 현재 선택한 타일의 버튼은 활성화 되도록..
farmingData[cellPosition].stateButton.gameObject.SetActive(true);
// 아래 방법처럼 하면 오류남. 이유는 뭐지??
// --> GameObject 는 컴포넌트가 아니라서 오류가 나는 것이었다... 이번 기회에 알게 됐다.
// --> 그냥 gameObject 로 바로 게임 오브젝트에 접근할 수 있었다.
// --> 기본적인걸 까먹고 있었다.. 이번엔 잘 기억하자..
//farmingData[cellPosition].stateButton.GetComponent<GameObject>().SetActive(true);
}
}
prevSelectTile = cellPosition; // 지금 누른 타일을 이전에 누른 타일 위치를 저장하는 변수에 저장..
}
foreach (Vector3Int pos in farmingData.Keys)
{
if (farmingData[pos].seed != null)
{
if (farmingData[pos].seed.isGrown)
{
farmingData[pos].harvestEnableState = true; // 작물 수확할 수 있는 상태
farmingData[pos].stateButton.gameObject.SetActive(true); // 수확하기 버튼은 항상 떠있어야 함
farmingData[pos].currentState = "harvest";
}
}
}
}
- PointerEventData: 마우스의 현재 위치를 기준으로 PointerEventData 객체를 생성한다.
- PointerEventData 는 이벤트 시스템의 입력 데이터를 나타내는 클래스
- RaycastAll 호출: 현재 이벤트 시스템에서 모든 UI 요소에대해 레이캐스트를 실행하여 해당 위치에 있는 모든 UI 요소를 감지한다.
- EventSystem.current.RaycastAll 메서드를 사용해서 현재 이벤트 시스템에서 모든 UI 요소에 대해 레이캐스트를 실행한다.
- 레이캐스트 결과는 results 리스트에 저장된다.
- 레이캐스트 결과를 확인하여 하나 이상의 UI 요소가 감지되었는지 확인하다. 감지된 경우 마우스 포인터가 UI 요소 위에 있다고 판단한다.
- if (IsPointerOverUIObject()) return; 이 구문은, 조건문이 true 일 때 해당 프레임에서는 이후 코드가 실행되지 않고, 다음 프레임에서 다시 Update 메서드가 호출되면서 처음부터 코드를 실행하게 된다(Update 메서드는 매 프레임마다 다시 호출된다).
- IsPointerOverUIobject() 함수는 마우스 포인터가 UI 요소 위에 있는 동안 계속해서 true 를 반환한다. EventSystem 을 통해 마우스 위치에서 모든 UI 요소에대해 레이캐스트를 수행하고, 하나 이상의 UI 요소가 감지되면 true 를 반환하는 방식이다.
[참고자료]
https://docs.unity3d.com/kr/530/ScriptReference/EventSystems.PointerEventData.html
EventSystems.PointerEventData - Unity 스크립팅 API
Event payload associated with pointer (mouse / touch) events.
docs.unity3d.com
https://code-piggy.tistory.com/entry/Unity-PointerEventData
Unity - PointerEventData class
PointerEventData class Unity 엔진에서 사용되는 UnityEngine.EventSystems 클래스 중 하나이다. UI 이벤트 시스템과 함께 사용되며, UI 요소에 대한 포인터(mouse/touch) 입력 관련 정보를 처리하기 위해 사용된다.
code-piggy.tistory.com
https://godnr149.tistory.com/73
PointerEventData
PointerEventData Event payload associated with pointer (mouse / touch) events. 터치하고 있는 상태나 마우스를 클릭하고 있는 상황 (연속적으로 Input.GetKey() 상태를 유지하고 있을 때) 에서 특정 액션을 취할 수 있
godnr149.tistory.com
[Unity] Raycast 터치 구현 시 UI 아래 GameObject 터치 방지하기
GameObject를 Raycast로 터치 처리 시 UI가 GameObject위에 있는 경우에도 GameObject가 터치되는 경우가 발생합니다.
gameneo.medium.com