一般的な単純化は、3Dを2Dに折りたたむことです。レンダリングと物理は真に3Dである場合でも、意思決定ロジックは3つの軸すべてを同等に扱う必要はありません。MotoGPトラックには丘が少ないため、AIはyコンポーネントを無視できました。
次に、x / zデカルト座標からトラック相対システムに切り替えました。位置は、次の2つの値で表されました。
int距離= 16.16固定小数点形式で保存された、トラックの周囲の距離
- 0 =開始行
- 0x8000 =中間点
- 0x10000 =最初にループバック
- 0x1C000 = 2周目の4分の3
フロートクロス=トラックを横切る距離0 =中心線上
- -1 =レーシングサーフェスの左端
- 1 =レーシングサーフェスの右端
これと、物理コードおよびレンダリングコードで使用されるデカルト座標を変換するために、レーシングサーフェスの形状を定義するセグメントのリストを保存しました。struct TrackSegment {Vector CenterPoint; float DistanceToLeftEdge; float DistanceToRightEdge; }
元々トラックが作成されたベジェ曲線をテッセレーションすることにより、トラックの周りに等間隔に配置されたこれらの構造を数百作成しました。これにより、必要な座標変換関数を記述するのに十分な情報が得られました。
トラック相対座標を使用すると、多くの便利な計算が簡単になります。
if (abs(cross) > 1)
// You are off the track and should steer back toward the center line
if (this.distance > other.distance)
// You are ahead of the other player (even though you may be
// physically behind in 3D space if you have lapped them)
short difference = (short)(this.distance - other.distance);
if (abs(difference) < threshold)
// These two bikes are physically close together,
// so we should run obstacle avoidance checks
固定小数点データ形式のため、距離カウンターを32ビットから16ビットにキャストすることは、ラップ数を破棄する簡単な方法でした。そのため、2つのバイクが異なるラップにある場合、どちらの計算が適切かを知りたいのではなく、どの計算を選択するかを選択できました。物理的な空間で接近していた。2の賛辞の魔法のおかげで、違いを符号付き16ビットとして扱うと、どちらの自転車が前にあるかに関係なく、最短距離が得られます(ループレーストラックなどのモジュロ演算システムでは、2つの可能な距離があることに注意してください。トラックのいずれかの方向)。これは、2台のバイクがスタートラインの反対側にある場合でも機能します。この状況では、他のほとんどの座標系でエラーが発生しやすい特殊なケースのロジックが必要になります。
この仮想ゲームプレイ領域を平らにしてまっすぐにすることで、「私はレーシングラインにいますか?」または「私はこの他の自転車の後ろに速く来ています。左または右に追い越すための余地はありますか?」これは、完全な3Dワールド空間に実装するのが難しいでしょう。左側を通過することを決定したら、結果のトラック相対座標をワールド空間に変換します。その時点でトラックの曲率が考慮され、選択した目標を達成するためにどのように操縦すべきかを示します。