0%

Unity

키오스크 앞에 선 관람객에게 가장 좋은 UX는 무엇일까요? 버튼 하나를 눌렀을 때 예상대로 반응하고, 잠시 자리를 떠도 다음 사람이 깨끗한 화면에서 시작하며, 관리자는 복잡한 메뉴 없이 조용히 앱을 종료할 수 있는 것. 화려한 기능보다 **이 당연한 것들을 당연하게 만드는 일**이 더 어렵습니다

전*원··수정됨 2026.07.21

키오스크 앞에 선 관람객에게 가장 좋은 UX는 무엇일까요? 버튼 하나를 눌렀을 때 예상대로 반응하고, 잠시 자리를 떠도 다음 사람이 깨끗한 화면에서 시작하며, 관리자는 복잡한 메뉴 없이 조용히 앱을 종료할 수 있는 것. 화려한 기능보다 **이 당연한 것들을 당연하게 만드는 일**이 더 어렵습니다

이번 포스팅에서는 성남박물관 '미래 직업 소개' 키오스크 콘텐츠를 단 4개의 스크립트 로 견고하게 구축한 미니멀리스트 설계 접근을 공유합니다.

아키텍처_01_전체구조.png

1. 시스템 아키텍처 개요

본 프로젝트는 크게 세 가지 단계로 구성됩니다.

상태 관리: 메인 메뉴(Main)와 상세 이미지 뷰어(Info) 두 개의 캔버스를 HUDState enum 기반 상태 머신(State Machine)으로 전환

인덱스 매핑: 5개 직업 × 2장 이미지 = 10장을 단일 InfoImageTextures 배열에 평탄화하고, **짝수·홀수 인덱스 산술**로 이전/다음 페이지를 제어

무인 운영 안전망: 30초 유휴 자동 복귀와 관리자 전용 7회 연타 종료 패턴으로 무인 키오스크의 일상 운영을 보장

이 모든 과정은 **단일 씬** 구조에서 단 4개의 스크립트FutureJobFlowController, FutureJobQuitButton, AudioManager, ButtonManager)만으로 구현되어, 유지보수 비용을 최소화했습니다.

2. 주요 기술적 구현

2.1 평탄 배열 + 산술 연산으로 대체한 2D 데이터 구조 (FutureJobFlowController.cs)

"직업 5개 × 이미지 2장" 구조는 Texture2D[5][2] 같은 2차원 배열이 직관적이지만, Unity 인스펙터에서 관리하기 까다롭습니다. 대신 10장을 **1차원 InfoImageTextures 배열**에 순서대로 배치하고, 선택 시 selectedInfoIndex = index × 2로 진입점을 계산한 뒤 이전/다음 버튼은 홀짝 판정으로 경계 제어하는 방식을 선택했습니다. 덕분에 디자이너가 드래그 앤 드롭으로 이미지를 할당할 수 있으면서도 로직은 단순한 정수 산술만으로 완결됩니다.

```csharp

ChangeIndex(int index) {

selectedInfoIndex = index * 2;

InfoBGImage.texture = InfoImageTextures[selectedInfoIndex];

}

InfoBGChangeNext() { if (selectedInfoIndex % 2 == 0) selectedInfoIndex++; }

InfoBGChangeBefore() { if (selectedInfoIndex % 2 == 1) selectedInfoIndex--; }

```

2.2 자식 계층 자동 스캔 기반 클릭음 바인딩 (ButtonManager.cs)

키오스크에서는 모든 버튼에 "같은 클릭음"이 붙는 것이 일관성 있는 UX입니다. 하지만 버튼마다 onClick 이벤트를 수동 연결하는 방식은 버튼이 늘어날수록 유지보수가 피곤해집니다. ButtonManagerAwake() 시점에 GetComponentsInChildren<Button>(true)로 자식 계층의 모든 버튼을 자동 수집한 뒤 Start()에서 AudioManager.PlayClickSound를 일괄 등록합니다. 덕분에 디자이너가 버튼을 새로 추가해도 **부모 오브젝트 아래 두기만 하면** 자동으로 클릭음이 붙습니다.

2.3 연타 감쇠 기반 숨은 종료 버튼 (FutureJobQuitButton.cs)

무인 키오스크에는 관람객이 실수로 앱을 종료하는 일이 있어서는 안 되지만, 운영자는 필요할 때 조용히 종료할 수 있어야 합니다. FutureJobQuitButton은 이 상반된 요구를 **시간 가중 카운터** 로 풀어냈습니다. 매 탭마다 currentClick이 1씩 증가하지만 1초에 1씩 자연 감쇠하므로, 평범하게 탭하는 관람객은 절대 임계치(7)에 도달하지 못하고 운영자가 **1초 이내 빠르게 7회 연타** 해야만 종료 조건이 성립합니다. 동일 스크립트가 30초 유휴 감지도 담당해, Main 상태에서는 타이머를 정지시켜 "메인 메뉴가 영원히 떠 있는" 기본 상태를 보장합니다.

3. 사용자 경험(UX) 최적화

상태 기반 유휴 타이머 : NowWaitStatus()가 현재 캔버스가 메인 메뉴인지 확인해 **Main 상태에서는 유휴 타이머를 정지**시키고, Info 상태일 때만 30초를 카운트해 자연스러운 자동 복귀 시점을 제공합니다.

빌드/에디터 분기 커서 : Start()#if UNITY_EDITOR 블록으로 에디터에서는 커서를 보여 개발 편의성을 유지하되, 실제 빌드에서는 커서를 숨겨 터치 전용 키오스크 느낌을 살렸습니다.

미래 확장 훅 : MainStateStart() / InfoStateStart() 빈 메서드를 의도적으로 남겨 두어, 추후 상태 진입 애니메이션이나 사운드를 추가할 때 매니저의 조건문 블록을 뒤지지 않고 곧바로 해당 지점에 코드를 주입할 수 있는 확장 포인트로 활용할 수 있도록 했습니다.

이벤트 시스템 기반 종료 : 종료 버튼이 별도 UI 요소가 아닌 IPointerDownHandler를 구현한 투명 오브젝트로 숨겨져 있어, 관람객 눈에는 보이지 않지만 운영자만 위치를 알고 접근할 수 있습니다.

4. 마치며

이 프로젝트는 **"단순함도 설계의 대상"** 이라는 사실을 체감하게 한 작업이었습니다. 이미지 뷰어라는 단순한 요구사항에 평탄 배열 + 산술 연산, 자식 자동 스캔 바인딩, 시간 감쇠 카운터 같은 작은 설계 결정을 쌓아 올려 유지보수 부담을 극적으로 낮출 수 있었고, 관람객에게는 "그냥 자연스럽게 동작하는" 일관된 경험을 제공했다는 점에서 큰 의미가 있었습니다.

향후에는 InfoImageTextures 평탄 배열을 **ScriptableObject 기반 직업 데이터 에셋**으로 전환하여 이미지뿐 아니라 직업 설명 텍스트·대표 영상·연계 URL까지 한 번에 관리할 수 있도록 확장하고, MainStateStart / InfoStateStart 확장 포인트에 부드러운 전환 애니메이션을 추가해 콘텐츠 깊이를 한층 끌어올릴 예정입니다.

읽기 도구

6분 읽기

이 글이 도움이 되었나요?

다음으로 읽기