소리꽃 KeyBloom TIL 8
파티클과 건반이 따로 놀던 색 설정을 하나로 통일하며 나온 것들.
같은 것을 두 곳에서 만들지 않기
그리는 방식은 달라도 규칙은 한 곳에 둔다
파티클과 건반은 색을 화면에 올리는 방식이 아주 다르다. 파티클은 수천 개라 색 단계별 스프라이트를 미리 구워 아틀라스(여러 스프라이트를 한 장에 모은 이미지)로 두고 찍어내고, 건반은 88개뿐이라 매 프레임 계산해서 칠한다.
방식이 다르니 코드도 따로 자랐고, 그러다 보니 같은 노트인데 파티클 색과 건반 색이 어긋나는 일이 생겼다.
정리하면서 나눈 기준은 이랬다. “무슨 색인가”를 정하는 규칙은 한 곳에 두고, “어떻게 화면에 올리는가”는 각자 둔다. 재료도 각자 갖는다 — 파티클과 건반을 다른 색으로 칠하고 싶을 수 있으니까.
두 곳에서 같은 일을 할 때 전부 합칠지 말지로 고민하게 되는데, 대개는 “판단”만 합치고 “실행”은 각자 두는 선이 맞다. 판단이 갈리면 결과가 어긋나 보이고, 실행까지 억지로 합치면 한쪽에 안 맞는 코드가 된다.
통일 작업의 절반은 새로 만드는 게 아니라 따로 자란 두 코드를 되돌리는 일이었다. 처음에 하나로 두는 것과 나중에 합치는 것의 비용 차이가 여기서 나온다.
다시 만들지 판정하는 기준은 빠짐없이 넣는다
아틀라스는 색이 바뀌면 다시 구워야 한다. 그래서 색을 정하는 값들을 이어 붙여 시그니처(캐시를 다시 만들지 판정하는 지문 문자열)를 만들고, 그게 달라지면 다시 굽는다.
이 시그니처에 값 하나를 빠뜨리면 조용히 깨진다. 색을 바꿨는데 화면은 그대로다. 오류도 안 나고 로그도 없다.
미리 만들어 두고 재사용하는 구조에는 항상 “언제 다시 만들 것인가”가 따라오고, 그 판정에 빠진 항목은 나중에 기능을 추가하는 사람이 만든다. 새 설정을 추가할 때 이 판정을 같이 고쳐야 한다는 걸 아는 사람은 처음 만든 사람뿐이라, 그 자리에 눈에 띄게 적어 두는 게 낫다.
제약이 다르면 구현도 갈라도 된다
되감기가 있는 경로는 결정적이어야 한다
색을 팔레트에서 하나씩 고르되 직전 색은 안 나오게 했다. 순진하게 만들면 직전 색을 기억해 두고 그때그때 뽑게 되는데, 스크럽(재생 위치를 끌어 옮기는 것)으로 되감아 다시 보면 색이 달라진다. 같은 입력이면 항상 같은 결과가 나오는 성질을 결정적이라고 하는데, 그게 깨진 것이다. 볼 때마다 바뀌는 것이다.
그래서 곡을 열 때 색 순서를 미리 정해 두고 그 표를 쓰게 했다. 같은 노트는 항상 같은 색이라 되감기·재생·영상 뽑기가 전부 일치한다.
그런데 라이브 연주에는 되감기가 없다. 여기서는 그때그때 뽑는 방식이 오히려 자연스럽다 — 칠 때마다 새 곡처럼 색이 달라진다.
같은 규칙인데 경로마다 구현을 다르게 뒀다. 처음엔 통일 안 한 게 찜찜했는데, 제약이 다르면 갈라도 된다. 오히려 같은 구현을 억지로 쓰면 한쪽에서 이상해진다. 판단 기준은 “이 경로에 되감기가 있나” 같은 실제 제약이지 일관성 자체가 아니다.
고르게 나오는지는 눈으로 못 보고 세어 봐야 안다
팔레트에 다섯 색을 넣었는데 두 색만 계속 나왔다. 색을 고를 때 쓰는 해시(입력을 뒤섞어 큰 숫자로 바꾸는 함수) 안에서 값이 뭉개져 결과가 몇 개로 쏠린 것이다.
고친 뒤에 실제로 세어 봤다. 다섯 색이 41번, 37번, 38번, 47번, 37번씩 나왔다.
무작위가 고른지는 화면만 봐서는 모른다. 몇 개만 나오는 것처럼 보여도 우연일 수 있고, 고르게 보여도 실제로는 쏠려 있을 수 있다. 무작위를 쓰는 자리는 한 번은 세어 보고 넘어가는 게 맞다.
형식이 여러 개일 때
우연히 멀쩡했던 경로가 새 기능에서 터진다
파티클 주변에 색 네모가 생겼다. 빛이 가장자리로 갈수록 투명해져야 하는데 투명이 안 되고 색이 그대로 남은 것이다.
원인은 색 문자열 형식이 두 가지(#rrggbb와 rgb(...))였다는 것이다. 투명하게 바꿔 주는 함수가 한쪽 형식만 처리할 줄 알았고, 기존 색 모드는 마침 그 형식만 쓰고 있었다. 새로 추가한 모드가 다른 형식을 쓰면서 드러났다.
기존 기능이 잘 돌아간다고 그 부분이 튼튼한 건 아니다. 입력이 한 종류라서 안 터졌을 뿐일 수 있다. 새 기능을 추가할 때 “여기 들어오는 값의 종류가 늘어나나”를 보면 이런 게 미리 잡힌다.
값을 문자열로 주고받으면 형식이 늘어나기 쉽다. 늘어날 것 같으면 받는 쪽을 전부 대응시키거나, 애초에 한 형식으로 못 박고 들어오는 자리에서 변환하는 게 낫다.
요약
- 두 곳에서 같은 일을 할 때 “판단”은 합치고 “실행”은 각자 둔다
- 미리 만들어 두는 구조에는 “언제 다시 만드나”가 따라온다 — 그 판정에서 빠진 항목이 조용한 버그가 된다
- 제약이 다르면 구현을 갈라도 된다. 기준은 일관성이 아니라 실제 제약이다
- 무작위가 고른지는 화면으로 모른다. 한 번은 세어 본다
- 기존 기능이 멀쩡한 건 입력이 한 종류라서일 수 있다 — 새 기능이 종류를 늘리는지 본다