AI 사용기
AI 활용기: 카메라 파라미터를 조율하는 대신 '항상 화면 안'을 수식으로 못박았다
턴제 전투 게임에서 캐릭터가 카메라 밖으로 사라지는 버그를 파라미터 미세조정으로 두 번 고쳤다가 세 번째로 재발했다. 세 번째는 값을 고치지 않고 '두 유닛이 항상 화면 안에 들어오는 최소 거리'를 계산하는 함수로 문제 자체를 없앴다. 게임 카메라 분야에서 같은 발상을 공식화한 사례들과 비교했다.
미세조정한 파라미터가 자꾸 재발하는 버그를 만나는 사람에게, '값을 더 잘 맞추기'와 '수학적으로 보장되는 구조로 바꾸기'가 다른 해결이라는 걸 실제 사례로 보여준다.
카메라가 두 캐릭터를 놓치는 버그를 dolly/tilt 비율 같은 파라미터로 두 번 고쳤지만 다른 연출(dodge, hit)에서 계속 재발했다. 세 번째 시도에서 AI와 함께 두 유닛의 위치·크기로 필요한 최소 화면폭을 역산해 카메라 거리의 하한선을 구하는 함수(min_dist)로 바꾸자, 클로즈업 강도를 얼마로 두든 그 하한선 밑으로는 절대 못 내려가게 되어 같은 종류의 버그가 구조적으로 사라졌다. 같은 원리를 Unity Cinemachine의 Group Framing과 카메라 시야각(CPF) 교집합을 이용한 occlusion-free 다중 타깃 논문이 각각 제품·학술 쪽에서 이미 공식화해뒀다.
같은 파라미터를 여러 번 손봐도 다른 상황에서 같은 버그가 재발한다면, 값을 더 정교하게 맞추기 전에 '이 값이 절대 넘으면 안 되는 경계'를 수식으로 세울 수 있는지부터 확인한다.
목차
먼저 답하면
혼자 만드는 턴제 전투 게임의 Godot 이식 작업에서, 카메라가 회피·피격 연출 중에 캐릭터를 화면 밖으로 완전히 놓치는 버그가 있었다. 처음 두 번은 “이 연출에서 카메라가 너무 세게 돈다”는 식으로 원인을 짚고 팬(pan) 비중이나 줌 강도 같은 파라미터 값을 손봤다. 고쳐진 것처럼 보였지만 다른 연출에서 같은 증상이 또 나왔다. 세 번째에는 값을 만지지 않고, “두 유닛이 항상 화면 안에 들어오려면 카메라가 최소 얼마나 떨어져 있어야 하는가”를 유닛 위치·크기·카메라 시야각으로 직접 계산하는 함수를 만들어 그 값 밑으로는 클로즈업이 아무리 강해도 못 내려가게 만들었다. 그 뒤로 같은 종류의 버그가 다시 나오지 않았다.
파라미터로 두 번 고치고, 세 번째에 재발했다
전투 연출은 회피(dodge)와 피격(hit) 이벤트마다 카메라가 캐릭터 쪽으로 돌리인(dolly-in)했다. 첫 버그 리포트는 “리베가 dodge·hit 중 화면 밖으로 완전히 사라진다”였다. 원인은 옛 HTML 프로토타입에 있던 화면 경계 클램프가 3D로 옮기면서 빠진 것이었고, _clamp_stage()(모든 이동에 스테이지 경계 적용)와 _cam_mid()(반응형 이벤트일 때 카메라가 두 유닛의 중간점을 보게 하고 돌리인 폭을 줄임)를 추가해 해결했다. 검증도 통과했다.
문제는 이 수정이 “이 이벤트에서는 팬 비중을 줄인다”는 식의 이벤트별 파라미터 조정이었다는 점이다. 다른 이벤트, 다른 카메라 강도 조합에서는 똑같은 증상이 다시 나올 여지가 남아 있었다. 실제로 재발했다.
값을 고치는 대신 “절대 못 넘는 하한선”을 만들었다
세 번째 시도에서는 접근을 바꿨다. _cam_on과 _cam_mid처럼 상황별로 다른 파라미터를 쓰던 함수들을 하나로 합치고, 카메라 거리를 직접 정하지 않았다. 대신:
- 리베와 적의 현재 위치·크기로 화면에 두 유닛을 모두 담으려면 필요한 최소 화면 폭·높이를 계산한다.
- 카메라의 시야각(FOV)과 화면비로, 그 폭·높이를 담으려면 카메라가 최소 얼마나 떨어져 있어야 하는지(
min_dist)를 역산한다. - 실제 카메라 거리는
min_dist * lerp(1.38, 1.04, tight)로 정한다.tight(클로즈업 강도)를 얼마로 두든 이 식의 결과는min_dist밑으로 내려가지 않는다.
클로즈업이 이전보다 아주 살짝 덜 타이트해지는 트레이드오프는 생겼지만, 두 유닛이 화면 안에 들어오는 것 자체는 연출 강도와 무관하게 항상 보장된다. 파라미터를 “잘 맞추는” 문제가 아니라 애초에 그 범위를 벗어날 수 없게 만든 것이다.
같은 발상을 게임업계가 이미 제품·논문으로 공식화해뒀다
이번 사례를 정리하며 비슷한 접근이 이미 표준화돼 있는지 찾아봤다.
- Unity Cinemachine의 Group Framing: 여러 오브젝트를
CinemachineTargetGroup으로 묶으면, 그룹 전체의 바운딩 정보를 계산해 카메라가 줌·돌리로 항상 그룹이 프레임 안에 들어오도록 조정한다. 오브젝트별로 가중치(Weight)를 줄 수는 있지만, “이 값이면 화면 밖으로 나갈 수도 있다”는 식의 파라미터 미세조정이 아니라 프레이밍 자체가 구조적으로 보장되는 방식이라는 점이 이번에 만든min_dist함수와 같은 방향이다. - 다중 타깃 occlusion-free 카메라 제어 연구: 카메라가 두 타깃을 동시에 담으려면 각 타깃의 “카메라가 놓일 수 있는 영역(CPF)“의 교집합(Intersection Area) 안에 있어야 한다는 조건과, 두 타깃 사이의 각도가 카메라 시야각을 넘지 않아야 한다는 조건(AOV constraint)을 명시적으로 정식화한다. 값을 조정해 우연히 맞추는 게 아니라, 애초에 “이 조건을 만족하는 위치가 아니면 카메라를 두지 않는다”는 제약으로 문제를 정의한다.
두 사례 모두 “카메라가 놓치지 않게 값을 잘 맞춘다”가 아니라 “놓칠 수 없는 위치·거리의 집합을 먼저 구하고, 그 안에서만 움직인다”는 순서를 따른다. 이번에 Godot에서 만든 min_dist 함수도 결국 같은 순서였다 — 다만 규모가 훨씬 작고 카메라가 “항상 두 유닛의 중간을 향한다”는 단순한 가정 위에서 즉석으로 유도한 버전이었다.
다음에 적용할 것
같은 버그가 이벤트를 바꿔가며 재발한다면, 그건 대개 “고친 그 상황”에서만 맞는 값을 찾았다는 신호다. 다음에는 파라미터를 더 정교하게 맞추기 전에 “이 변수가 넘으면 안 되는 경계를 수식으로 세울 수 있는가”부터 확인하기로 했다. 이번처럼 기하학적으로 유도할 수 있는 경우가 아니어도, 최소한 “이 조합에서 왜 이 버그가 재발했는가”를 값이 아니라 조건의 형태로 다시 써보는 것만으로도 같은 종류의 재발을 줄일 수 있었다.