Ajout de virages réalistes
L'étape suivante consiste à ajouter des virages incurvés réalistes à nos unités, afin qu'elles ne semblent pas changer brusquement de direction à chaque fois qu'elles doivent tourner. Une solution simple consiste à utiliser une spline pour lisser les virages abrupts en virages. Bien que cela résout certaines des préoccupations esthétiques, il en résulte toujours un mouvement physiquement très irréaliste pour la plupart des unités. Par exemple, cela pourrait transformer une courbe brusque d'un réservoir en une courbe serrée, mais le virage incurvé serait toujours beaucoup plus serré que le réservoir ne pourrait réellement le faire.
Pour une meilleure solution, la première chose que nous devons savoir est le rayon de braquage de notre unité. Le rayon de braquage est un concept assez simple: si vous êtes dans un grand parking dans votre voiture, et tournez la roue vers la gauche aussi loin que possible et continuez à rouler en cercle, le rayon de ce cercle est votre virage rayon. Le rayon de braquage d'une Volkswagen Beetle sera sensiblement plus petit que celui d'un gros SUV, et le rayon de braquage d'une personne sera sensiblement inférieur à celui d'un gros ours lourd.
Disons que vous êtes à un certain point (origine) et pointé dans une certaine direction, et vous devez vous rendre à un autre point (destination), comme illustré dans la figure 5. Le chemin le plus court se trouve soit en tournant à gauche aussi loin que vous peut, en faisant un cercle jusqu'à ce que vous soyez directement pointé vers la destination, puis en avançant, ou en tournant à droite et en faisant la même chose.
Sur la figure 5, l'itinéraire le plus court est clairement la ligne verte en bas. Ce chemin se révèle assez simple à calculer en raison de certaines relations géométriques, illustrées à la figure 6.
Nous calculons d'abord l'emplacement du point P, qui est le centre de notre cercle de braquage, et est toujours à un rayon r du point de départ. Si nous tournons à droite de notre direction initiale, cela signifie que P est à un angle de (direction_initiale - 90) par rapport à l'origine, donc:
angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)
Maintenant que nous connaissons l'emplacement du point central P, nous pouvons calculer la distance de P à la destination, indiquée par h sur le diagramme:
dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)
À ce stade, nous voulons également vérifier que la destination ne se trouve pas dans le cercle, car si elle l'était, nous ne pourrions jamais l'atteindre:
if (h < r)
return false
Nous pouvons maintenant calculer la longueur du segment d, car nous connaissons déjà les longueurs des deux autres côtés du triangle rectangle, à savoir h et r. Nous pouvons également déterminer l'angle à partir de la relation triangle-droite:
d = sqrt(h*h - r*r)
theta = arccos(r / h)
Enfin, pour déterminer le point Q auquel quitter le cercle et commencer sur la ligne droite, nous devons connaître l'angle total +, et est facilement déterminé comme l'angle de P à la destination:
phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)
Les calculs ci-dessus représentent la trajectoire de virage à droite. Le chemin de gauche peut être calculé exactement de la même manière, sauf que nous ajoutons 90 à initial_direction pour calculer angleToP, et plus tard nous utilisons - au lieu de +. Après avoir calculé les deux, nous voyons simplement quel chemin est le plus court et utilisons celui-ci.
Dans notre implémentation de cet algorithme et de ceux qui suivent, nous utilisons une structure de données qui stocke jusqu'à quatre «segments de ligne» distincts, chacun étant soit droit soit courbe. Pour les trajectoires courbes décrites ici, il n'y a que deux segments utilisés: un arc suivi d'une ligne droite. La structure de données contient des membres qui spécifient si le segment est un arc ou une ligne droite, la longueur du segment et sa position de départ. Si le segment est une ligne droite, la structure de données spécifie également l'angle; pour les arcs, il spécifie le centre du cercle, l'angle de départ sur le cercle et le total des radians couverts par l'arc.
Une fois que nous avons calculé le chemin incurvé nécessaire pour se rendre entre deux points, nous pouvons facilement calculer notre position et notre direction à tout instant donné, comme le montre le listing 2.
LISTE 2. Calcul de la position et de l'orientation à un moment donné.
distance = unit_speed * elapsed_time
loop i = 0 to 3:
if (distance < LineSegment[i].length)
// Unit is somewhere on this line segment
if LineSegment[i] is an arc
//determine current angle on arc (theta) by adding or
//subtracting (distance / r) to the starting angle
//depending on whether turning to the left or right
position.x = LineSegment[i].center.x + r*cos(theta)
position.y = LineSegment[i].center.y + r*sin(theta)
//determine current direction (direction) by adding or
//subtracting 90 to theta, depending on left/right
else
position.x = LineSegment[i].start.x
+ distance * cos(LineSegment[i].line_angle)
position.y = LineSegment[i].start.y
+ distance * sin(LineSegment[i].line_angle)
direction = theta
break out of loop
else
distance = distance - LineSegment[i].length