31 votes

Mouvement simple basé sur la physique

Je suis en train de travailler sur un jeu en 2D où j'essaie d'accélérer un objet à une vitesse de pointe à l'aide de certains de la physique de base de code.

Voici le pseudo-code correspondant:


const float acceleration = 0.02f;
const float friction     = 0.8f;  // value is always 0.0..1.0
      float velocity     = 0;
      float position     = 0;

move()
{
   velocity += acceleration;
   velocity *= friction;
   position += velocity;
}

C'est une approche très simplifiée qui ne repose pas sur la masse réelle ou friction (le code de frottement est juste un générique de la force agissant à l'encontre de mouvement). Il fonctionne bien comme la "vitesse *= frottement;" la partie continue de la vitesse d'aller au-delà d'un certain point. Cependant, c'est cette vitesse de pointe et sa relation à l'accélération et à la friction où je suis un peu perdu.

Ce que je voudrais faire est de définir une vitesse supérieure, et la quantité de temps qu'il faut pour l'atteindre, puis de les utiliser pour dériver l'accélération et les valeurs de frottement.

c'est à dire,


const float max_velocity = 2.0; 
const int   ticks;       = 120; // If my game runs at 60 FPS, I'd like a 
                                // moving object to reach max_velocity in 
                                // exactly 2 seconds.
const float acceleration = ?
const float friction     = ?

40voto

gnovice Points 70970

DE LOURDES MODIFICATIONS

Je trouve cette question très intéressante car j'ai récemment fait un peu de travail sur la modélisation de projectile de mouvement avec la drague.

Point 1: Vous êtes essentiellement la mise à jour de la position et de la vitesse à l'aide de l' explicite vers l'avant/Euler itération chaque nouvelle valeur pour les etats doivent être en fonction des valeurs anciennes. Dans un tel cas, vous devriez faire la mise à jour de la position de la première, puis la mise à jour de la vitesse.

Point 2: Il y a de plus réaliste des modèles de la physique de l'effet de la traînée de frottement. Un modèle (suggéré par Adam Liss) implique une force de traînée est proportionnelle à la vitesse (connu sous le nom de Stokes' glisser, qui s'applique généralement à une faible vitesse de situations). Celui que j'ai déjà proposé implique une force de traînée est proportionnelle au carré de la vitesse (connu sous le nom quadratique glisser, qui s'applique généralement à haute vitesse situations). Je vais répondre à chacun à l'égard de la façon dont vous déduire des formules pour la vitesse maximale et le temps nécessaire pour atteindre efficacement la vitesse maximale. Je vais renoncer à la complète dérivations, car ils sont plutôt impliqués.


Stokes a glisser:

L'équation de mise à jour de la vitesse:

velocity += acceleration - friction*velocity

qui représente l'équation différentielle suivante:

dv/dt = a - f*v

À l'aide de la première entrée dans cette intégrale de la table, nous pouvons trouver la solution (en supposant que v = 0 à t = 0):

v = (a/f) - (a/f)*exp(-f*t)

Le maximum (c-terminal) de vitesse se produit lorsque t >> 0, de sorte que le second terme de l'équation est très proche de zéro et:

v_max = a/f

Concernant le temps nécessaire pour atteindre la vitesse maximale, remarque que l'équation jamais vraiment atteint, mais au lieu asymptotes vers elle. Toutefois, si l'argument de l'exponentielle est égale à -5, la vitesse est de l'ordre de 98% de la vitesse maximale, sans doute assez proches de la considérer l'égalité. Vous pouvez ensuite approximative du temps maximum de vitesse:

t_max = 5/f

Vous pouvez ensuite utiliser ces deux équations à résoudre pour f et un donné un souhaité vmax et tmax.


Quadratique glisser:

L'équation de mise à jour de la vitesse:

velocity += acceleration - friction*velocity*velocity

qui représente l'équation différentielle suivante:

dv/dt = a - f*v^2

À l'aide de la première entrée dans cette intégrale de la table, nous pouvons trouver la solution (en supposant que v = 0 à t = 0):

v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)

Le maximum (c-terminal) de vitesse se produit lorsque t >> 0, de sorte que l'exponentielle termes sont beaucoup plus grand que 1 et l'équation approches:

v_max = sqrt(a/f)

Concernant le temps nécessaire pour atteindre la vitesse maximale, remarque que l'équation jamais vraiment atteint, mais au lieu asymptotes vers elle. Toutefois, si l'argument de l'exponentielle est égale à 5, la vitesse est d'environ 99% de la vitesse maximale, sans doute assez proches de la considérer l'égalité. Vous pouvez ensuite approximative du temps maximum de vitesse:

t_max = 2.5/sqrt(a*f)

ce qui est aussi équivalent à:

t_max = 2.5/(f*v_max)

Un vmax et tmax, la deuxième équation pour tmax vous dira que f doit être, et alors que vous pouvez brancher que dans l'équation de vmax pour obtenir la valeur de un.


Cela me semble un peu exagérer, mais ce sont en fait certains des façons les plus simples de modèle de glisser! N'importe qui qui vraiment veut voir les étapes d'intégration peut tirer sur moi un email et je vais vous les envoyer. Ils sont un peu trop impliqué de type ici.

Un autre Point: je n'ai pas tout de suite compte, mais la mise à jour de la vitesse n'est plus nécessaire si vous utilisez les formules que je dérivée de v(t). Si vous êtes tout simplement la modélisation de l'accélération de repos, et vous gardez une trace du temps depuis l'accélération a commencé, le code devrait ressembler à quelque chose comme:

position += velocity_function(timeSinceStart)

où "velocity_function" est l'une des deux formules pour v(t) et vous n'avez plus besoin d'une vitesse variable. En général, il y a un compromis à faire ici: le calcul de v(t) peut être plus gourmand en ressources que de simplement la mise à jour de vitesse à l'aide d'un schéma itératif (en raison de la croissance exponentielle des termes), mais il est garanti de rester stable et limité. Sous certaines conditions (par exemple en essayant d'obtenir un très court tmax), l'itération peut devenir instable et blow-up, un problème courant avec les avant d'Euler la méthode. Toutefois, le maintien de limites sur les variables (tels que 0 < f < 1), doit empêcher ces instabilités.

En outre, si vous vous sentez quelque peu masochiste, vous pouvez être en mesure d'intégrer la formule de v(t) pour obtenir une solution de la forme finie pour p(t), ce qui précède, la nécessité d'une itération de Newton tout à fait. Je vais vous laisser pour les autres de s'y essayer. =)

3voto

Adam Liss Points 27815

Avertissement: Solution Partielle

Si nous suivons la physique, comme indiqué, il n'est pas de la vitesse maximale. À partir d'un point de vue purement physique, vous avez fixé l'accélération à une valeur constante, ce qui signifie que la vitesse est toujours en augmentation.

Comme une alternative, considérons les deux forces qui agissent sur votre objet:

  • La constante de force externe, F, qui tend à l'accélérer, et
  • La force de traînée, d, qui est proportionnelle à la vitesse et tend à ralentir.

Donc la vitesse à l'itération n devient: vn = v0 + n F - dvn-1

Vous avez demandé de choisir la vitesse maximale, vnmax, qui se produit à l'itération nmax.

Notez que le problème est sous-contraint, c'est, F et d sont liés, de sorte que vous pouvez choisir arbitrairement une valeur pour l'un d'entre eux, puis de calculer l'autre.

Maintenant que le ballon roule, quelqu'un est-il prêt à ramasser les mathématiques?

Avertissement: il est moche et implique de puissance de la série!


Edit: Pourquoi doe la séquence de n**F** dans la première équation semble littéralement, sauf si il y a un espace après l' n?

2voto

GoatRider Points 838

Cela ne répond pas à votre question, mais une chose que vous ne devriez pas faire dans des simulations comme celle-ci est de dépendre d'une fréquence d'images fixe. Calculez le temps écoulé depuis la dernière mise à jour et utilisez le delta-T dans vos équations. Quelque chose comme:

 static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();
 

Il est également bon de vérifier si vous perdez le focus et arrêtez la mise à jour, et lorsque vous obtenez le focus, définissez lastUpdate sur 0. De cette façon, vous n'obtenez pas un énorme deltaT à traiter lorsque vous revenez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X