ポイント、トライポイント、および座標システム

本ゲームは三次元であり、軸は以下のように設定されています:

  • x軸 ディスプレイ上を左から右へ進む方向(非アイソメトリックビューの場合)。
  • y軸 ディスプレイ上を上から下へ進む方向。
  • z軸 垂直方向で、負のzは地下を指し、正のzは上空を指します。

座標システム

CDDAでは、様々な目的のために多様な座標システムが使用されています。これらはスケールと原点が異なります。

最も精度の高い座標はマップマス (ms) 座標です。これらは、通常ゲームをプレイする際に見るタイルを指します。

マップマス座標には2種類の一般的な原点があります:

  • 絶対座標 グローバルとも呼ばれ、固定された原点に対するゲーム全体にわたるグローバルシステムです。
  • ローカル座標 現在の「現実バブル」またはアバターを中心とした大まかな map の角を基準とする座標です。ローカルマップマス座標では、 xy 値 値は共に範囲[0, MAPSIZE_X)に収まります。

次のスケールはサブマップ submap (sm) 座標です。1つのサブマップは 12x12 (SEEXxSEEY)のマップマスです。サブマップは、現実バブルに出入りする際に、マップのチャンクがロードまたはセーブされる際のスケールです。

その次はオーバーマップ地形 overmap terrain (omt) 座標です。1つのオーバーマップ地形は 2x2 のサブマップです。オーバーマップ地形は、ゲーム内のマップビューで単一のタイルに対応し、マップ生成処理のチャンクのスケールです。

最も大きいのはオーバーマップ overmap (om) 座標です。1つのオーバーマップは180x180 (OMAPXxOMAPY) のオーバーマップ地形です。大規模なマップ生成処理(例:都市のレイアウト)は、オーバーマップ単位で行われます。

最後に、セグメント segment (seg) と呼ばれるシステムがあります。これらはサブマップのセーブ/ロードでのみ使用され、あなたが遭遇する可能性は低いです。

絶対座標とローカル座標に加えて、より大きなスケールに対する相対座標を使用する必要がある場合もあります。例えば、単一のオーバーマップに対してマップ生成処理を行う場合、そのオーバーマップ内の座標で作業したいと考えます。これは、それを含むオーバーマップの角を基準としたオーバーマップ地形スケールのポイントとなり、通常 (0,180)の範囲の x 値と y 値を持ちます。

垂直座標

x 座標と y 座標はこれら全てのスケールで機能しますが、z 座標は全てのコンテキストで一貫しています。これらは範囲 [-OVERMAP_DEPTH,OVERMAP_HEIGHT]内に存在します。

乗り物座標

各乗り物 には独自の原点があり、それは乗り物の特定の部位に配置されます(例:運転席にあるかもしれません)。乗り物が損傷し、その位置にある全ての車両パーツが破壊された場合、原点は移動する可能性があります。

乗り物は、その原点に対する相対的な2つの座標システムを使用します:

  • マウント 座標: 乗り物が移動しても変化しない車両パーツの位置を提供します。これは、乗り物が真東を向いているとき、そのパーツが車両原点に対して持つマップマスです。

  • マップマス : 原点に対するマップマスですが、乗り物の現在の向きを考慮に入れます。

乗り物の向きは、四分の一回転(クォーターターン)と、四分の一回転間の補間を行うためのシアリング(shearing)の組み合わせによって実装されます。乗り物のマウント座標とマップマス座標間で変換を行うロジックは複雑であり、 vehicle::coord_translate() および vehicle::mount_to_tripoint() 系の関数によって処理されます。

現在、乗り物のマウント座標にはzレベルの要素はありませんが、乗り物のマップマス座標にはzレベルの要素があります。z座標は車両原点に対して相対的です。

ポイント型

これらの座標システムを扱うために、様々な型が用意されています。これらは coordinates.hで定義されています。例えば、絶対マップマス座標には point_abs_ms があります。この型名は、次元 次元 _ 原点 _ _スケール_の三つの部分から構成されています。

  • dimension 2次元の場合は point 、3次元の場合は tripoint
  • origin 値が何に対する相対値かを示し、以下が可能です:
    • rel 任意の点に対する相対値。これは共通の原点を持つ2つの点を減算した結果です。例えば、アバターと、アバターが射撃しているモンスターとの間のオフセットを表すために使用されます。
    • abs グローバルな絶対座標。
    • sm サブマップの角に対する相対値。
    • omt オーバーマップ地形の角に対する相対値。
    • om オーバーマップの角に対する相対値。
    • veh 乗り物の原点に対する相対値。
  • scale 上記で説明されたスケールを意味します。
    • ms マップマス。
    • sm サブマップ。
    • omt オーバーマップ地形。
    • seg セグメント。
    • om オーバーマップ。
    • mnt 乗り物のマウント座標 (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 を使用すると、より粗い座標システムに変換すると同時に、その粗いポイントに対する剰余をキャプチャできます。これは、結果の2つの部分をキャプチャするために 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 );

これは二次元の 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とは逆の操作を実行します。2つのポイントが与えられ、2番目のポイントの原点が1番目のポイントのスケールと一致する場合、それらを単一の値に結合できます。上記の議論から予想されるように、これら2つのうち一方は 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 原点を持つ型は可能です(「同じ方向に半分の距離」と言うのは理にかなっているため)。

同様に、一般に2つのポイントを足し合わせることはできませんが、一方のポイントが rel 原点を持っている場合、または一方のポイントが生のポイント型である場合は可能です。

距離を計算するために、要件に応じて様々な関数が利用可能です: square_disttrig_distrl_distmanhattan_dist。その他の関連ユーティリティ関数には、 direction_from および line_toが含まれます。

同じ型の近隣のポイントを反復処理するには、closest_points_firstを使用できます。