Équilibrage dynamique des propulseurs d'un vaisseau spatial

14

Les vaisseaux spatiaux dans mon jeu sont conçus pour être construits par les joueurs avec une quantité arbitraire de propulseurs attachés n'importe où avec n'importe quelle rotation. J'ai actuellement du code sale pour faire tourner le vaisseau à un angle donné (accélération et décélération).

Voici un exemple de vaisseau symétrique faisant face au pointage de la ligne rouge, qui doit tourner à gauche.

Navire

Cependant, comme vous pouvez l'imaginer, selon l'endroit où le joueur a placé les propulseurs, des forces linéaires non désirées affectent parfois le navire. Dans ce cas, le navire commence à avancer.

J'élabore sur la possibilité de trouver la poussée maximale qu'un propulseur peut appliquer pour ne provoquer aucune vitesse linéaire. (Dans le cas ci-dessus, ce serait nul car il n'y a rien pour contrer les forces des propulseurs arrière et les avant se tuent).

Ce que j'ai trouvé jusqu'à présent est une formule pour déterminer l '"efficacité de virage", par exemple, la quantité de rotation causée par rapport au mouvement linéaire.

a - vecteur de position au propulseur a b - vecteur de position au propulseur b v1 - force du propulseur a v2 - force du propulseur b

efficientDelta = a.cross (v1) / | v1 | - (a.cross (v1) + b.cross (v2)) / | v1 + v2 |

, essentiellement "a.cross (v1 * t) / | v1 |" est censé être l'efficacité du tour. Et puis nous le soustrayons par l'efficacité de rotation des propulseurs combinés, pour voir si le tir du nouveau propulseur en vaut la peine.

Un problème survient lorsque je me rends compte que les propulseurs ne sont pas censés être allumés / éteints, mais peuvent varier leur poussée de 0 à 1. Et comment s'y prendre lorsque le joueur veut que le navire aille de l'avant. Bien sûr, il devrait y avoir un équilibre entre la quantité de rotation / déplacement.

Je ne suis pas un spécialiste des fusées, j'espère donc qu'il y aura quelqu'un qui pourra me dire s'il est même possible de calculer l'accélérateur de chaque propulseur de cette façon et de me pousser dans la bonne direction.

Je vous remercie d'avoir pris le temps! / Kim

Kim
la source
3
J'ai commencé sur le même chemin, mais avec de nombreuses configurations, il est impossible de faire pivoter et de ne pas traduire. Alors, enlevez-vous la rotation? Ou autorisez-vous la traduction? En fin de compte, c'est à l'utilisateur de concevoir le navire. Pour ma démonstration de cela, je l'ai truqué. Connexes: gamedev.stackexchange.com/questions/58216/… , gamedev.stackexchange.com/questions/40615/…
MichaelHouse
J'ai emprunté un chemin similaire et j'ai fini par écrire une démo sur cette page . Lorsque vous déplacez les propulseurs (faites-les glisser sur le navire pour définir la position et la puissance), il dessine trois formes. L'intuition est que vous pouvez considérer tous les mouvements possibles comme un point dans l'espace 3D (x, y, rotation), et être limité à 0-1 est une contrainte dans cet espace. Vous vous retrouvez donc avec une forme 3D contenant tous les mouvements possibles. Si vous ne voulez pas de vitesse linéaire, vous regardez la ligne (x = 0, y = 0) dans cet espace (Q, W, E, S tous 0 dans ma démo)
amitp

Réponses:

7

Je suppose que vous avez un mouvement physiquement correct pour votre navire, sinon cette analyse ne tiendra pas. Vous avez besoin de quelque chose de plus fort que l'efficacité pour résoudre correctement ce problème.

Chaque propulseur produira deux effets sur le mouvement du navire: linéaire et angulaire. Ceux-ci peuvent être considérés indépendamment. Si le propulseur produit une force fdans une direction dir, et est décalé du centre de masse par un vecteur r(pas le centre géométrique ou le centre du sprite!), Alors l'effet sur la composante linéaire est:

t = f * dir // f is a scalar, dir is unit length

L'effet sur la vitesse angulaire est donné par le couple:

tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product

test un vecteur de force (c'est-à-dire la poussée linéaire). tauest un scalaire signé qui, divisé par le moment d'inertie de masse, donnera l'accélération angulaire. Il est important que diret rsoient tous deux dans le même espace de coordonnées, c'est-à-dire les deux en coordonnées locales ou les deux en coordonnées mondiales.

L'accélération linéaire globale du navire est donnée par la somme des ts pour chaque propulseur divisée par la masse du navire. De même, l'accélération angulaire n'est que la somme des couples divisés par le moment d'inertie de masse (qui est un autre scalaire). Le navire ne tournera pas si le couple total est nul. De même, il ne bougera pas si la poussée totale est nulle. Le couple de rappel est un scalaire mais une poussée (la somme dest ) est un vecteur 2D.

Le point de cette exposition est que maintenant nous pouvons écrire notre problème comme un programme linéaire . Dites d'abord que nous voulons que notre navire tourne sans bouger . Nous avons une variable pour chaque propulseur, $ x_1, x_2, ... $, qui est la quantité de poussée que le propulseur fournira. Un ensemble de contraintes est:

0 <= x_i < fmax_i  //for each i

fmaxest la force maximale pour ce propulseur (cela nous permet d'avoir des forces plus fortes ou plus faibles). Ensuite, nous disons que les deux égalités:

0 = Sum_i  x_i * dir_i.x
0 = Sum_i  x_i * dir_i.y

Cela encode la contrainte que nous n'appliquerons pas d'accélération linéaire, en disant que la poussée totale est nulle (la poussée est un vecteur, donc nous disons simplement que chaque partie est nulle).

Maintenant, nous voulons que notre navire tourne. Vraisemblablement, nous voulons le faire le plus rapidement possible, nous voulons donc:

max (Sum_i  x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0>

Résoudre pour le x_i tout en satisfaisant les inégalités et les égalités ci-dessus, tout en maximisant la somme ci-dessus, nous donnera la poussée souhaitée. La plupart des langages de programmation ont une bibliothèque LP disponible pour eux. Mettez simplement le problème ci-dessus et cela produira votre réponse.

Un problème similaire nous permettra d'avancer sans tourner. Supposons que nous réécrivions notre problème dans un système de coordonnées dans lequel nous voulons nous déplacer dans la direction x positive. Alors les contraintes sont:

0 <= x_i < fmax_i  //for each i
max Sum_i  x_i * dir_i.x
0 = Sum_i  x_i * dir_i.y
0 = (Sum_i  x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0> // as before

Avec la contrainte que les propulseurs ne peuvent produire une poussée que dans une seule direction, il y aura des limites au type de rotations et de vitesses linéaires que vous pourrez réaliser. Cela se manifestera lorsque la solution sera0 = x_1 = x_2 = ... = x_n , ce qui signifie que vous n'irez nulle part. Pour atténuer cela, je suggère d'ajouter une paire de petits propulseurs faibles (disons 5% ou 10%) pour chaque joueur placé à 45 degrés de chaque côté. Cela donnera à la solution plus de flexibilité, car ceux-ci peuvent être utilisés pour contrer les effets secondaires faibles des propulseurs principaux.

Enfin, pour jusqu'à 100 propulseurs, la solution au LP est suffisamment rapide pour être effectuée par image. Cependant, comme la solution ne dépend pas de l'emplacement ou de l'état actuel, vous pouvez précalculer la solution pour chaque combinaison d'entrée de contrôleur raisonnable chaque fois que la forme change (cela inclut l'ajout de non-propulseurs qui modifient le moment d'inertie ou la masse du navire, car alors les propulseurs sont dans un emplacement différent par rapport au centre de masse!). C'est 24 possibilités (soit 8 directions fois {rotation gauche, pas de rotation, rotation droite}).


la source
Très bien expliqué!
Kim
1
Que Sum_isignifie dans ce contexte?
S. Tarık Çetin
1

Ma première pensée a été une solution purement empirique, c'est-à-dire simuler la plate-forme dans un environnement de bac à sable pour divers degrés de poussée afin de déterminer comment elle se comporte. Au lieu d'équilibrer beaucoup de mathématiques complexes dans la recherche d'une solution déterministe, vous pouvez l'atteindre numériquement, par exemple en utilisant la méthode de newtons. Exemple:

La plage de poussée est de 0 à 1000, où 1000 est ALOT.

Étape 1

Simulez avec confiance (0 + 1000) / 2 = 500. Résultat: trop de confiance

Étape 2

La plage est désormais de 0 à 500 Simuler avec confiance (0 + 500) / 2 = 250. Résultat: trop de confiance

Étape 3

La plage est désormais de 0 à 250 Simuler avec confiance (0 + 250) / 2 = 125 Résultat: trop peu de confiance

Étape 4

La plage est désormais de 125 à 250 Simuler avec confiance (125 + 250) /2=187.5 Résultat trop de confiance

Étape # 5 plage est désormais de 125 à 187,5 Simuler avec confiance (125 + 187,5) /2=156.25 Le résultat est une confiance trop faible

Étape # 6 plage est maintenant de 156,25 à 187,5 La plage est inférieure au seuil de 35, ce qui signifie qu'il s'agit d'une estimation suffisamment bonne

Résultat final = (187,5 + 156,25) / 2 = 171,875

Lennart Rolland
la source