캐릭터들이 부딪혀도 서로 자연스럽게 비켜서는 원인

좁은 문 하나로 캐릭터 여러 명이 한꺼번에 몰려드는 장면을 상상해보면 다들 정확히 같은 출구 지점을 목표로 움직이고 있습니다. 목표 지점만 보고 일직선으로 걷게 하면 이론상으로는 전부 같은 좌표에 겹쳐서 도착하는 것이 보통의 경우입니다.

그러나 실제 게임에서는 캐릭터들이 서로 몸을 슬쩍슬쩍 피하면서 자연스럽게 흩어져 지나가게 되는데요. 이 차이를 만드는 것은 물리 엔진의 충돌 처리가 아닌 “분리 스티어링”이라는 별도의 이동 보정 규칙입니다. 아래에서 이런 현상이 발생하는 원인에 대해서 알아보도록 하겠습니다.

다들 같은 곳을 향할 때

캐릭터의 이동 로직을 가장 단순하게 구성하면 매 프레임 목표 지점 방향을 계산해서 그쪽으로 한 걸음씩 옮기는 것이 전부입니다. 이 방법은 캐릭터가 혼자 움직일 때는 아무런 문제가 안된다고 할 수 있는데요. 하지만 여러 캐릭터가 동시에 같은 목표 위치, 예를 들어 같은 엄폐물이나 같은 출구를 향해 몰려들면 상황이 매우 달라집니다. 각자는 자기 목표만 보고 움직이기 때문에 다른 캐릭터의 존재 자체를 생각하지 않고 결국에는 여러 캐릭터가 정확히 같은 좌표를 향해 겹쳐 들어가게 됩니다.

보이즈에서 나온 규칙

이 문제에 대한 답은 이미 1986년에 나와 있었는데요. 컴퓨터 그래픽스 연구자 크레이그 레이놀즈는 새떼의 움직임을 컴퓨터로 재현한 “보이즈” 모델을 제작하면서 개체들이 따라야 할 3가지 규칙을 정리하였는데 그중 하나가 “가까운 동료와 너무 붙지 않도록 조종한다”는 분리 규칙입니다.

나머지 두 규칙인 정렬/응집과 다르게 분리는 오히려 서로를 밀어내는 방향으로 작동하는 것이 특이점이라고 할 수 있습니다. 이 로직이 원래는 새떼나 물고기떼의 움직임을 자연스럽게 하기 위해서 제작되었으나 지금은 게임 속 많은 캐릭터들이나 몬스터 무리가 서로 겹치지 않게 만드는 데에도 그대로 적용되고 있습니다.

정확히 어떻게 밀어낼까?

레이놀즈의 규칙은 개념만 제시할 뿐이지 구체적인 계산식까지는 정해주지 않았습니다. 오픈소스 AI 라이브러리 gdx-ai의 기술 문서는 이걸 실제 구현 수준으로 한 단계 더 풀어서 이야기하는데요.

“각 이웃까지의 벡터를 정규화한 후 거리의 역제곱 법칙에 따라 감소하는 세기를 곱해서 누적한다.”는 것이 이 문서가 설명하는 계산 방법입니다. 쉽게 말하면 다음과 같습니다. 캐릭터 하나를 기준으로 주변 일정 반경 안의 다른 캐릭터를 모두 찾고 그 각각에서 “나를 향해 오는” 방향 벡터를 계산한 뒤에 거리가 가까울 수록 훨씬 크게, 멀 수록 급격히 작게 가중치를 줘서 전부 합합니다.

이렇게 더해진 벡터가 그 캐릭터의 “밀려나는 방향”이 되고 원래 가려고 했던 목표 방향과 이 밀려나는 방향이 합쳐져서 최종 이동 방향을 결정합니다.

좁은 출구로 몰려드는 캐릭터 16명의 위치를 분리 스티어링 없음과 적용 두 경우로 비교한 산점도

16명을 직접 움직여보니

이 로직을 그대로 파이썬 코드로 옮겨서 좁은 출구 하나를 향해 캐릭터 16명이 동시에 응집되는 상황을 제작해봤습니다. 초당 30프레임 기준으로 8초 동안 움직임을 계산하면서 두 캐릭터의 중심 거리가 충돌 반경 합(0.7m)보다 가까워지는 “겹침”이 몇 번이나 발생하는지 매 프레임 카운트해봤습니다. 목표 방향으로만 이동하게 뒀을 때는 전체 프레임의 100%에서 겹침이 한 번 이상 발생했고 프레임당 평균 23.55쌍, 최대 44쌍까지 동시에 겹쳤습니다. 두 캐릭터가 거의 완전히 포개진 순간의 중심 거리는 3.8cm에 불과했죠.

그러나 분리 스티어링을 적용하자 상황이 너무나도 달라졌습니다. 겹침이 발생한 프레임은 전체의 5%로 줄어들었고 프레임당 평균 겹침 쌍수도 0.43쌍까지 줄어들었습니다.

같은 시각의 위치를 찍어보면 차이가 더 뚜렷했는데요. 목표 방향으로만 움직인 쪽은 캐릭터 16명이 한 덩어리로 뭉쳐 서로를 가리고 있었지만 분리 스티어링을 적용한 쪽은 같은 시점에 넓게 흩어진 채로 여전히 출구 방향으로 전진하고 있었습니다.

완전히 막지는 못했다

하지만 분리 스티어링을 적용해도 겹침이 0%까지 떨어지지는 않았습니다. 5%의 프레임에서는 여전히 겹침 현상이 발생하였고 그 순간의 최대 겹침 쌍수도 17쌍으로 나타났습니다.

이유는 아주 간단합니다. 이번 시뮬레이션의 목표 지점 자체가 폭이 없는 점 하나였기 때문입니다. 그렇기 때문에 아무리 캐릭터들이 서로를 밀어내도 결국 모든 캐릭터가 같은 한 점 근처로 수렴할 수 밖에 없었습니다.

분리 스티어링은 캐릭터들이 이동하는 동안 서로 겹치는 것을 크게 줄여주지만 목표 지점 자체가 극단적으로 좁은 병목이라면 그 지점 근처에서는 여전히 밀집이 생기게 됩니다. 실제 게임에서 문이나 통로처럼 진짜 병목 구간을 다룰 때 순서대로 통과시키는 큐 처리나 통로 폭 자체를 넓히는 방식이 따로 쓰이는 이유가 여기에 있었던 것입니다.

밀어내는 힘 하나의 효과

캐릭터 하나하나에 적용된 규칙은 “가까운 이웃에게서 멀어지는 방향으로 조금씩 밀려난다.”는 단순한 계산 하나 뿐이었습니다. 그런데 이 단순한 힘을 캐릭터 16명 모두에게 적용시켰을 뿐인데 전체 겹침 프레임 비율이 100%에서 5%로 떨어지는 결과가 나왔습니다. 개별 캐릭터 입장에서는 그저 옆 사람을 밀쳐냈을 뿐이지만 그 작은 판단들이 모여서 무리 전체가 자연스럽게 흩어지는 움직임으로 이어진 셈이라고 할 수 있습니다.

댓글 남기기