조향 행동(Steering Behaviors)과 Arrive 시뮬레이션 이해하기

게임이나 시뮬레이션에서 물체가 자연스럽게 목표를 향해 이동하게 하려면 어떻게 해야 할까요? 단순히 위치 좌표만 더해서는 로봇처럼 딱딱하고 부자연스러운 움직임이 나옵니다.

생명체처럼 자연스러운 움직임을 만들기 위해 널리 쓰이는 기법이 바로 크레이그 레이놀즈(Craig Reynolds)가 고안한 **조향 행동(Steering Behaviors)**입니다. 오늘은 이 중에서도 가장 기본이 되는 개념인 **조향력(Steer Force)**과, 목표 지점에 부드럽게 감속하며 멈춰 서는 Arrive(도착) 모델의 작동 원리를 물리와 수학적 관점에서 이해해 보겠습니다.


1. 힘과 벡터, 물체의 운동 상태

조향(Steer)을 코드로 구현하기 전에, 그 바탕이 되는 **벡터(Vector)**와 **힘(Force)**을 먼저 짚고 넘어가겠습니다.

벡터란 크기와 방향을 모두 가진 물리량입니다. 화면에 렌더링되는 오브젝트가 이동하려면 힘을 가해야 하는데, 힘 역시 ‘어느 방향으로’ ‘얼마나 세게’ 미는지를 정해야 하므로 벡터로 표현됩니다.

물체의 움직임을 이해하려면 뉴턴의 제2법칙인 F=maF = ma (힘 = 질량 ×\times 가속도)를 떠올려보세요. 식을 변형하면 a=Fma = \frac{F}{m}가 됩니다. 만약 렌더링되는 물체의 질량 mm11이라고 가정한다면, 식은 a=Fa = F가 되어 **‘물체에 가해진 힘은 곧 가속도이다’**가 성립합니다.

물체에 힘을 가하면 가속도가 생깁니다. 가속도가 생기면 속도가 변하고, 속도가 변하면 결과적으로 물체의 위치가 변하게 됩니다. 즉, 힘을 가하는 것은 물체의 가속도를 만들어 속도를 변화시키는 과정이며, 이 연쇄적인 업데이트 과정을 통해 물체가 부드럽게 이동하게 됩니다.


2. 조향력(Steering Force)의 비밀: 왜 속도의 차이가 힘일까?

조향(Steer)이란 물체가 원하는 방향과 속도로 움직이도록 현재의 운동 상태(속도)를 조절하는 것을 말합니다. 조향 알고리즘의 가장 핵심이 되는 공식은 다음과 같습니다.

Steering Force=Desired VelocityCurrent Velocity\text{Steering Force} = \text{Desired Velocity} - \text{Current Velocity} (조향력 = 원하는 목표 속도 - 현재 속도)

수식을 처음 보면 조금 당황스러울 수 있습니다. “어째서 속도(Velocity)끼리 뺐는데 그 결과가 힘(Force)이 되지?”

하지만 물리학적 정의를 떠올리면 명쾌해집니다. 가속도는 속도의 변화량입니다. 우리가 현재 속도에서 목표로 하는 속도로 상태를 바꾸려면 Δv\Delta v (속도의 차이) 만큼의 가속을 가해야 합니다. 앞서 우리는 계산의 편의를 위해 질량을 1로 두어 ‘가속도 = 힘’으로 취급하기로 했습니다.

결국 이 속도의 차이, 즉 필요한 가속도가 곧 물체에 밀어주어야 할 **조향력(Steering Force)**이 되는 것입니다.


3. 위치를 빼면 방향이 나온다? (벡터의 뺄셈)

이제 목표 지점까지 부드럽게 다가가는 Arrive(도착) 모델을 살펴봅시다. 목표로 나아가려면 현재 내 위치에서 목표 지점까지의 방향과 남은 거리를 구해야 합니다. 이는 위치 벡터의 뺄셈으로 쉽고 우아하게 구할 수 있습니다.

먼저 1차원을 상상해 봅시다. 위치가 좌표축 위의 숫자라고 할 때, 내 위치가 +2+2이고 가야 할 타겟 위치가 +5+5라고 합시다. 타겟 위치에서 내 위치를 빼면 52=+35 - 2 = +3이 나옵니다. 이는 즉 **‘오른쪽(양의 방향)으로 3만큼 떨어진 거리’**를 의미하죠.

이 논리는 2차원으로도 똑같이 확장됩니다. 현재 위치가 A(2,3)A(2, 3)이고 목표 위치가 B(5,7)B(5, 7)이라면 두 점의 벡터를 빼면 BA=(52,73)=(3,4)\vec{B} - \vec{A} = (5-2, 7-3) = (3, 4)를 얻습니다. 이 (3,4)(3, 4) 벡터는 수학적으로 시작점 AA에서 목표점 BB를 향해 그어진 화살표입니다.

즉, 목표 위치(Target)에서 현재 위치(My Position)를 빼는 것만으로도 우리는 타겟을 향하는 ‘방향’과 남은 ‘거리(벡터의 크기)‘를 한 번에 얻을 수 있습니다.


4. 종합: Arrive 시뮬레이션 의사코드(Pseudocode) 작성하기

조향 알고리즘의 동작 순서는 다음과 같습니다. 이 흐름은 거의 모든 Steering Behavior의 기본 뼈대가 됩니다.

  1. 원하는 이동 벡터(Desired) 구하기: 타겟 위치 - 현재 위치
  2. 목표까지의 거리(Distance) 계산: Desired 벡터의 길이(magnitude)
  3. 원하는 속력 정하기: 목표까지 남은 거리가 특정 감속 반경(Radius) 이내라면 거리에 비례하여 속도 감소, 반경 밖이라면 최고 속도(MaxSpeed)로 설정
  4. 목표 속도 벡터(Desired Velocity) 세팅: Desired 벡터의 방향을 유지한 채 길이(속력)를 3번의 값으로 재조정
  5. 조향력(Steer Force) 계산 및 적용: Desired Velocity - Current Velocity 후 물체에 적용

이를 코드로 표현하면 다음과 같습니다.

// 1. 타겟을 향한 벡터(방향+거리) 도출
let Desired = Target - MyPosition;
let Distance = Desired.mag();

// 2. Arrive 로직: 거리에 따라 속력을 조절
let Speed = 0;
if (Distance < Radius) {
    // 반경 내에 들어오면 거리에 비례해 감속 (0 ~ MaxSpeed)
    Speed = mapRange(Distance, 0, Radius, 0, MaxSpeed);
} else {
    // 반경 밖이면 최고 속도로 직진
    Speed = MaxSpeed;
}

// 3. Desired에 속력 적용 (방향은 유지, 크기만 Speed로 변경)
Desired.setMag(Speed);

// 4. 최종 조향력 계산 (목표 속도 - 현재 속도)
let Steer = Desired - CurrentVelocity;

// 5. 물체의 물리계에 조향력 가하기
Vehicle.applyForce(Steer);
Vehicle.update(delta); // 속도, 위치 업데이트