Uma simplificação comum é recolher o 3D em 2D. Embora a renderização e a física possam ser verdadeiramente 3D, a lógica da tomada de decisão não precisa tratar os três eixos igualmente. As trilhas de MotoGP têm poucas colinas, então nossa IA foi capaz de ignorar o componente y.
Em seguida, passamos de coordenadas cartesianas x / z para um sistema relativo a trilhas. As posições foram representadas por um par de valores:
int distance = a que distância da pista é armazenada no formato de ponto fixo 16.16
- 0 = linha de partida
- 0x8000 = meio caminho andado
- 0x10000 = volta ao início
- 0x1C000 = três quartos da segunda volta
float cross = a que distância lateral da pista 0 = na linha central
- -1 = borda esquerda da superfície de corrida
- 1 = borda direita da superfície de corrida
Para converter entre isso e as coordenadas cartesianas usadas por nosso código físico e de renderização, armazenamos uma lista de segmentos que definem a forma da superfície de corrida: struct TrackSegment {Vector CenterPoint; float DistanceToLeftEdge; flutuar DistanceToRightEdge; }
Criamos várias centenas dessas estruturas, espaçadas uniformemente ao redor da pista, classificando as curvas de Bezier a partir das quais as faixas foram originalmente criadas. Isso nos deu informações suficientes para escrever as funções necessárias de conversão de coordenadas.
Com as coordenadas relativas à faixa, muitos cálculos úteis se tornam 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
Devido ao formato de dados do ponto fixo, converter o contador de distância de 32 a 16 bits era uma maneira fácil de descartar o número da volta, para que pudéssemos escolher quais cálculos se importariam se duas bicicletas estivessem em voltas diferentes, em vez de querer saber se elas estavam perto no espaço físico. Graças à magia do elogio de dois, tratar a diferença como 16 bits assinada oferece a menor distância, independentemente da bicicleta à frente (lembre-se de que em um sistema aritmético modular, como uma pista de corrida em loop, existem duas distâncias possíveis, como você pode medir em qualquer direção ao redor da pista). Isso funciona mesmo quando as duas bicicletas estão em lados opostos da linha de partida, uma situação que exigiria lógica de caso especial propensa a erros na maioria dos outros sistemas de coordenadas.
Achatar e endireitar esta área de jogo virtual facilitou o raciocínio sobre coisas como "estou na linha de corrida?" ou "Estou chegando rápido atrás dessa outra bicicleta: tenho mais espaço para passá-las à esquerda ou à direita?" o que seria difícil de implementar em um espaço mundial em 3D completo. Uma vez que decidimos passar à esquerda, converteríamos a coordenada relativa à trilha resultante de volta ao espaço do mundo, momento em que a curvatura da trilha é levada em consideração, mostrando como devemos orientar para alcançar nosso objetivo escolhido.