Programmation d'un changement en douceur de la poussée du vecteur vitesse du courant à un vecteur cible

StackOverflow https://stackoverflow.com/questions/1365415

Question

TL; dr: «Je ne sais pas comment calculer une transition en douceur de la poussée entre un vecteur et une autre »

Je suis la programmation d'un jeu simple où un ennemi pourchasse le joueur dans un espace ouvert (sans murs). Je calculais les vitesses de x et y de l'ennemi indépendamment, en les accélérant si elles les prennent dans la direction du joueur et les ralentir rapidement si elles allaient dans le mauvais sens (par exemple EnemyVelocity.x> 0 & player.x

Alors que le gameplay est décemment amusant d'essayer d'esquiver l'ennemi, il est mon désir d'avoir l'ennemi en utilisant la physique appropriée se comportent. Ce que je fais actuellement est que l'ennemi leur poussée fixé (penser à un vaisseau spatial) en fonction de l'angle entre eux et le joueur, et ont leur poussée à accélérer jusqu'à une vitesse maximale (calcul côté c du triangle de EnemyVelocity). Une fois que cela arrive, je ne suis pas sûr de la meilleure façon d'avoir la poussée se régler. Si je laisse pas la vitesse maximale, l'ennemi accélère bien mais le joueur facilement remise des gaz, puis prendre beaucoup de temps pour obtenir assez d'élan retourner dans la direction du joueur.

Ce que je voudrais arriver est que l'ennemi constamment ajuster leur vitesse sur le chemin au joueur, en ciblant chaque fois qu'ils sont à (je ne veux pas qu'ils prédire où vous). Puis, quand ils ratent le joueur, je voudrais que les mêmes formules de poussée et d'accélération pour réajuster leur vitesse et les renvoyer au lecteur.

Je pense cela implique deux vecteurs: un où l'ennemi est en voyage, et celui où l'ennemi veut voyager (le vecteur qui les emmènera au joueur droite). Je ne sais pas comment calculer une transition en douceur de la poussée entre un vecteur et un autre.

Des conseils, des formules ou questions seront très appréciés! Thank you débordement de la pile.

Était-ce utile?

La solution

Tout revient aux équations de Newton:

F = m * a
s = s_o + v * t + a * t^2 / 2
v = v_o + a * t

Dans ce cas, F est la force (poussée), a est l'accélération, et m est la masse du navire. s est l'emplacement actuel, s_o est l'emplacement d'origine, v est la vitesse, et t est l'heure actuelle.

Bien sûr, cela est le long d'une ligne droite, donc si vous voulez convertir en deux ou trois dimensions, vous devrez faire quelques calculs. F, s, v et a sont tous les vecteurs, ce qui signifie que leur direction est tout aussi important. Techniquement t est aussi un vecteur, mais depuis le temps que nous ne pas va généralement une seule direction, à inquiéter à ce sujet.

2d:
F^2 = F_x^2 + F_y^2 (use Pythagorean theorem to split force into components)
F_x = m * a_x
F_y = m * a_y
s_x = s_o_x + v_x * t + a_x * t^2 / 2
s_y = s_o_y + v_y * t + a_y * t^2 / 2
v_x = v_o_x + a_x * t
v_y = v_o_y + a_y * t

3d:
F^2 = F_x^2 + F_y^2 + F_z^2 (surprisingly, this works)
F_x = m * a_x
F_y = m * a_y
F_z = m * a_z
s_x = s_o_x + v_x * t + a_x * t^2 / 2
s_y = s_o_y + v_y * t + a_y * t^2 / 2
s_z = s_o_z + v_z * t + a_z * t^2 / 2
v_x = v_o_x + a_x * t
v_y = v_o_y + a_y * t
v_z = v_o_z + a_z * t

Maintenant, pour ajuster votre vitesse à la direction du joueur, vous avez une force totale fixe (F) afin de changer la vitesse du courant vers le joueur. Dans la physique des choses ne se produisent pas instantanément, mais votre objectif devrait être de réduire au minimum le temps où le changement se produit ( « t »).

Cela vous donne une équation en termes de votre emplacement actuel ((s_o_x,s_o_y) ou (s_o_x,s_o_y,s_o_z)) et l'emplacement actuel de votre adversaire ou votre emplacement cible ((s_x,s_y) ou (s_x,s_y,s_z)), pour votre vitesse cible (ne tient pas compte d'accélération).

v_x = (s_x - s_o_x) / t
v_y = (s_y - s_o_y) / t

v_x = (s_x - s_o_x) / t
v_y = (s_y - s_o_y) / t
v_z = (s_z - z_o_y) / t

On peut remplacer cela pour notre autre équation:

(s_x - s_o_x) / t = v_o_x + a_x * t
(s_y - s_o_y) / t = v_o_y + a_y * t

(s_x - s_o_x) / t = v_o_x + a_x * t
(s_y - s_o_y) / t = v_o_y + a_y * t
(s_z - z_o_y) / t = v_o_z + a_z * t

Nous avons ensuite résolvons pour l'accélération (cela est lié à la force, ce qui est ce que nous essayons de calculer).

(s_x - s_o_x) / t^2 - v_o_x / t = a_x
(s_y - s_o_y) / t^2 - v_o_y / t = a_y

(s_x - s_o_x) / t^2 - v_o_x / t = a_x
(s_y - s_o_y) / t^2 - v_o_y / t = a_y
(s_z - z_o_y) / t^2 - v_o_z / t = a_z

Brancher ce dans l'équation de force:

F_x = m * (s_x - s_o_x) / t^2 - m * v_o_x / t
F_y = m * (s_y - s_o_y) / t^2 - m * v_o_y / t

F_x = m * (s_x - s_o_x) / t^2 - m * v_o_x / t
F_y = m * (s_y - s_o_y) / t^2 - m * v_o_y / t
F_z = m * (s_z - z_o_y) / t^2 - m * v_o_z / t

pour résoudre t:

t = (-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
t = (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y

t = (-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
t = (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y
t = (-m * v_o_z +/- sqrt(m^2 * v_o_z^2 - 4 * F_z * m * (s_z - s_o_z))) / 2 / F_z

Les temps doivent converger, de sorte que les temps seront égaux! Cela nous donne un système d'équations pour chaque coordonnée (plan et sphère). Notez qu'il existe plusieurs valeurs possibles, mais certains impliquent les nombres imaginaires de sorte que vous devrez éliminer ces solutions:

(-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
= (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y
F^2 = F_x^2 + F_y^2

(-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
= (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y
= (-m * v_o_z +/- sqrt(m^2 * v_o_z^2 - 4 * F_z * m * (s_z - s_o_z))) / 2 / F_z
F^2 = F_x^2 + F_y^2 + F_z^2

résolvez les coordonnées (F_x,F_y) ou (F_x,F_y,F_z) et vous avez la force dont vous avez besoin.

Laissez-moi savoir si vous avez des questions ou si vous trouvez des erreurs dans mes calculs.

Autres conseils

Vous pouvez obtenir l'effet que vous voulez en assurant un changement en douceur dans vitesse , plutôt que poussée . De cette façon, si l'ennemi le joueur dépasse, il peut immédiatement inverser son accélération, ce qui le ralentit et finalement inverser la direction de Voyage.

Vous pouvez accomplir cela en changeant la vitesse lors de chaque itération, par une petite quantité qui est basée sur la distance de l'ennemi au joueur:

while (game_in_progress)
{
    // Distance from enemy to player.  The larger the
    // distance, the greater the acceleration will be.
    delta.x = player.x - enemy.x
    delta.y = player.y - enemy.y

    // Accelerate by changing velocity based on distance,
    // where 'scale' is sufficiently small. (Limit v to
    // some maximum if you choose; likely to be unnecessary.)
    v.x += delta.x * scale
    v.y += delta.y * scale

    // Update the enemy's position.
    enemy.x += v.x
    enemy.y += v.y
}

En calculant les valeurs de x et y indépendamment, vous pouvez vous épargner les maux de tête de traiter avec des vecteurs, des angles et equiations simultanés.

De même, en reconnaissant que l'accélération (poussée) est tout simplement un changement de vitesse, ce qui est un changement de position, vous pouvez créer une simulation à temps discret en utilisant uniquement l'algèbre simple, au lieu de calcul.

Amusez-vous bien!

Vous devez penser en termes de physique appropriés. Vous avez une vitesse, et que vous voulez ajouter une accélération. C'est tout ce qu'il ya à faire -. L'accélération est un changement progressif de la vitesse qui va attirer l'ennemi vers au joueur, lui permettre de remettre les gaz, ralentir (ou tour), puis la tête en arrière vers le joueur

L'accélération est mesurée en tant que d (vitesse) / heure. Vous souhaitez accélérer vers le joueur à tout moment, de sorte que chaque intervalle (seconde, centième de seconde ou tout ce que vous choisissez), vous devez ajouter le vecteur entre l'ennemi et le joueur, multiplié par une constante, à votre vitesse.

Velocity = Velocity + c * (Player-Enemy vector)

constante c dépendra de la vitesse à laquelle vous voulez accélérer vers le joueur, et à quelle fréquence vous mettez à jour votre vitesse.

Si vous voulez « plafond », la vitesse maximale de l'ennemi afin qu'il ne continue pas à augmenter indéfiniment l'ampleur de sa vitesse, vous pouvez le faire.

Velocity = Velocity * (Maximum magniture / |Velocity|)

EDIT: pour clarifier davantage, en ajoutant une vitesse signifie simplement en ajoutant les vecteurs de composantes. Donc,

Vx = Vx + c * Ax
Vy = Vy + c * Ay

où V est la vitesse et A est l'accélération. Magnitude est mesurée comme sqrt(Vx^2 + Vy^2), à savoir l'hypoténuse d'un triangle rectangle. Donc, si vous voulez la vitesse maximale de l'ennemi pour être m,

Vx = Vx * ( m / sqrt(Vx^2 + Vy^2)
Vy = Vy * ( m / sqrt(Vx^2 + Vy^2)

J'ai écrit un simple jeu d'astéroïdes un certain temps qui avait un « allié » navire qui traquer les astéroïdes et tirer sur eux pour vous. Fondamentalement, il a trouvé l'astéroïde le plus proche puis a commencé à tourner en douceur vers elle et aller après. Malheureusement, je n'ai pas le code plus mais si ma mémoire est bonne, je pense que je Tured le navire un peu à chaque tour, alors si l'astéroïde était loin mais si j'ai accéléré, il était proche j'ai essayé de correspondre à la vitesse de l'astéroïde. Il était assez cool en fait, et un minimum de l'algèbre en cause.

La meilleure façon de le faire serait de prendre 2 valeurs radians et lerp entre eux, emballage de manutention. (Peut-être en ajoutant ou soustrayant 2pi le cas échéant). Puis le convertir en un vecteur unitaire. multiplier par la suite que par la vitesse à laquelle vous voulez que le navire pour accélérer, et là vous allez!

Une façon simple (non physique appropriée) est de calculer votre ennemi de « la vitesse désirée », puis ajuster actuellement la vitesse de l'ennemi vers ce, garde tout ce qui limite au-dessus, ou la vitesse minimum, il a.

Par exemple, dans un petit jeu 2d j'ai écrit ( http://wordwarvi.sourceforge.net ) il y a des « missiles à la recherche de chaleur. » Il semble assez bizarre si les missiles arrêtent en plein vol pour tourner autour. Donc, ce que je faisais était la suivante: je calcule une « vitesse désirée » qui est vers le joueur. Ceci est juste fait par des « triangles semblables ». Je trouve la distance au joueur X, et Y, et whichver est plus, je fais le « désiré (x ou y) la vitesse soit le meilleur possible, puis échelle l'autre pour adapter le « triangle similaire. » Note , c'est juste la « vitesse souhaitée », pas la vitesse actuelle. Je prends la vitesse du courant et de l'ajuster lentement (par un peu par image) vers la vitesse « désirée » (bien que la vitesse désirée est recalculé par image et,) mindimg sur les peines minimales Vx et Vy pour les empêcher de s'arrêter à mi-air.

algorithme Dumb, mais il fonctionne bien (personne ne se plaint qu'ils sont trop faciles, trop dur ou trop irréaliste.)

Edit:. En relisant la question, ma réponse est probablement pas ce que vous êtes après

Je l'ai résolu des problèmes comme celui-ci par des professionnels, et je vous conseille de commencer avec des versions simples et progressez. Assurez-vous d'obtenir un comportement attendu à chaque étape avant d'essayer la suivante.

  1. Le demandeur vise une cible fixe à l'origine dans une dimension. C'est vrai, une dimension. Elle peut poussée avant et en arrière sur l'axe des x et il essaie de se rendre à x = 0. Le propulseur n'a pas d'étranglement (comme une fusée solide), mais le demandeur peut pointer dans les deux sens. Si vous programmez ce droit, le demandeur oscillera autour de x = 0, surréaction à chaque fois.
  2. La même, mais la cible est un endroit stationnaire autre que x = 0. Assurez-x relative, pas absolue (qui est, le chercheur se soucie de différence en x, x pas de la cible).
  3. Maintenant, la cible se déplace (ou saut). Le demandeur doit être en mesure de le suivre autour. L'oscillation va augmenter ou diminuer en fonction de la façon dont la cible se déplace - vous verrez ce que je veux dire.
  4. Maintenant deux dimensions. Le chercheur pousse toujours directement vers la cible, ce qui signifie que vous devez diviser la poussée en composantes x et y par TRIG simple. Si vous déplacez la cible, le demandeur peut aller en orbite autour d'elle.
  5. Retour à une dimension et une cible fixe, mais maintenant le chercheur tente un rendez-vous, pas un défilé aérien. C'est la partie difficile. L'objectif est d'avoir la distance et la vitesse deviennent nuls en même temps, sans dépassement, de sorte que le chercheur doit connaître sa propre capacité de freinage. Lorsque x est inférieur à v ^ 2 / 2a, le demandeur doit inverser la poussée, poussée à une distance de la cible dans le but de ralentir et de le relever. Il est agréable de permettre au demandeur d'arrêter fourrant quand il est très proche de la cible.
  6. La cible commence à se déplacer à nouveau. C'est facile; juste faire x et v relative, pas absolue.
  7. De multiples dimensions. Ceci est très facile; x, y et z parties sont indépendantes.

Maintenant, si vous voulez un chercheur qui ne peut pas tourner sur une pièce de dix cents, mais doit courbe autour, les choses se compliquent ...

Il y a juste quelques conseils pour obtenir ce droit et facile. 1) il est plus facile et la plus générale de travailler avec des vecteurs plutôt que d'écrire tout deux ou trois fois. 2) les choses vont regarder à droite si vous contrôlez la force (qui est effectivement l'accélération puisque A = F / masse), puis évoluer de manière dynamique la vitesse et la position.

Votre boucle de base pour le mouvement réaliste ressemble (où ces comités sont des vecteurs et dt est votre timestep):

while (motion) {
   A = get_acceleration(X, V, A, X_target, V_targer, A_target)
   V += A*dt       // V is the integral of A
   X += V*dt       // X is the integral of V
}

Et vraiment, il est question pour vous l'évolution dynamique.

Ensuite, vous devez décider comment déterminer votre accélération, à savoir get_acceleration d'écriture. Il y a un certain nombre d'options ici qui dépendent de facteurs multiples et chasers vie réelle emploient plusieurs stratégies. Par exemple, si vous avez beaucoup de poussée par rapport à votre masse (à savoir une forte accélération) vous voulez probablement juste à la tête de droite à la cible; mais si vous avez beaucoup de masse par rapport à votre poussée que vous voulez sans doute de faire un cours d'interception. Si vous voulez ralentir à l'approche de la cible, vous pouvez inverser l'accélération quand |X-X_target| devient petit (à savoir qu'ils se rapprocher) et / ou leurs vitesses sont proches. En outre, l'amortissement peut aider les choses oscillent pas, et pour cela, ajoutez un terme à quelque chose d'accélération comme -c*(V-V_target). Je vous suggère de jouer avec ces jusqu'à ce que vous obtenez quelque chose qui correspond à l'aspect physique et le sentiment que vous visez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top