포인트, 트라이포인트 및 좌표 시스템
축
게임은 3차원이며 축은 다음과 같이 정렬됩니다:
- x축은 디스플레이에서 왼쪽에서 오른쪽으로 이동합니다(비등각 뷰에서).
- y축은 디스플레이의 위에서 아래로 이동합니다.
- z축은 수직이며, 음수 z는 지하를, 양수 z는 하늘을 가리킵니다.
좌표 시스템
CDDA는 다양한 목적을 위해 여러 좌표 시스템을 사용합니다. 이들은 규모와 원점에 따라 다릅니다.
가장 정밀한 좌표는 맵 스퀘어(ms) 좌표입니다. 이것은 게임을 플레이할 때 일반적으로 보는 타일을 나타냅니다.
맵 스퀘어 좌표의 두 가지 일반적인 원점:
- 절대 좌표(때로는 글로벌이라고도 함)는 고정된 원점을 기준으로 하는 전체 게임의 글로벌 시스템입니다.
- 로컬 좌표는 현재 "현실 버블" 또는 아바타를 중심으로 하는
map의 모서리를 기준으로 합니다. 로컬 맵 스퀘어 좌표에서x및y값은 모두[0, MAPSIZE_X)범위에 속합니다.
다음 규모는 서브맵(sm) 좌표입니다. 하나의 서브맵은 12x12(SEEXxSEEY) 맵 스퀘어입니다. 서브맵은 맵의 청크가 현실 버블에 들어가거나 나갈 때 로드되거나 저장되는 규모입니다.
다음은 오버맵 터레인(omt) 좌표입니다. 하나의 오버맵 터레인은 2x2 서브맵입니다. 오버맵 터레인은 게임 내 맵 뷰의 단일 타일에 해당하며 맵젠의 청크 규모입니다.
가장 큰 것은 오버맵(om) 좌표입니다. 하나의 오버맵은 180x180(OMAPXxOMAPY) 오버맵 터레인입니다. 대규모 맵젠(예: 도시 레이아웃)은 한 번에 하나의 오버맵에서 발생합니다.
마지막으로 세그먼트(seg) 좌표라는 시스템이 있습니다. 이것은 서브맵 저장/로드에만 사용되며 마주칠 가능성이 낮습니다.
절대 및 로컬 좌표 외에도 때때로 더 큰 규모에 상대적인 좌표를 사용해야 합니다. 예를 들어 단일 오버맵에 대한 맵젠을 수행할 때 해당 오버맵 내의 좌표로 작업하려고 합니다. 이것은 포함하는 오버맵의 모서리를 기준으로 하는 오버맵 터레인 규모 포인트이므로 일반적으로 [0,180) 범위의 x 및 y 값을 취합니다.
수직 좌표
x 및 y 좌표는 이러한 다양한 규모에서 작동하지만 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는 차량 원점을 기준으로 한다는 의미입니다.
- 규모는 위에서 논의한 규모를 의미합니다.
msfor 맵 스퀘어.smfor 서브맵.omtfor 오버맵 터레인.segfor 세그먼트.omfor 오버맵.mntfor 차량 마운트 좌표(veh원점에만 관련).
원시 포인트 타입
타입에 인코딩된 원점과 규모를 가진 이러한 타입 외에도 point 및 tripoint라는 간단한 원시 포인트 타입이 있습니다. 이들은 특정 게임 규모가 의도되지 않은 경우에 사용할 수 있습니다.
작성 시점에서 우리는 여전히 이러한 원시 포인트 타입을 어디서나 사용하는 것에서 코드베이스를 전환하는 과정에 있으므로, 더 타입 안전한 포인트가 적절해 보이는 곳에서 이들을 사용하는 레거시 코드를 볼 가능성이 높습니다.
새 코드는 가능한 경우 좌표 시스템을 포함하는 타입을 사용하는 것을 선호해야 합니다.
포인트 타입 간 변환
규모 변경
원점을 변경하지 않고 포인트의 규모를 변경하려면 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_to 및 project_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_remain 및 project_combine은 일부 원점 변경을 용이하게 하지만 재스케일링과 특별히 관련된 원점만 해당합니다. 로컬 또는 차량 좌표로 또는 로컬 또는 차량 좌표에서 변환하려면 특정 map 또는 vehicle 오브젝트가 필요합니다.
TODO: 이것이 구현되면 몇 가지 예제를 작성하세요.
포인트 연산
표준 산술 연산을 오버로드된 연산자로 제공하지만 버그를 방지하기 위해 제한합니다. 예를 들어 대부분의 포인트 타입은 상수로 곱할 수 없지만 rel 원점을 가진 것은 가능합니다("같은 방향으로 절반만큼 멀리"라고 말하는 것이 합리적입니다).
마찬가지로 일반적으로 두 포인트를 더할 수 없지만 그 중 하나가 rel 원점을 가지거나 원시 포인트 타입인 경우 가능합니다.
거리를 계산하기 위해 요구 사항에 따라 다양한 함수를 사용할 수 있습니다: square_dist, trig_dist, rl_dist, manhattan_dist. 기타 관련 유틸리티 함수에는 direction_from 및 line_to가 있습니다.
같은 타입의 근처 포인트를 반복하려면 closest_points_first를 사용할 수 있습니다.