포인트, 트라이포인트 및 좌표 시스템

게임은 3차원이며 축은 다음과 같이 정렬됩니다:

  • x축은 디스플레이에서 왼쪽에서 오른쪽으로 이동합니다(비등각 뷰에서).
  • y축은 디스플레이의 위에서 아래로 이동합니다.
  • z축은 수직이며, 음수 z는 지하를, 양수 z는 하늘을 가리킵니다.

좌표 시스템

CDDA는 다양한 목적을 위해 여러 좌표 시스템을 사용합니다. 이들은 규모와 원점에 따라 다릅니다.

가장 정밀한 좌표는 맵 스퀘어(ms) 좌표입니다. 이것은 게임을 플레이할 때 일반적으로 보는 타일을 나타냅니다.

맵 스퀘어 좌표의 두 가지 일반적인 원점:

  • 절대 좌표(때로는 글로벌이라고도 함)는 고정된 원점을 기준으로 하는 전체 게임의 글로벌 시스템입니다.
  • 로컬 좌표는 현재 "현실 버블" 또는 아바타를 중심으로 하는 map의 모서리를 기준으로 합니다. 로컬 맵 스퀘어 좌표에서 xy 값은 모두 [0, MAPSIZE_X) 범위에 속합니다.

다음 규모는 서브맵(sm) 좌표입니다. 하나의 서브맵은 12x12(SEEXxSEEY) 맵 스퀘어입니다. 서브맵은 맵의 청크가 현실 버블에 들어가거나 나갈 때 로드되거나 저장되는 규모입니다.

다음은 오버맵 터레인(omt) 좌표입니다. 하나의 오버맵 터레인은 2x2 서브맵입니다. 오버맵 터레인은 게임 내 맵 뷰의 단일 타일에 해당하며 맵젠의 청크 규모입니다.

가장 큰 것은 오버맵(om) 좌표입니다. 하나의 오버맵은 180x180(OMAPXxOMAPY) 오버맵 터레인입니다. 대규모 맵젠(예: 도시 레이아웃)은 한 번에 하나의 오버맵에서 발생합니다.

마지막으로 세그먼트(seg) 좌표라는 시스템이 있습니다. 이것은 서브맵 저장/로드에만 사용되며 마주칠 가능성이 낮습니다.

절대 및 로컬 좌표 외에도 때때로 더 큰 규모에 상대적인 좌표를 사용해야 합니다. 예를 들어 단일 오버맵에 대한 맵젠을 수행할 때 해당 오버맵 내의 좌표로 작업하려고 합니다. 이것은 포함하는 오버맵의 모서리를 기준으로 하는 오버맵 터레인 규모 포인트이므로 일반적으로 [0,180) 범위의 xy 값을 취합니다.

수직 좌표

xy 좌표는 이러한 다양한 규모에서 작동하지만 z 좌표는 모든 컨텍스트에서 일관됩니다. 이들은 [-OVERMAP_DEPTH,OVERMAP_HEIGHT] 범위에 있습니다.

차량 좌표

각 차량에는 고유한 원점이 있으며, 이는 차량의 특정 부분(예: 운전석)에 위치합니다. 차량이 손상되고 해당 위치의 모든 차량 부품이 파괴되면 원점이 이동할 수 있습니다.

차량은 원점을 기준으로 두 가지 좌표 시스템을 사용합니다:

  • 마운트 좌표는 차량이 이동할 때 변경되지 않는 차량 부품의 위치를 제공합니다. 차량이 정동쪽을 향할 때 차량 원점을 기준으로 한 해당 부품의 맵 스퀘어입니다.

  • 맵 스퀘어는 원점을 기준으로 하지만 차량의 현재 방향을 고려한 맵 스퀘어입니다.

차량 방향은 회전(1/4 회전) 및 전단의 조합을 통해 1/4 회전 사이를 보간하여 구현됩니다. 차량 마운트와 맵 스퀘어 좌표 간 변환 로직은 복잡하며 vehicle::coord_translate()vehicle::mount_to_tripoint() 함수 계열에서 처리됩니다.

현재 차량 마운트 좌표에는 z 레벨 구성 요소가 없지만 차량 맵 스퀘어 좌표에는 있습니다. z 좌표는 차량 원점을 기준으로 합니다.

포인트 타입

이러한 좌표 시스템으로 작업하기 위해 다양한 타입이 있습니다. 이들은 coordinates.h에 정의되어 있습니다. 예를 들어 절대 맵 스퀘어 좌표에 대한 point_abs_ms가 있습니다. 타입 이름의 세 부분은 차원 _ 원점 _ _규모_입니다.

  • 차원은 2차원의 경우 point, 3차원의 경우 tripoint입니다.
  • 원점은 값이 무엇을 기준으로 하는지 지정하며 다음과 같을 수 있습니다:
    • rel은 임의의 포인트를 기준으로 한다는 의미입니다. 공통 원점을 가진 두 포인트를 빼는 결과입니다. 예를 들어 아바타와 그들이 쏘는 몬스터 사이의 오프셋을 나타내는 데 사용됩니다.
    • abs는 글로벌 절대 좌표를 의미합니다.
    • sm은 서브맵의 모서리를 기준으로 한다는 의미입니다.
    • omt는 오버맵 터레인의 모서리를 기준으로 한다는 의미입니다.
    • om은 오버맵의 모서리를 기준으로 한다는 의미입니다.
    • veh는 차량 원점을 기준으로 한다는 의미입니다.
  • 규모는 위에서 논의한 규모를 의미합니다.
    • ms for 맵 스퀘어.
    • sm for 서브맵.
    • omt for 오버맵 터레인.
    • seg for 세그먼트.
    • om for 오버맵.
    • mnt for 차량 마운트 좌표(veh 원점에만 관련).

원시 포인트 타입

타입에 인코딩된 원점과 규모를 가진 이러한 타입 외에도 pointtripoint라는 간단한 원시 포인트 타입이 있습니다. 이들은 특정 게임 규모가 의도되지 않은 경우에 사용할 수 있습니다.

작성 시점에서 우리는 여전히 이러한 원시 포인트 타입을 어디서나 사용하는 것에서 코드베이스를 전환하는 과정에 있으므로, 더 타입 안전한 포인트가 적절해 보이는 곳에서 이들을 사용하는 레거시 코드를 볼 가능성이 높습니다.

새 코드는 가능한 경우 좌표 시스템을 포함하는 타입을 사용하는 것을 선호해야 합니다.

포인트 타입 간 변환

규모 변경

원점을 변경하지 않고 포인트의 규모를 변경하려면 project_to를 사용합니다. 예를 들어:

point_abs_ms pos_ms = get_avatar()->global_square_location().xy();
point_abs_omt pos_omt = project_to<coords::omt>( pos_ms );
assert( pos_omt == get_avatar()->global_omt_location().xy() );

동일한 함수 project_to를 확대 또는 축소에 사용할 수 있습니다. 더 거친 좌표 시스템으로 변환할 때 정밀도가 손실됩니다. 나머지가 중요하다면 대신 project_remain을 사용해야 합니다.

project_remain은 더 거친 좌표 시스템으로 변환하고 해당 거친 포인트를 기준으로 나머지를 캡처할 수 있습니다. 결과의 두 부분을 캡처하기 위해 std::tie와 함께 사용하도록 의도된 헬퍼 구조체를 반환합니다. 예를 들어 아바타가 어느 오버맵에 있는지, 그 오버맵 내에서 어느 오버맵 터레인에 있는지 알고 싶다고 가정합니다.

point_abs_omt abs_pos = get_avatar()->global_omt_location().xy();
point_abs_om overmap;
point_om_omt omt_within_overmap;
std::tie( overmap, omt_within_overmap ) = project_remain<coords::om>( abs_pos );

2차원 point 타입에는 적합하지만 tripoint는 어떻게 처리할까요? z 좌표는 수평 차원과 함께 스케일링되지 않으므로 z 값은 project_toproject_remain에 의해 변경되지 않는다는 것을 기억하세요. 그러나 project_remain의 경우 결과의 두 부분에서 z 좌표를 복제하고 싶지 않으므로 정확히 하나를 tripoint로 선택해야 합니다. 위의 예에서 z 좌표는 오버맵 규모에서 큰 의미가 없으므로 omt_within_overmap에 z 좌표를 원할 것입니다. 다음과 같이 수행할 수 있습니다:

tripoint_abs_omt abs_pos = get_avatar()->global_omt_location();
point_abs_om overmap;
tripoint_om_omt omt_within_overmap;
std::tie( overmap, omt_within_overmap ) = project_remain<coords::om>( abs_pos );

포인트 재스케일링에 사용 가능한 마지막 작업은 project_combine입니다. 이것은 project_remain의 반대 작업을 수행합니다. 두 번째의 원점이 첫 번째의 규모와 일치하는 두 포인트가 주어지면 단일 값으로 결합할 수 있습니다. 위 논의에서 예상할 수 있듯이 이 중 하나는 tripoint일 수 있지만 둘 다는 아닙니다.

tripoint_abs_omt abs_pos = get_avatar()->global_omt_location();
point_abs_om overmap;
tripoint_om_omt omt_within_overmap;
std::tie( overmap, omt_within_overmap ) = project_remain<coords::om>( abs_pos );
tripoint_abs_omt abs_pos_again = project_combine( overmap, omt_within_overmap );
assert( abs_pos == abs_pos_again );

원점 변경

project_remainproject_combine은 일부 원점 변경을 용이하게 하지만 재스케일링과 특별히 관련된 원점만 해당합니다. 로컬 또는 차량 좌표로 또는 로컬 또는 차량 좌표에서 변환하려면 특정 map 또는 vehicle 오브젝트가 필요합니다.

TODO: 이것이 구현되면 몇 가지 예제를 작성하세요.

포인트 연산

표준 산술 연산을 오버로드된 연산자로 제공하지만 버그를 방지하기 위해 제한합니다. 예를 들어 대부분의 포인트 타입은 상수로 곱할 수 없지만 rel 원점을 가진 것은 가능합니다("같은 방향으로 절반만큼 멀리"라고 말하는 것이 합리적입니다).

마찬가지로 일반적으로 두 포인트를 더할 수 없지만 그 중 하나가 rel 원점을 가지거나 원시 포인트 타입인 경우 가능합니다.

거리를 계산하기 위해 요구 사항에 따라 다양한 함수를 사용할 수 있습니다: square_dist, trig_dist, rl_dist, manhattan_dist. 기타 관련 유틸리티 함수에는 direction_fromline_to가 있습니다.

같은 타입의 근처 포인트를 반복하려면 closest_points_first를 사용할 수 있습니다.