Forum Clubic

[Math] Déplacement en 2D - Algo pour se déplacer dans un plan

Bonne fête ^^

J’ai fais un algo qui me permet de bouger des sprites sur l’écran, il fonctionne mais pas correctement : si le déplacement est horizontal ou vertical, pas de problème, par contre en oblique, le déplacement ne se fait pas à la bonne vitesse (il est plus lent)

voici comment je m’y prends


            ' distance à parcourir en metre
            distanceX = Absolue( Destination.X - _Position.X)
            distanceY = Absolue( Destination.Y - Position.Y)

            ' correction de la vitesse dans le cas ou la distance à parcourir est plus petite que la vitesse
            cSpeed = _Speed
            If (distanceX + distanceY) < _Speed Then
                cSpeed = _Speed - (distanceX + distanceY)
            End If

            ' On répartit la vitesse en mouvement vers les X et vers les Y :
            ' Plus la distance à parcourir est grande pour un axe par rapport à l'autre, plus cet axe obtiendra de points de vitesse
            pourcentX = distanceX / (distanceX + distanceY)
            pourcentY = distanceY / (distanceX + distanceY)
            mouvementX = Arrondi(pourcentX * cSpeed))
            mouvementY = Arrondir(pourcentY * cSpeed))

            ' Si l'on se deplace vers le haut ou vers la gauche, on remonte les axes, donc * -1
            signeX = 1
            signeY = 1
            If Destination.X < Position.X Then
                signeX = -1
            End If
            If Destination.Y < Position.Y Then
                signeY = -1
            End If

            ' Enfin, on applique le mouvement au sprite
            Position.X = Position.X + mouvementX * signeX
            Position.Y = Position.Y + mouvementY * signeY

d’après mois le problème vient du fait que lorsque le déplacement est oblique, je bouge d’un certain nombre de pixel vers le haut et d’un certain nombre de pixel vers la droite, ça fait un escalier et l’escalier est plus court que la ligne droite => déplacement ralentit.

Je me rend compte que je suis pas forcément très clair mais c’est dure à expliquer, petit schéma : http://users.skynet.be/cyse/deplacement.JPG

Salut,

Je n’ai pas bien compris ton code (et ta/tes procédures Arrondir/Arrondi) mais à mon avis ton explication est fiable.

Si tu avais simplement incrémenté l’axe X et l’axe Y de la vitesse désirée tu n’aurait sans doute pas eu se problème (à mon avis). En lisant ton code j’ai cru que tu avais voulu rendre les déplacements en diagonale plus lents !
Le truc le plus simple serait d’incrémenter directement les coordonnées de ton sprit sans calculer de pourcentage pour les déplacements sur X et sur Y.

Je sais pas si j’ai bien compris et répondu à ta question. (dis si je suis totalement à côté pour que je puisse me corriger :ane: )

EDIT: Noyeu Joël :smiley:

indique le langage de programmation concerné dans le titre de ton topic, avant qu’un modéranteur ne passe par là :wink:
pour cela utilise le bouton http://www.clubic.com/forum/style_images/persoclubic/editer.gif situé sous ton message :super:

Ce problème me semble assez générique (il est intéressant pour tout programmeur venant de n’importe quel langage de prog). Tu pourrais cependant mettre [Algo] à la place de [Math].

Et sinon mon poste précédent semble être correcte? :slight_smile:

Vole pas mon boulot :slight_smile:

Puis ce sont des maths ou de l’algo, même si ici c’est du VB ou du Delphi, ça change rien.

Si on passe en vectoriel, tes deux déplacements sont équivalents; m’est avis que tu devras peut-être réfléchir à une solution spécifique au mouvement en diagonal (je n’ai pas d’idée …)

oui au départ c’est du VB.NET mais j’ai mis ça en forme pour que ça soit compréhensible par tout les programmeurs car c’est pas du code spécifique :stuck_out_tongue:

Dusty, si j’incrémente l’axe X et l’axe Y alors la vitesse sera accélérée en diagonale, on sera à la boule rose à la place de la boule bleu ( http://users.skynet.be/cyse/dep2.JPG )

et pour mieux expliqué mon système de pourcentage, en faite je prend la vitesse comme des points de déplacement, que je répartis sur l’axe X et Y selon si ils en ont beaucoup besoin ou pas (si la destination finale est très haute mais pas très a droite, alors le code fournira plus de point à Y et moins à X jusqu’a ce qu’il rejoigne la bonne destination)

pas très bien compris ^^

Oui, j’ai une petite idée, genre absolue( mouvementX - vitesse) : j’obtient une valeur qui est grande qu’en diagonale (car en horizontal mouvementX vaut vitesse donc 0.
Donc si je multiplie ça par mouvementX y aurait moyen d’augmenter la vitesse juste en diagonale.

Mais ça reste du bricolage pas très précis :frowning:

Et l’utilisation de coordonnées polaires (un angle, une distance) ?

Ca ne pourrait pas résoudre ton problème (avec l’utilisation de la trigo pour transmettre trouver la longueur du chemin de ton sprit) ? Le petit (gros?) problème après, c’est la précision de ton algo…

Ce que je proposait auparavant (si on prend le cercle trigonométrique) c’était d’incrémenter bêtement la positions du sprit sur les deux axes en même temps. Mais le chemin parcouru était de racine de 2, ma bille était trop rapide elle devait s’arrêter au cercle (chemin de 1), elle allait trop loin, elle était trop rapide.

Petite question: si tu fais aller ton sprit vers un point à 45 degré du point de départ es-ce que la vitesse est OK? Ou ça pose problème pour tout angle ]0;90[ ?

C’est normal, tu n’as pas de deplacement en diagonale mais uniquement horizontal ou vertical. La longueur d’une diagonale n’est pas la somme des longueurs horizontale ou verticale. La formule exacte pour determiner la longueur de la diagonale est : D^2 = X^2 + X^2
A partir de la tu calcules facilement pourcentX et pourcentY pour avoir un deplacement correct.

merci pour votre aide !

le signe ^ correspond à “exposant” c’est bien ça ?

D² = X² + X² : c’est bien X² + X² ? pas X² + Y² ?

je pense oui :wink:

En fait le monsieur t’a filé la formule de Pythagore, donc oui :wink:

Et le monsieur il s’est plante. Cést bien X et Y et pas X et X

bon j’ai essayé d’intégrer ça dans mon code mais j’ai pas encore réussis :frowning:

les seules données que j’ai sont :

  • coordonné du point : x et y
  • vitesse de déplacement : speed (nombre de pixel qu’on bouge en une fois/frame)
  • coordonné du point de destination = dx et xy (là ou devra se trouver le point lorsque tout les déplacements ont été effectués)

je vois pas trop ou mettre la formule magique dans mon code

Très simple, tu as le point de depart (X,Y) et l’arrivée (DX,DY). Tu determines la distance de cette facon :

DI² = (DX - X)² + (DY - Y)².

Le nombre DI², tu en prend la racine carrée, ca te donne la distance à parcourir DI

En divisant DI par speed tu obtient la durée. Ici, pour toi, le nombre de boucles (attention, ce n’est pas un nombre entier), ce nombre nous l’appelerons T.

T = DI / Speed.

Tu divises ensuite la distance horizontale par T pour savoir combien de pixels tu rajoutes à X à chaque tour, idem pour Y.

dX = (DX - X) / T;
dY = (DY - Y) / T;

A chaque iteration tu fais maintenant :

X = X + dX
Y = Y + dX

Tu fais attention à la dernière iteration pour ne pas depasser ton point d’arrivée (à moins d’avoir arrondi T pour avoir une valeur entière).

Ce n’est pas l’algorithme le plus rapide, mais il a l’avantage d’être universel.

Pour être vraiment universel, il suffit d’obtenir, à partir du point d’origine et du point de destination, l’équation paramétrique de la droite (c’est à dire en fonction d’une variable t).

Soit le point de départ (x0,y0), le point d’arrivée (x1,y1).
On a la position de ton point à l’instant t:
x = x0 + at
y = y0 + b
t

Où:
a = (x1-x0)/speed
b = (y1-y0)/speed

En définissant “speed” comme étant le temps que mettra ton point pour aller de (x0,y0) à (x1,y1).
Avec cette méthode, c’est vraiment universel, et tu n’as pas à te soucier d’arrondis.

edit: calcul quand t = speed:
x = x0 + (x1-x0)/speed*speed
donc x=x1, c’est pareil pour y :super:

edit 2: en règle générale, lorsqu’il s’agit de déplacer des trucs à l’écran selon une certaine trajectoire, on essaye d’éviter les itérations style x = x + delta, et de toujours calculer x en fonction de t (temps). Cela permet d’ajuster par exemple le framerate tout en conservant une représentation à l’écran qui soit cohérente avec le temps réellement écoulé. En d’autres termes, visuellement ça ira à la même vitesse quelle que soit la vitesse de l’ordinateur sur lequel le code est exécuté.

edit 3: bien sûr, il y a des cas où cela n’est pas possible, par exemple si tu simules (pour un screensaver par exemple) des boules qui s’attirent mutuellement par les forces gravitationnelles. Là, tu n’as pas d’autre choix que de découper le temps en tranches minuscules et de faire varier les coordonnées des différentes boules petit à petit (i.e. sans équation).

Merci, je vais regarder ça.

Entre temps j’ai trouvé la solution en utilisation la suggestion de sans-nom avec les vecteurs, mais d’après ce que j’ai lu c’est pas très performant en terme de vitesse.

merci en tout cas des réponses, ça me resservira par la suite

en vecteur :
mouvementX = Cos(_Angle) * _Speed
mouvementY = Sin(_Angle) * _Speed

        ' correction de la vitesse dans le cas ou la distance à parcourir est plus petite que la vitesse
        Si mouvementX &gt; Absolue(X - Destination.X) Alors
            mouvementX = Absolue(X - Destination.X)
        End If
        Si mouvementY &gt; Absolue(Y - Destination.Y) Alors
            mouvementY = Absolue(Y - Destination.Y)
        Fin si

        ' Nouvelles coordonnées du sprite
        X = X+mouvementX
        Y = Y+mouvementY

Quand la vitesse prime, la formule n’est pas utilisable. Le calcul en utilisant la formule necessite une multiplicaiton et une addition pour chaque point alors que la methode iterative ne necessite qu’une addition pour chaque point. Le probleme de la precision peut etre compense par la methode de la virgule fixe, qui reste rapide en donnant de bons resultats.