Unity
숫자 버튼 하나를 누를 때마다 자동차가 도로를 달리고, 로봇 팔이 흔들리며, 인체 그래프가 춤추듯 차오른다면 어떨까요?
전*원··수정됨 2026.07.21

"공학적 사고"라는 추상 개념을 10가지 서로 다른 시각적 경험으로 풀어내되, 코드 베이스는 하나의 인터페이스 기반 액션 시스템으로 우아하게 통합할 수 있다면요. 이번 포스팅에서는 성남박물관 '공학자의 생각상자' 체험 콘텐츠를 인터페이스(Interface)와 싱글톤(Singleton) 패턴으로 확장 가능하게 설계한 기술적인 구현 과정을 공유합니다.

1. 시스템 아키텍처 개요
본 프로젝트는 크게 세 가지 단계로 구성됩니다.
입력 관리: 숫자 버튼(2, 3, 4, 6, 10) 클릭을 ButtonActionManager가 수신하여 AudioManager로 클릭음 재생 후 대응 애니메이션을 활성화
액션 디스패치: ActionManager가 자식 계층의 모든 ActionScriptInterface 구현체를 수집해 StartAction()을 일괄 호출
애니메이션 실행: 10여 종의 액션 스크립트가 각자의 타이밍·속도·진폭으로 Sin·Lerp·PingPong 기반 움직임을 재생
이 모든 과정은 Unity 2023.2.20f1의 단일 씬 구조에서 ActionManagerButtonActionManagerAudioManager 세 개의 싱글톤이 이벤트로 협업하는 방식으로 동작합니다.
2. 주요 기술적 구현
2.1 인터페이스 기반 액션 시스템 (ActionManager.cs)
다양한 애니메이션을 코드 수정 없이 확장할 수 있도록 모든 액션은 ActionScriptInterface 를 구현하도록 설계했습니다. 이 인터페이스는 StartAction() / StopAction() 두 메서드만 정의하며, ActionManager는 GetComponentsInChildren<ActionScriptInterface>()로 자식 계층의 모든 구현체를 자동 수집합니다. 덕분에 새로운 효과를 추가할 때 매니저 로직을 건드릴 필요 없이 인터페이스만 구현한 스크립트를 해당 버튼의 자식 오브젝트에 부착하기만 하면 됩니다.
```csharp
public interface ActionScriptInterface {
void StartAction();
void StopAction();
}
```
2.2 10종의 수학적 움직임 라이브러리 (Actions/*.cs)
액션 라이브러리는 수학 함수를 시각적 움직임으로 변환하는 소규모 스크립트의 모음입니다. ArmWavingScript는 Mathf.Sin 기반으로 자연스러운 팔 흔들림을, ZoomInOutScript는 Mathf.PingPong으로 확대/축소 왕복을, BiggerAndRemoveScript는 Lerp 보간 후 페이드 아웃까지 이어지는 2단계 애니메이션을 제공합니다. 각 스크립트는 인스펙터 필드로 튜닝 파라미터를 노출해, 개발자가 아닌 디자이너도 값을 조정해가며 원하는 효과를 만들 수 있도록 했습니다.
ShowImage / ShowText: startTime ~ EndTime 구간 표시
EditAlphaValue: 페이드인·아웃 + IsLoop / IsReverse 옵션
ArmWaving: wavingAngle · wavingSpeed 로 Sin 파형 제어
FiledImage: fillAmount 증가 애니메이션 (그래프용)
2.3 웨이포인트 기반 자동차 시뮬레이션 (CarManager.cs + CarSpawner.cs + MoveToDestinationScript.cs)
"자동차" 버튼을 누르면 Black / Red / Blue 3종 차량이 각자 지정된 웨이포인트 경로를 따라 도로를 달립니다. CarSpawner가 SpawnTime 간격으로 차량 프리팹을 생성해 CarPrefabs[3] 에서 선택 Instantiate하고, 생성된 차량에 부착된 MoveToDestinationScript가 MoveTowards + RotateTowards 조합으로 웨이포인트를 순회합니다. Vector3.Distance < 0.5f 조건으로 도착을 판정해 다음 포인트로 자연스럽게 전환하며, 효과 종료 시 CarManager.DestoryAllCar()가 모든 차량을 일괄 제거해 씬을 깨끗한 상태로 되돌립니다.
3. 사용자 경험(UX) 최적화
버튼 스팸 차단 : 버튼을 누른 직후 interactable = false로 비활성화하고, BlockButtonTime 경과 후 자동 재활성화해 연속 클릭으로 인한 애니메이션 중첩을 원천 차단합니다.
주기적 사용자 안내 : PlayMainMetapo가 메인 나레이션을 루프 재생하며, 11초 주기로 "여기를 터치하세요" 손 이미지가 투명도 0.3 로 은은하게 깜빡여 관람객의 다음 행동을 자연스럽게 유도합니다.
자동 리소스 할당 오디오 : AudioManager.PlaySound(ESoundType)이 사용 가능한 AudioSource를 자동 탐색해 재생하고, 부족하면 동적으로 생성함으로써 여러 효과음이 겹치는 상황에서도 잘림 없이 부드럽게 출력됩니다.
파라미터화된 튜닝 : 깜빡임 주기·페이드 속도·자동차 Spawn 간격·팔 흔들림 각도까지 모든 수치가 인스펙터 필드로 노출되어, 현장 반응에 따라 빌드 없이 즉시 튜닝할 수 있도록 했습니다.
4. 마치며
이 프로젝트는 "공학적 사고"라는 추상적 전시 주제를 10가지 시각적 움직임으로 구체화하면서, 코드 레벨에서는 단 하나의 인터페이스로 우아하게 통합한 작업이었습니다. Sin·Lerp·PingPong 같은 기초 수학 함수를 조합한 마이크로 애니메이션 라이브러리는 기술적으로도 흥미로웠지만, 관람객이 "버튼 하나 눌렀는데 이렇게 다채로운 장면이 펼쳐진다"고 느끼게 한 점에서 큰 의미가 있었습니다.
향후에는 현재의 고정된 5개 숫자 버튼 구조를 데이터 기반 동적 버튼 시스템으로 확장해 전시 리뉴얼 시 코드 수정 없이 새 주제를 추가할 수 있도록 하고, 각 액션의 파라미터를 ScriptableObject 프리셋으로 저장해 테마별 애니메이션 묶음을 한 번에 전환할 수 있도록 개선할 예정입니다.
읽기 도구
약 6분 읽기
이 글이 도움이 되었나요?