[Unity / C#] 보는 대상 감지, UI제어

주예성·2025년 6월 11일
post-thumbnail

📋 목차

  1. 오브젝트 생성 및 Material 적용
  2. 오브젝트 감지하기
  3. 임시 제작대 UI 제작 (Bench_Panel)
  4. 스크립트에 변수와 함수 추가
  5. 중간 확인
  6. 중간 문제점
  7. 최종 결과
  8. 오늘의 배운 점
  9. 다음 계획

❒ 오브젝트 생성 및 Material 적용

보는 대상이 될 Bench라는 Cube를 생성했습니다.
만들다보니 사물을 분간하기가 어려워져 오브젝트에Material을 적용시켰습니다.
구분하길 원하는 오브젝트에 원하는 색상으로 적용시키세요.

  1. Project 우클릭 -> Create -> Material
  2. 이름 변경: Mat_Object
  3. Albedo: 원하는 색상
  4. Object에 드래그 앤 드롭

⚡ 오브젝트 감지하기

1. InteractionDetector 스크립트 생성

오브젝트 감지용 스크립트, InteractionDetector을 생성합니다.
Player의 컴포넌트로 추가합시다.

2. RaycastHit 활용

Unity에서는 상대 감지를 위해 Ray, Raycast, RaycastHit 을 사용합니다.
아래 코드는 현재 바라보는 오브젝트의 태그가 Bench일 경우 로그를 띄우는 코드입니다.

using UnityEngine;
using UnityEngine.Experimental.GlobalIllumination;

public class InteractionDetector : MonoBehaviour
{
	// Ray가 충돌한 오브젝트의 정보를 저장하는 변수
    private RaycastHit hit;
    
    private KeyCode InteractionKey = KeyCode.F;
    
    void Update()
    {
        if (Input.GetKeyDown(InteractionKey))
        {
            CheckInteraction();
        }
    }

    private void CheckInteraction()
    {
    	// 화면 중앙 좌표를 구해서 Ray 생성 (크로스헤어 방식)
        Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
        
        // Ray를 5미터 거리까지 쏘아서 충돌 감지
        if (Physics.Raycast(ray, out hit, 5f))
        {
        	// 충돌한 오브젝트의 태그가 "Bench"인지 확인
            if (hit.collider.CompareTag("Bench"))
            {
                Debug.Log("Bench를 감지했습니다!");
            }
        }
    }
}

🖥️ 임시 제작대 UI 제작 (Bench_Panel)

- 구조

Bench_Panel에 두 개의 Background, 그리고 Scroll View를 추가했습니다.

Bench_Panel
	├── Background (Image)
	├── Background2 (Image)
	└── Scroll View (Scroll View)
  1. Scroll View -> Viewport -> Content 컴포넌트에 Grid Layout GroupContent Size Fitter을 추가합니다.

  2. ContentUI_Slot을 테스트 용으로 다수 집어 넣습니다. 나중에 스크립트에서 동적으로 할당하게끔 변경할 예정입니다.

- 기타 설정

  1. Scroll View 의 Scroll Rect
    • Horizontal: 체크해제
    • Vertical: 체크
    • Scroll Sensitivity: 스크롤 속도
  2. ContentContent Size Fitter
    • Horizontal Fit: Unconstrained
    • Vertical Fit: Preferred Size

- UI 완성 및 스크롤 테스트

  • 스크롤이 되지 않을 경우, UI가 열릴때 아래 코드를 실행하게 하세요.
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = true;

📄 스크립트에 변수와 함수 추가

Bench를 바라본 채 F를 누르면 BenchPanel이 켜지고 꺼지는 코드입니다.

// UIManager.cs

public GameObject benchPanel;
private bool isBenchOpen = false;

public void ToggleBench()
{
	if (!benchPanel) return;
    isBenchOpen = !isBenchOpen;
    benchPanel.SetActive(isBenchOpen);
    SetMouseState();
}

// UI가 띄워져 있을 때는 마우스 커서 활성화
private void SetMouseSate()
{
    if (isInventoryOpen || isBenchOpen)
    {
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = true;
    }
    else
    {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }
}
// InteractionDetector.cs

[SerializeField] private UIManager uiManager;

private void CheckInteraction()
{
    Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
    if (Physics.Raycast(ray, out hit, 5f))
    {
        if (hit.collider.CompareTag("Bench"))
        {
            if (!uiManager) return;
            uiManager.ToggleBench();
        }
    }
}

✔ 중간 확인

제작대 창이 켜지고 꺼지는 것을 확인할 수 있습니다.


⚠️ 중간 문제점!

1. 끄고 다시 열 때 스크롤이 원위치가 되어있지 않음

  • 해결방안: Bench UI가 열릴 때는 ScrollRect를 원위치로 두자!
// UIManager.cs 

private ScrollRect benchScrollRect;

void Start()
{
    if (benchPanel != null)
    {
        benchScrollRect = benchPanel.GetComponentInChildren<ScrollRect>();
    }
}

public void ToggleBench()
{
    if (!benchPanel) return;
    isBenchOpen = !isBenchOpen;
    benchPanel.SetActive(isBenchOpen);

    if (isBenchOpen && benchScrollRect != null)
    {
        benchScrollRect.verticalNormalizedPosition = 1f;
    }

    SetMouseSate();
}

2. Bench UI를 킨 채로 다른 곳을 보면 꺼지지 않음

  • 해결방안: 시야내에 Bench가 있어야 ToggleBench()가 실행하게 코딩되어 있다. UI가 띄워져 있는 동안은 이동 및 카메라 회전을 잠궈두자!
// GameState.cs 스크립트 추가

using UnityEngine;

public class GameState : MonoBehaviour
{
    public static bool IsUIOpen = false;
}
// UIManager.cs

private void SetMouseSate()
{
    if (isInventoryOpen || isBenchOpen)
    {
        GameState.IsUIOpen = true;
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = true;
    }
    else
    {
        GameState.IsUIOpen = false;
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }
}
// PlayerController.cs

void Update()
{
    if (!GameState.IsUIOpen)
    {
        HandleMouseLook();
        HandleMovement();
        HandleJump();
    }
}

3. Bench 와 Inventory UI가 동시에 켜질 가능성이 있음

  • 해결방안: 한 쪽 UI가 켜져있을 경우 Toggle함수가 return되게 하자!
// UIManager.cs
// 각 함수에 isBenchOpen 혹은 isInventoryOpen일 경우 return 한다는 조건을 추가함

private void ToggleInventory()
{
    if (!inventoryPanel || isBenchOpen) return;
    isInventoryOpen = !isInventoryOpen;
    inventoryPanel.SetActive(isInventoryOpen);
    SetMouseSate();
}

public void ToggleBench()
{
    if (!benchPanel || isInventoryOpen) return;
    isBenchOpen = !isBenchOpen;
    benchPanel.SetActive(isBenchOpen);

    if (isBenchOpen && benchScrollRect != null)
    {
        benchScrollRect.verticalNormalizedPosition = 1f;
    }

    SetMouseSate();
}

🎮 최종 결과

UI 완벽 제어 완료!!


📚 오늘의 배운 점

  • Material 적용 및 생성
  • 오브젝트 감지 - (Ray, Raycast, RaycastHit)
  • Bench UI - Scroll View

🎯 다음 계획

다음 글에서는:

  1. 시간이 지날 수록 줄어드는 배고픔, 목마름 수치 구현
  2. 데미지를 받을 때 줄어드는 체력 수치 구현
profile
Unreal Engine & Unity 게임 개발자

0개의 댓글