Una simplificación común es colapsar 3D en 2D. Aunque el renderizado y la física pueden ser realmente 3D, la lógica de toma de decisiones no necesita tratar los tres ejes por igual. Las pistas de MotoGP tienen pocas colinas, por lo que nuestra IA pudo ignorar el componente y.
A continuación, cambiamos de coordenadas cartesianas x / z a un sistema relativo a la pista. Las posiciones fueron representadas por un par de valores:
distancia int = qué tan lejos alrededor de la pista, almacenada en formato de punto fijo 16.16
- 0 = línea de inicio
- 0x8000 = a mitad de camino
- 0x10000 = regresado al inicio
- 0x1C000 = tres cuartos del camino a través de la segunda vuelta
cruz flotante = qué tan lejos de lado a través de la pista 0 = en la línea central
- -1 = borde izquierdo de la superficie de carrera
- 1 = borde derecho de la superficie de carrera
Para convertir entre esto y las coordenadas cartesianas utilizadas por nuestro código de representación y física, almacenamos una lista de segmentos que definen la forma de la superficie de carrera: struct TrackSegment {Vector CenterPoint; flotante DistanceToLeftEdge; flotante DistanceToRightEdge; }
Creamos varios cientos de estas estructuras, espaciadas uniformemente alrededor de la pista, al teselar las curvas de Bezier a partir de las cuales se crearon originalmente las pistas. Esto nos dio suficiente información para escribir las funciones de conversión de coordenadas necesarias.
Con las coordenadas relativas a la pista, muchos cálculos útiles se vuelven trivialmente simples:
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
Debido al formato de datos de punto fijo, convertir el contador de distancia de 32 a 16 bits era una manera fácil de descartar el número de vuelta, para que pudiéramos elegir qué cálculos importarían si dos bicicletas estuvieran en vueltas diferentes, en lugar de querer saber si estaban cerca en el espacio físico. Gracias a la magia del cumplido de dos, tratar la diferencia como 16 bits con signo proporciona la distancia más corta, independientemente de la bicicleta que esté al frente (recuerde que en un sistema aritmético de módulo, como una pista de carreras en bucle, hay dos distancias posibles, como puede medir en cualquier dirección alrededor de la pista). Esto funciona incluso cuando las dos bicicletas están en lados opuestos de la línea de partida, una situación que requeriría una lógica de caso especial propensa a errores en la mayoría de los otros sistemas de coordenadas.
Al aplanar y enderezar esta área de juego virtual, fue fácil razonar sobre cosas como "¿estoy en la línea de carreras?" o "Estoy subiendo rápido detrás de esta otra bicicleta: ¿tengo más espacio para pasarlos a la izquierda o la derecha?" que habría sido difícil de implementar en un espacio mundial en 3D completo. Una vez que decidimos pasar por la izquierda, convertiríamos la coordenada relativa a la pista resultante nuevamente en el espacio mundial, en ese punto la curvatura de la pista se tiene en cuenta, mostrando cómo debemos dirigirnos para lograr nuestro objetivo elegido.