
Grid Layout Group로 인벤토리 UI 정렬childCountTextMeshPro-Text의 Auto SizeactiveInHierarchy 로 인벤토리 토글 만들기Instantiate 로 아이템 드랍하기EquipCamera)Animation Event로 메서드 호출하기Raycast 와 RaycastHit 로 오브젝트 감지하기인벤토리 구현 (1-10 ~ 1-12)
Grid Layout Group
자식 오브젝트들을 일정한 크기의 격자(Grid) 형태로 자동 정렬하는 레이아웃 컴포넌트
버튼, 아이콘, 아이템 슬롯, 인벤토리 등 격자 형태로 정렬할 때 유용하다.
Grid Layout Group 의 주요 속성

Cell Size : 각 아이템(버튼, 아이콘) 크기Spacing : 아이템 사이 간격 조절Start Corner : 아이템 배치 시작 위치 (왼쪽 위, 오른쪽 아래 등)Start Axis : 가로 또는 세로 방향으로 채워지는 방식 설정Constraint : 열 개수 또는 행 개수를 고정Child Alignment : 셀 내부에서 아이템의 정렬 방식Grid Layout Group 사용 방법:
1. Canvas 안에 Panel 또는 Empty GameObject를 만든다.
2. Inspector 창에서 Add Component → GridLayoutGroup 검색 후 추가.
3. GridLayoutGroup이 추가된 오브젝트에 자식 오브젝트(UI 버튼, 이미지 등)를 추가하면 자동으로 정렬된다.
아래는 GridLayoutGroup 오브젝트에 자식 오브젝트를 추가하고 그대로 복사한 모습. 자동으로 잘 정렬되는 것을 볼 수 있다 :


Spacing 을 통해 가로 세로 간격을 각각 15로 맞춰준 모습:

TextMeshPro-Text의 Auto Size

TextMeshPro-Text의 Auto Size 를 체크하면 설명이 길어질 때 설정한 min size까지 폰트 크기를 줄여 UI를 넘어가지 않도록 설정할 수 있다. 
Auto Size 를 체크하고, Min을 18로 조정한 모습: 
childCount : 해당 오브젝트의 자식 오브젝트가 몇 개인지 갯수를 받아올 수 있다. (UIInventory.cs)
void Start()
{
//초기화
controller = CharacterManager.Instance.Player.controller;
condition = CharacterManager.Instance.Player.condition;
//처음에 인벤토리가 보이면 안되므로 꺼진 상태로 시작
inventoryWindow.SetActive(false);
//아이템 슬롯은 슬롯 판넬의 자식 오브젝트로 들어가 있음
//childCount을 통해 슬롯 판넬의 자식 오브젝트 개수를 받아온 뒤 그만큼 슬롯을 만들어준다.
slots = new ItemSlot[slotPanel.childCount];
}
activeInHierarchy
activeSelf 와 다른점:activeSelf 는 해당 게임 오브젝트의 자체의 활성화 여부를 반환activeInHierarchy 는 오브젝트 자신이 SetActive(true) 로 활성화 상태여도 상위 부모 오브젝트가 비활성화되면 false 를 반환한다.Documentation Link 👉
activeInHierarchy 가 사용된 스크립트 (UIInventory.cs) ://인벤토리는 Tab키를 눌러서 열고 닫을 수 있도록 한다.
//열려있으면 닫고, 닫혀있으면 열도록 한다.
public void Toggle()
{
if (IsOpen())
{
inventoryWindow.SetActive(false);
}
else
{
inventoryWindow.SetActive(true);
}
}
//창이 열려있는지 확인하는 메서드
public bool IsOpen()
{
return inventoryWindow.activeInHierarchy;
}Instantiate
Instantiate를 아이템 드랍 메서드에 사용한 코드 (UIInventory.cs) ://인벤토리에서 선택한 아이템을 버리는 메서드
public void ThrowItem(ItemData data)
{
//아이템을 버리면 땅에 떨어져야 하므로 해당 아이템을 인스턴스화 시킨다.
//Instantiate(찍어낼 오브젝트, 찍어낼 위치, 찍을때 회전값)
Instantiate(data.dropPrefab, dropPosition.position, Quaternion.Euler(Vector3.one * Random.value * 360));
}장비 카메라 (EquipCamera)
카메라를 하나만 쓰는 경우 장착된 무기가 가려지는 문제가 발생한다.
때문에 장비만을 찍는 카메라를 따로 만들어 주어야함!
특정 오브젝트만을 찍는 카메라를 만드는 방법은 다음과 같다:
Clear Flags 속성을 Depth only 로 바꾸면, 아래 Culling Mask 항목에서 선택한 레이어 속성만 촬영할 수 있게 된다. 
Culling Mask 에 Equip 을 추가한 모습. 카메라에 레이어 속성이 Equip 인 도끼만 찍히는 것을 확인할 수 있다. (레이어 속성을 여러개 선택하는 것도 가능하다.) 
Clear Flags 속성을 바꿔준 EquipCamera 는 장비만 찍어주고 있지만, 실 게임에서는 아래와 같이 MainCamera 의 화면과 합쳐서 보여진다. 
자원 캐기 구현 (1-13 ~ 1-14)
Animation Event로 메서드 호출하기
플레이어가 장작을 팬다고 가정할 때, 도끼로 나무를 치는 순간 장작이 떨어져야지 나무를 치고 도끼를 내려놓았을 때 장작이 떨어지면 부자연스러울 것임.
때문에 아이템을 드랍하는 메서드는 애니메이션이 끝나고 난 뒤가 아니라, 애니메이션 실행 중에 메서드를 호출해주어야 하는데, 이런 상황에서 필요한 것이 바로 Animation Event이다.
Animation Event 를 추가하는 방법은 다음과 같다:
Window > Animation > Animation 을 클릭해 Animation 창을 연다 (또는 Ctrl+6)2. Animator Componont포함된 오브젝트(이 경우에는 도끼)를 선택한다.
내려치는 모션 타이밍에 맞춰 클릭 > 오른쪽 마우스 버튼 클릭 > Add Animation Event 클릭으로 Animation Event 추가 (혹은 왼쪽의 추가 버튼 클릭)

추가된 Animation Event 을 클릭하면 Inspector창에서 선택한 타이밍에 호출할 메서드를 선택할 수 있다.


Raycast 와 RaycastHit 로 오브젝트 감지하기
Raycasttrue를 반환하고, RaycastHit 에 충돌한 오브젝트 정보를 저장한다.Physics.Raycast() , 2D에서는 Physics2D.Raycast()RaycastHitbool isHit = Physics.Raycast(출발점, 방향, out RaycastHit 충돌정보, 최대 거리, 충돌할 레이어);
| 기능 | 설명 |
|---|---|
Physics.Raycast() | 특정 방향으로 Ray를 발사하여 충돌 감지 |
Physics.RaycastAll() | 광선이 충돌한 모든 오브젝트 감지 |
RaycastHit | 충돌한 오브젝트의 정보를 저장하는 구조체 |
LayerMask | 특정 레이어만 감지하도록 필터링 |
Physics2D.Raycast() | 2D 물리 엔진에서 Raycast 사용 |
Raycast 와 RaycastHit 로 오브젝트 감지하기 :public void OnHit()
{
//카메라의 중심에서 ray를 쏴서 공격 거리 내에 있는 오브젝트를 찾는다.
Ray ray = camera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
//ray와 충돌한 오브젝트의 정보를 저장할 변수
RaycastHit hit;
if (Physics.Raycast(ray, out hit, attackDistance))
{
//자원 수집이 가능한 장비이고, 충돌한 오브젝트가 Resource 컴포넌트를 가지고 있다면
if (doesGatherResources && hit.collider.TryGetComponent(out Resource resource))
{
//해당 자원을
resource.Gather(hit.point, hit.normal);
}
}
}실습 중 Tab 키를 눌러도 인벤토리 창이 열리지 않는 문제 발생:
Tab 을 누르면 마우스 잠금은 제대로 꺼지는데, 인벤토리 창은 열리지 않음Tab 키가 아닌 다른 키로 설정했는지 확인해보았으나 제대로 Tab 으로 설정해준 것을 확인 

OnInventory 메서드 확인:public void OnInventory(InputAction.CallbackContext context)
{
//Tab키를 누르면 inventory 델리게이트에 있는 함수를 호출
if (context.phase == InputActionPhase.Started)
{
inventory?.Invoke();
ToggleCursor();
}
}Toggle)를 가진 클래스 UIInventory.cs 에서, inventory 델리게이트에 Toggle 매서드를 구독시켜주었더니 정상적으로 작동함UIInventory.cs ) :private PlayerController controller; //정보를 주고받을 플레이어 컨트롤러
void Start()
{
controller = CharacterManager.Instance.Player.controller;
controller.inventory += Toggle; //추가한 코드
}
//인벤토리는 Tab키를 눌러서 열고 닫을 수 있도록 한다.
//열려있으면 닫고, 닫혀있으면 열도록 한다.
public void Toggle()
{
if (IsOpen())
{
inventoryWindow.SetActive(false);
}
else
{
inventoryWindow.SetActive(true);
}
}
//창이 열려있는지 확인하는 메서드
public bool IsOpen()
{
return inventoryWindow.activeInHierarchy;
}Raycast 는 이번에 처음 나온게 아닌 상호작용을 구현할 때도 사용했는데 정리하는 것을 잊었다.