본문 바로가기

블로그 / 기술

소리 없는 이벤트 찾기: PallMark 효과음을 코드에서 데이터 표로 옮긴 세 단계

개발 중인 PallMark에서 게임이 내는 이벤트 86개와 스킬·시길·몬스터의 소리 경로를 전수 조사하고, 빈자리를 데이터 표로 채운 기록이다. 일반 적 57종을 음색 그룹 10개로 나누고, 같은 WAV를 2D와 3D에 동시에 걸어 생긴 충돌도 고쳤다.

Salmonholic ·· 6분 읽기

PallMark 주방 테마 아레나에서 고블린 무리에 둘러싸인 각인병이 양손검을 휘두르는 장면

PallMark는 아직 개발 중인 탑 오르기 액션 게임이고, Steam 출시를 준비하고 있다. 9월 6일에 로드맵 다섯 번째 항목을 “구매한 효과음 3,070개를 이벤트에 배선하기”로 정해 두었다. 주로 쓰는 팩은 효과음 2,944개가 든 중세 판타지 번들이다. 발소리는 넣지 않기로 9월 5일에 정했다. 번들에 발소리가 없어서다.

문제는 그사이 들어온 기능이 많았다는 점이다. 테마 아레나 다섯 곳의 몬스터와 보스, 보스 패턴, 층 보상 상자, 마을 포탈, 레벨업 카드, 유니크 아이템의 규칙형 효과가 대부분 소리 없이 들어왔을 가능성이 컸다. 그래서 9월 26일 오후부터 다음 날 새벽까지 소리 작업을 세 단계로 나눠 진행했다.

먼저 무엇이 조용한지부터 셌다

첫 단계(9월 26일)는 새 소리를 붙이기 전에 목록부터 만드는 일이었다. Unity를 켜지 않고 코드와 데이터만 읽어서, 게임이 내보내는 표현 이벤트마다 “소리 있음 / 없음 / 지정은 됐는데 파일이 없음”을 표로 정리했다.

조사 대상 개수
게임 이벤트 종류 86
스킬 134
시길 540
몬스터 종류 24

다행히 지정된 구매 WAV 중 실제로 없는 파일은 0개였다. 대신 빈자리가 순위별로 드러났다. 보호막이 깨질 때와 동료가 쓰러지고 일어설 때는 오디오 쪽에서 이벤트를 아예 듣지 않고 있었다. 일반 적 24종은 공용 타격음 하나를 같이 썼고, 피격음은 재질 두 가지뿐이었다. 회복, 장착 거부, 포탈 닫힘, 체력 구슬 떨어짐 같은 것들은 무음이었다.

반대로 일부러 비워 둔 것도 있다. 장판 생성·종료, 보스 효과, 오라 맥동, 스킬 적중은 이미 다른 소리와 겹쳐 나기 때문에 독립된 소리를 무조건 붙이지 않았다. 다 채우는 것보다 겹쳐서 시끄러워지지 않게 하는 쪽이 중요했다.

보스 예고음은 switch 문에서 표로

첫 단계에서 바로 손댄 것은 공격 예고음이다. 예고는 전투 판독에 직접 영향을 주기 때문에 우선순위가 가장 높았다. 원래 보스 예고음은 코드 안 switch 문에 패턴 5개만 적혀 있었다. 패턴이 늘 때마다 코드를 고쳐야 하는 구조였다.

이것을 효과음 매핑 JSON의 telegraphs 표로 옮기고 15개 패턴을 채웠다. 음량은 보스 패턴을 0.650.85로, 일반 아레나 몬스터의 직선·부채꼴 예고를 0.7로 잡았다. 같은 소리가 연타되는 피로를 줄이려고 클립마다 변주 24개를 두고 동시 재생은 3개로 제한했다.

성소 보스가 바닥에 붉은 삼각형 공격 예고를 그리는 장면

옮기다가 결함도 하나 찾았다. 일반 아레나 몬스터도 보스와 같은 예고 이벤트 형식을 쓰는데, 코드는 처음 들어온 예고에 보스 등장음을 울리고 있었다. 일반 적의 예고가 먼저 나오면 보스가 없는데도 등장음이 날 수 있었다. 이벤트에 보스 ID가 있을 때만 등장음으로 치도록 조건을 하나 넣었다.

이벤트 12개와 몬스터 57종을 데이터로

두 번째 단계(같은 날 늦은 오후)는 남은 공백을 채우는 일이었다. 원칙은 하나였다. 코드에 소리 이름을 더 적지 않고, 전부 JSON 표에 넣는다. 그래서 이벤트 이름과 소리, 조건을 한 줄로 적는 eventRoutes를 만들었다.

{
  "eventName": "heal",
  "sfxId": "event_heal",
  "gain": 0.35,
  "cooldownTicks": 12,
  "positionField": "target_id",
  "positiveField": "amount",
  "minimumAmount": 2.0
}

회복은 자주 나기 때문에 가장 조심했다. 2 미만의 작은 회복은 소리를 내지 않고, 한 번 울리면 12틱 동안 다시 울리지 않는다. 시뮬레이션이 20Hz로 돌기 때문에 0.6초다. 스킬 거부나 장착 거부는 내 캐릭터에게 일어났을 때만 울리고, 창고 이동은 실제로 성공했을 때만 울린다. 포탈·보상 창 닫힘과 구슬 소멸처럼 끝을 알리는 소리는 0.25로 짧고 작게 했다. 체력 구슬을 주울 때는 회복음 위에 물약 소리가 한 번 더 얹히고 있어서 중복을 걷어냈다. 이렇게 상태 변화 이벤트 12개를 표로 연결했다.

일반 적은 테마와 체형으로 음색 그룹 10개를 만들고, 실제 몬스터 ID 57개를 하나씩 그룹에 배정했다. 그룹마다 공격·피격·사망 소리와 다시 울리기까지의 간격을 따로 둔다. 주방의 작은 적은 공격음 간격이 12틱이고, 성소의 신성 계열은 50틱이다. 떼로 몰려오는 작은 적은 자주 울려도 가볍고, 무거운 적은 드물게 울려야 묻히지 않는다.

지하묘지 해골, 도서관 유령, 실험실 버섯 무리. 테마마다 적의 재질이 달라 소리도 달라야 했다

일반 적 57종을 음색 그룹 10개에 배정한 수. 지하묘지 뼈 10종이 가장 많고 실험실 두꺼비 2종이 가장 적다

배정이 빠진 몬스터는 예전 공용 소리로 돌아가고, 빠진 ID를 진단 목록으로 돌려준다. 새 몬스터를 추가하고 배정을 잊어도 게임은 조용해지지 않고, 빠진 것은 목록에 드러난다. 막지 않고 보이게 하는 쪽을 골랐다.

같은 WAV를 2D와 3D에 동시에 걸었다

세 번째 단계(9월 27일 새벽)는 두 번째 단계가 만든 결함 수습이었다. 체력 구슬 떨어짐에 붙인 클립 두 개가 일반 전리품 소리와 같은 파일이었다. 문제는 전리품 소리는 화면 소리(2D)이고, 구슬 소리는 위치가 있는 소리(3D)라는 점이다. 3D 소리는 모노로 가져와야 해서, 가져오기 규칙이 같은 파일에 서로 다른 설정을 요구했다. 자동 설정 단계를 돌릴 때마다 두 .meta 파일이 뒤집혔고, 가져오기 규칙을 보는 시험이 새로 실패했다.

구슬 소리를 짧은 유리 소리 두 개(-14dB)로 바꿔 파일을 나눴다. 그리고 같은 파일이 2D와 3D 경로에 동시에 걸리면 파일 경로와 두 경로 이름을 같이 적어 실패시키는 검사를 넣었다. 이것만은 보이기만 해서는 안 되고 막아야 했다. 가져오기 설정은 파일당 하나뿐이라 둘 중 하나는 반드시 틀어지기 때문이다.

항목 수정 전 수정 후
구슬 떨어짐 클립 전리품 소리와 같은 파일 2개 전용 유리 소리 2개
고유 구매 클립 수 159 161
재생 시험의 기대 개수 숫자 74를 코드에 적음 JSON에서 읽어 비교

마지막 줄도 같은 날 고쳤다. 재생 시험 하나는 “음원 배정 74개”를 숫자로 들고 있었는데, 실제로는 93개로 늘어 있었다. 라우트를 늘릴 때마다 시험을 손으로 고치는 대신, 현재 JSON에서 개수를 읽고 중복 ID와 누락만 단언하게 바꿨다.

남은 일은 귀로 듣는 것

세 단계에서 바뀐 것을 요약하면, 소리 이름이 코드에서 표로 옮겨 갔다는 것이다. 예고음 15개, 상태 이벤트 12개, 몬스터 그룹 10개가 이제 JSON 한 파일에 있다. 다만 이 단계의 시험이 확인하는 것은 “가리키는 파일이 있는가”와 “간격과 상한이 지켜지는가”까지다. 실제로 귀에 거슬리지 않는지는 테마별 장면을 정해 직접 들어 보며 확인해야 하고, 그 목록을 다음 작업으로 남겼다.

틱 단위 시뮬레이션 이야기는 20Hz로 도는 게임을 144fps로 그리기에, 소리를 나눈 기준이 된 다섯 테마는 테마 아레나 다섯 곳을 설계하며에 적었다. 결함이 생긴 자리마다 검사를 하나씩 붙이는 방식은 PallMark 커밋 전 훅에서도 썼다. 게임 소개는 PallMark 게임 페이지에서 볼 수 있다.

#PallMark#사운드#효과음#Unity#데이터 주도#테스트

함께 읽으면 좋은 글

전체 글 →