🛠️ 오늘 한 작업
- 실전 모의 면접 2회차를 진행했습니다.
- 이번에는 Unity와 C# 기초 관련 질문을 많이 받았습니다.
- 인벤토리는
Tab, 장비창은O입력으로 열 수 있도록 연결했습니다. - 화면 드래그 작업으로 패널을 드래그해서 이동할 수 있게 만들었습니다.
- 인벤토리에서 장비를 더블클릭해 장착하면 장비창이 자동으로 열리도록 수정했습니다.
- 장비창 슬롯을 더블클릭했을 때 장착 해제가 가능하도록 작업했습니다.
- 퀵슬롯 버튼을 눌렀을 때 소비 아이템이 바로 사용되도록 수정했습니다.
- 기획 변경에 맞춰 퀵슬롯 아이템 수량이 0이 되어도 자동 삭제하지 않고, 직접 삭제해야 없어지도록 바꿨습니다.
📌 오늘 계획
오전에는 면접 준비와 UI 사용성 개선 작업을 목표로 잡았습니다.
- 면접 준비하기
- 장비창 더블클릭 시 장착 해제 처리하기
- 패널 드래그와 닫기 버튼 위치 수정하기
- 퀵슬롯 버튼을 눌렀을 때 소비 아이템이 바로 사용되도록 수정하기
오후에는 작업을 더 이어가려고 했지만, 면접도 있었고 중간에 확인해야 할 부분이 많아서 계획처럼 깔끔하게 진행되지는 않았습니다.
그래도 오늘은 인벤토리, 장비창, 퀵슬롯을 실제 플레이 흐름에서 조금 더 편하게 사용할 수 있도록 다듬는 작업을 많이 했습니다.
🎤 기술 모의 면접
오늘도 실전 모의 면접을 봤습니다.
이번에는 인성 면접보다는 Unity나 C# 기초 쪽 질문이 더 많이 나왔습니다. 기억나는 질문으로는 public, private 같은 접근 제한자 관련 질문, SRP에 대한 질문, 그리고 게임에서 시간을 다룰 때 어떤 시간대를 기준으로 해야 하는지에 대한 질문이 있었습니다.
시간 관련 질문은 꽤 인상 깊었습니다. 게임을 만들 때 한국 시간만 생각하면 안 되고, 다른 나라 유저가 있을 때는 시간대가 달라질 수 있습니다. 그래서 서버나 저장 데이터에서는 기준 시간을 통일하고, 실제 표시할 때는 지역 시간으로 보여주는 식으로 생각해야겠다고 느꼈습니다.
저는 마지막 면접자라서, 앞에서 면접을 본 팀원들에게 어떤 질문을 받았는지 조금 물어볼 수 있었습니다. 덕분에 어떤 방향으로 질문이 나올지 어느 정도 감을 잡고 들어갈 수 있었습니다.
이번에도 튜터님께서 제가 제일 잘 봤다고 말씀해주셔서 정말 다행이었습니다. 저번 면접도 긴장했는데, 이번에는 기술 질문이 섞여 있어서 더 걱정됐습니다. 그래도 준비한 내용과 기존에 공부했던 내용을 바탕으로 답변할 수 있어서 조금 안심했습니다.
🪟 인벤토리 / 장비창 열기
개발 쪽에서는 먼저 인벤토리와 장비창을 열고 닫는 흐름을 만들었습니다.
인벤토리는 Tab, 장비창은 O 입력으로 열리도록 연결했습니다. 기존에는 UI를 직접 켜두거나 테스트용으로 확인하는 느낌이었다면, 이제는 실제 플레이 중 입력으로 패널을 여는 흐름에 가까워졌습니다.
PlayerInputHandler.cs - 인벤토리 / 장비창 입력 연결
public void OnInventory(InputAction.CallbackContext context)
{
if (!context.performed) return;
GameManager.Instance.UIManager.OpenInventoryPanel();
}
public void OnEquip(InputAction.CallbackContext context)
{
if (!context.performed) return;
GameManager.Instance.UIManager.OpenEquipPanel();
}
UIManager도 추가해서 인벤토리, 장비창, 퀵슬롯 패널을 관리하도록 했습니다. 시작할 때 인벤토리와 장비창은 꺼두고, 퀵슬롯은 켜두는 방식으로 설정했습니다.
UIManager.cs - UI 패널 기본 상태
void Start()
{
inventoryPanel.gameObject.SetActive(false);
equipPanel.gameObject.SetActive(false);
quickSlotPanel.gameObject.SetActive(true);
}
이런 작업은 기능 자체는 단순해 보이지만, 실제 게임처럼 조작하려면 꼭 필요한 부분입니다. 인벤토리와 장비창이 언제 열리고 닫히는지 명확해야 이후 다른 UI와도 충돌이 덜 날 것 같습니다.
🧲 패널 드래그 기능
패널을 드래그해서 움직일 수 있도록 PanelDrag도 추가했습니다.
기획서에 패널 자체를 드래그할 수 있는 내용이 있었기 때문에, 인벤토리나 장비창 같은 UI를 고정 위치에만 두는 것보다 사용자가 직접 옮길 수 있게 만드는 방향으로 작업했습니다.
PanelDrag.cs - 패널 드래그 시작
public void OnBeginDrag(PointerEventData eventData)
{
if (targetPanel == null) return;
targetPanel.SetAsLastSibling();
RectTransformUtility.ScreenPointToLocalPointInRectangle(
targetPanel.parent as RectTransform,
eventData.position,
eventData.pressEventCamera,
out var localMousePos);
offset = targetPanel.localPosition - (Vector3)localMousePos;
}
드래그를 시작할 때 SetAsLastSibling을 호출해서, 클릭한 패널이 다른 패널보다 위로 올라오도록 했습니다. 여러 패널이 겹칠 수 있기 때문에 이 부분도 필요했습니다.
그리고 패널을 드래그하다가 화면 밖으로 완전히 나가버리면 다시 잡기 어려울 수 있습니다. 그래서 닫기 버튼을 기준으로 화면 밖으로 나가지 않도록 제한하는 처리도 추가했습니다.
PanelDrag.cs - 닫기 버튼 기준 화면 밖 이동 방지
private void KeepCloseButtonOnScreen()
{
Vector3[] corners = new Vector3[4];
standardRect.GetWorldCorners(corners);
float minX = 0;
float maxX = Screen.width;
float minY = 0;
float maxY = Screen.height;
Vector3 fix = Vector3.zero;
if (corners[0].x < minX) fix.x = minX - corners[0].x;
if (corners[2].x > maxX) fix.x = maxX - corners[2].x;
if (corners[0].y < minY) fix.y = minY - corners[0].y;
if (corners[2].y > maxY) fix.y = maxY - corners[2].y;
targetPanel.position += fix;
}
처음에는 닫기 버튼의 위치 하나만 기준으로 잡았는데, 이후에는 GetWorldCorners를 사용해서 영역 기준으로 확인하도록 수정했습니다. 단순히 한 점만 보면 버튼의 일부가 화면 밖으로 나갈 수 있어서, 코너 기준으로 보는 쪽이 더 안정적이라고 판단했습니다.
⚔️ 장착 시 장비창 자동 열기
인벤토리에서 아이템을 더블클릭해 장착했을 때, 장비창이 자동으로 열리도록 수정했습니다.
아이템이 장착됐는데 장비창이 닫혀 있으면 사용자가 장착 결과를 바로 확인하기 어렵습니다. 그래서 장착이 성공했을 때 장비창을 보여주는 방식으로 처리했습니다.
ItemSlot.cs - 장착 성공 시 장비창 열기
if (eq.TryEquipInventory(inv, Index, equipSlotType))
{
GameManager.Instance.UIManager.ShowEquipPanel();
}
UIManager에는 이미 장비창이 열려 있으면 그대로 두고, 닫혀 있을 때만 여는 ShowEquipPanel을 추가했습니다.
UIManager.cs - 장비창 표시
public void ShowEquipPanel()
{
if (!equipPanel.gameObject.activeSelf)
{
equipPanel.gameObject.SetActive(true);
}
}
이건 작은 사용성 개선이지만, 실제로 장비를 장착했을 때 결과를 바로 확인할 수 있어서 훨씬 자연스럽다고 느꼈습니다.
🖱️ 더블클릭 장착 해제
장비창에서도 더블클릭으로 장착 해제가 가능하도록 작업했습니다.
이전에는 인벤토리에서 장비를 장착하는 흐름에 더 집중했다면, 이제는 장착된 아이템을 다시 빼는 흐름도 UI에서 자연스럽게 처리해야 했습니다.
ItemSlot.cs - 장비 슬롯 더블클릭 해제
case SlotKind.Equipment:
var itemDB = DataManager.Instance.ItemDB;
if (itemDB == null) return;
eq.UnEquipToIndex(inv, Index, equipSlotType);
break;
장비 해제는 단순히 장비 슬롯에서 빼는 게 아니라, 인벤토리의 어느 위치로 돌아갈지도 같이 생각해야 합니다. 그래서 기존에 만든 UnEquipToIndex 흐름을 사용해 장비창 더블클릭과 연결했습니다.
⚡ 퀵슬롯 아이템 바로 사용
퀵슬롯 입력도 수정했습니다.
기존에는 선택된 퀵슬롯을 다시 눌렀을 때만 사용되는 흐름에 가까웠는데, 오늘은 퀵슬롯 버튼을 누르면 바로 선택 처리와 사용 처리가 이어지도록 수정했습니다.
QuickSlotController.cs - 퀵슬롯 입력 시 사용 호출
public void SelectSlotByNumber(int number)
{
int index = Mathf.Clamp(number - 1, 0, 4);
var slotType = (QuickSlotType)index;
SelectedIndex = index;
ApplySelection();
EquipSelectedIfWeapon();
if (index == SelectedIndex)
{
Use(slotType);
return;
}
}
사실 이 코드는 아직 더 정리가 필요해 보입니다. SelectedIndex를 먼저 바꾼 뒤 바로 비교하고 있어서, 조건 자체가 항상 true처럼 보일 수 있습니다. 다만 오늘 작업 의도는 분명했습니다. 퀵슬롯 키를 눌렀을 때 소비 아이템은 바로 사용되도록 만들고 싶었습니다.
마지막에는 기획자님 의견에 맞춰 퀵슬롯 수량이 0이 되어도 자동으로 삭제하지 않도록 수정했습니다. 즉, 아이템을 다 써도 퀵슬롯 칸 자체는 남아 있고, 사용자가 직접 삭제해야 없어지는 방식입니다.
QuickSlotController.cs - 수량 0이어도 자동 삭제하지 않기
if (inv.HasInventoryItem(itemId) <= 0) return;
var player = GameManager.Instance.ActivePlayer;
if (player == null) return;
player.AddHunger(c.HungerRecover);
player.AddThirst(c.ThirstRecover);
player.AddStamina(c.MaxStaminaBuffAdd);
if (!inv.TryRemoveByItemId(itemId, 1))
return;
처음에는 수량이 0이 되면 퀵슬롯에서 자동으로 지우는 게 자연스럽다고 생각했는데, 기획 방향은 달랐습니다. 기획자님은 수량이 없어져도 바로 삭제하지 않고, 직접 삭제해야 없어지는 쪽을 원하셨습니다.
그래서 퀵슬롯이 0 상태로 남아 있게 수정했습니다. 이런 부분은 개발자가 보기에는 자동 정리가 편해 보여도, 실제 UX나 기획 의도에 따라 달라질 수 있다는 걸 다시 느꼈습니다.
🧩 장신구 장착 슬롯 처리 수정
장신구 장착 처리도 조금 수정했습니다.
장신구는 슬롯이 Accessory1, Accessory2 두 개라서, 단순히 아이템 타입을 장비 슬롯 타입으로 바로 변환하면 문제가 생길 수 있습니다.
그래서 첫 번째 장신구 슬롯이 비어 있으면 Accessory1에 넣고, 두 번째 슬롯이 비어 있으면 Accessory2에 넣도록 수정했습니다. 둘 다 차 있으면 우선 첫 번째 슬롯으로 교체되도록 흐름을 잡았습니다.
ItemSlot.cs - 장신구 슬롯 선택
if (type == ItemType.Accessory)
{
if (eq.GetEquipped(EquipSlotType.Accessory1) == null)
{
equipSlotType = EquipSlotType.Accessory1;
}
else if (eq.GetEquipped(EquipSlotType.Accessory2) == null)
{
equipSlotType = EquipSlotType.Accessory2;
}
else
{
equipSlotType = EquipSlotType.Accessory1;
}
}
else
{
equipSlotType = (EquipSlotType)type;
}
이 부분도 장비창을 실제로 쓰기 시작하니까 보이는 문제였습니다. 장비 타입과 장비 슬롯이 항상 1:1로 매칭되는 건 아니라서, 이런 예외 처리를 더 신경 써야 했습니다.
📌 오늘의 회고
오늘은 기술 모의 면접과 UI 기능 개선을 같이 진행한 날이었습니다.
면접에서는 접근 제한자, SRP, 시간대 처리 같은 질문을 받았습니다. 처음 들으면 당황할 수 있는 질문도 있었지만, 앞에서 면접을 본 사람들에게 질문을 조금 물어보고 들어간 덕분에 어느 정도 마음의 준비를 할 수 있었습니다.
저번 면접에 이어 이번에도 튜터님께서 잘 봤다고 해주셔서 정말 다행이었습니다. 솔직히 기술 질문은 틀릴까 봐 더 긴장되는데, 그래도 공부한 내용과 프로젝트 경험을 엮어서 답변하려고 했던 게 좋게 보인 것 같습니다.
개발 쪽에서는 인벤토리와 장비창 열기, 패널 드래그, 더블클릭 장착/해제, 퀵슬롯 아이템 사용 같은 사용성 작업을 많이 했습니다. 기능을 만들수록 단순히 “동작한다”에서 끝나는 게 아니라, 사용자가 자연스럽게 쓸 수 있는지도 계속 봐야 한다는 생각이 듭니다.
특히 퀵슬롯 수량이 0이 됐을 때 자동 삭제할지 말지는 기획자님 의견에 따라 바뀐 부분이었습니다. 개발자 입장에서는 자동으로 정리되는 게 편해 보였지만, 기획 의도에 맞춰 직접 삭제하도록 남겨두는 게 맞았습니다.
오늘은 면접도 잘 끝났고, UI도 실제 플레이 흐름에 조금 더 가까워졌습니다. 아직 고칠 부분은 많지만, 그래도 이제 인벤토리와 장비창이 점점 “테스트용 기능”이 아니라 실제 게임 UI처럼 보이기 시작한 것 같습니다.
'내일배움캠프 본캠프' 카테고리의 다른 글
| [내일배움캠프 64일차 TIL] 최종 프로젝트 16일차 - 대화창 구조와 기본 무기/내구도 처리 (0) | 2025.12.30 |
|---|---|
| [내일배움캠프 63일차 TIL] 최종 프로젝트 15일차 - 드랍 아이템 시스템 구현 시작 (0) | 2025.12.29 |
| [내일배움캠프 61일차 TIL] 최종 프로젝트 13일차 - 가방 장착 처리와 퀵슬롯 아이템 사용 보완 (0) | 2025.12.24 |
| [내일배움캠프 60일차 TIL] 최종 프로젝트 12일차 - 퀵슬롯 상태 표시와 소비 아이템 사용 기능 (0) | 2025.12.23 |
| [내일배움캠프 59일차 TIL] 최종 프로젝트 11일차 - 퀵슬롯 수정과 플레이어 인벤토리 연결 (0) | 2025.12.22 |