JeuWeb - Crée ton jeu par navigateur
La gestion de l'évolution de la balle dans un casse-brique (maths inside) - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : La gestion de l'évolution de la balle dans un casse-brique (maths inside) (/showthread.php?tid=1408)



La gestion de l'évolution de la balle dans un casse-brique (maths inside) - Ekilio - 03-05-2008

Yop,

Je me retrouvais dans un cas un peu casse-tête dans le développement d'exo-lands, et comme j'ai fait mon calcul, je me suis dit "autant éviter aux autres de le faire". Donc je vous poste le resultat du calcul ici.

Donc je vous explique le principe général. J'ai un casse-brique, avec donc une balle qui se déplace dans deux direction (vertical et horizontal). Si je le gère uniquement avec des angles de 90°, pas de problèmes. Mais moi, j'aimerais pour varier un peu le jeu que les angles changent.

Donc, pour faire changer les angles, la solution la plus simple est de ne pas se déplacer à la même vitesse sur les repères X et Y : ainsi, si pour 1 pas à droite j'en fait 2 en haut, je me déplacerais pas au même angle que si pour 1 à droite j'en fait 1 en haut.

Mais arrive alors un autre problème : dans ce cas, la vitesse de la balle fluctue en fonction de l'angle avec lequel la balle se déplace. C'est logique, si sur une boucle je fais 3 pas en haut et 1 à droite, je me déplace plus que si je fais 1 en haut et 1 à droite.

Donc la solution pour éviter ça (du moins celle que j'ai trouvée, si vous en avez une meilleure je suis preneur) est de tracer une "ligne imaginaire" entre la position actuelle de la balle (qui est connue) et la position où la balle se trouverais si on la déplaçait selon l'angle prévu.

Je mathématise.

Je vais nommer Xt et Yt la position de la balle à l'instant t, et Xt1 et Yt1 la position de la balle à l'instant t+1, si on se déplace selon l'angle prévu.

Soit Xp et Yp les pas respectifs en X et en Y de la balle. Ces pas sont des données connues.

Actuellement, on a donc :

Xt1 = Xt + Xp
Yt1 = Yt + Yp

Je rappelle que SQRT signifie la racine carrée, et que la distance entre nos deux points est calculable par :

SQRT((Xt1 - Xt)² + (Yt1 - Yt)²)

Bien évidement, une fois remplacées on s'aperçoit de ce que j'indiquais tout à l'heure :

SQRT((Xt1 - Xt)² + (Yt1 - Yt)²) = SQRT((Xt + Xp - Xt)² + (Yt + Yp)²)
= SQRT(Xp² + Yp²)

La distance est donc fortement liée aux pas, ce qui entraine les variations de vitesse dont je parlais.

Un petit dessin pour expliquer la suite :

[Image: demohm3.jpg]

Maintenant, si on trace une ligne imaginaire entre ces deux points dont nous connaissons les coordonnés (en gras sur le schéma ci-dessus).

On veux donc un point sur cette ligne (pour conserver l'angle) mais dont la distance serait fixe et égale à une valeur que je nommerais V et qui est la vitesse de la balle. Se point se trouve aux coordonnés (X?, Y?), et est n'importe où sur la droite.

Notre but est donc de calculer X? et Y? afin de pouvoir positionner la balle au cycle suivant.

Nommons nos points T, T1 et T2 comme sur la figure.

Notre repère est orthonormal, donc on a T1aT2 et T1bT2 perpendiculaires, donc (aT2) et (bT2) parallèles. Par conscéquent, on a (j'utilise la notation des segment pour leur longeur):

[aT2] / [bT] = [T1a] / [T1b] = [T1T2] / [T1T]

Maintenant, on peut remplacer là-dedans pour obtenir nos coordonnés. Commençons par rappeller que, du fait de la position de nos points a et b, et en posant a (Xa, Ya) et b (Xb, Yb), on a :

Xa = Xb = Xt1
Ya = Y?
Yb = Yt

On a donc :

[aT2] = SQRT((X? - Xt1)² + (Y? - Y?)²)
= SQRT((X? - Xt1)²)
= |X? - Xt1|

[bT] = SQRT((Xt - Xt1)² + (Yt - Yt)²)
= SQRT((Xt - Xt1)²)
= |Xt - Xt1|

[T1a] = SQRT((Xt1 - Xt1)² + (Y? - Yt1)²)
= |Y? - Yt1|

[T1b] = SQRT((Xt1 - Xt1)² + (Yt - Yt1)²)
= |Yt - Yt1|

[T1T] = SQRT(Xp² + Yp²) (cf. démonstration plus haut)

Notez que j'utilise une valeure absolue, puisque pour tout X réel, SQRT(X²) = |X|.

Maintenant, pour le calcul des deux dernières mesures, on va utiliser une autre méthode. En effet, je sais que [TT2] = V par définition de V. Ici, il va falloir envisager deux cas :

- Si [TT1] < V, autrement dit si ma balle va plus lentement qu'elle ne devrait, j'ai [T1T2] = V - [TT1]
- Si [TT1] >= V, autrement dit si ma balle va plus vite qu'elle ne devrait, j'ai [T1T2] = [TT1] - V

Pour éviter de calculer dans les deux cas, je vais considérer que dans tous les cas, [TT1] >= V, autrement dit que SQRT(Xp² + Yp²) >= V. Dans les faits, cela veux dire que Xp >= V et Yp >= V puisque :

Xp >= V et Yp >= V
=> Xp² >= V et Yp² >= V (puisque la fonction carré est strictement croissante sur R)
=> Xp² + Yp² >= V
=> SQRT(Xp² + Yp²) >= V (puisque la fonction racine carrée est strictement croissante sur R*+, et que notre vitesse n'est pas négative (impossible, ce n'est même pas reculer puisque ce serait un changement d'angle) et que bien sur, la somme de deux carrés est strictement positive).

Donc voila, tant que Xp >= V et Yp >= V, on a [T1T2] = [TT1] - V = SQRT(Xp² + Yp²) - V.

Attention, je ne peux pas utiliser d'équivalences ici puisque j'ai une incertitude sur les signes.

On va donc commencer les vrais calculs :

[T1a] / [T1b] = [T1T2] / [T1T]
=>
|Y? - Yt1| / |Yt - Yt1| = SQRT(Xp² + Yp²) - V / SQRT(Xp² + Yp²)
=>
SQRT(Xp² + Yp²) * |Yt - Yt1| = (SQRT(Xp² + Yp²) - V) * |Y? - Yt1|
=>
|Y? - Yt1| = SQRT(Xp² + Yp²) * |Yt - Yt1| / (SQRT(Xp² + Yp²) - V)

Maintenant, la question est de savoir si Y? est superieur à Yt1. La réponse se trouve assez simplement puisque nous savons que la direction est la même sur les différents points pour le déplacement de la balle. Donc on peut dire que :

- Si Yt > Yt1, alors Y? > Yt1, d'où :
|Y? - Yt1| = SQRT(Xp² + Yp²) * |Yt - Yt1| / (SQRT(Xp² + Yp²) - V)
=>
Y? - Yt1 = SQRT(Xp² + Yp²) * |Yt - Yt1| / (SQRT(Xp² + Yp²) - V)
=>
Y? = ((SQRT(Xp² + Yp²) * |Yt - Yt1|) / (SQRT(Xp² + Yp²) - V)) + Yt1

- Si Yt < Yt1 (cas du dessin), alors Y? < Yt1, d'où :
|Y? - Yt1| = SQRT(Xp² + Yp²) * |Yt - Yt1| / (SQRT(Xp² + Yp²) - V)
=>
-(Y? - Yt1) = SQRT(Xp² + Yp²) * |Yt - Yt1| / (SQRT(Xp² + Yp²) - V)
=>
Y? + Yt1 = SQRT(Xp² + Yp²) * |Yt - Yt1| / (SQRT(Xp² + Yp²) - V)
=>
Y? = ((SQRT(Xp² + Yp²) * |Yt - Yt1|) / (SQRT(Xp² + Yp²) - V)) - Yt1

Notons au passage que :

Yt < Yt1
<=>
Yt < Yt + Yp
<=>
Yp > 0

Et vice versa.

De manière strictement analogue, on calcul que :

[aT2] / [bT] = [T1T2] / [T1T]
=>
|X? - Xt1| / |Xt - Xt1| = SQRT(Xp² + Yp²) - V / SQRT(Xp² + Yp²)
=>
- Si Xp > 0 :
X? = ((SQRT(Xp² + Yp²) * |Xt - Xt1|) / (SQRT(Xp² + Yp²) - V)) - Xt1
- Si Xp < 0 :
X? = ((SQRT(Xp² + Yp²) * |Xt - Xt1|) / (SQRT(Xp² + Yp²) - V)) + Xt1

Voila, ce qui nous permet au final de résumer :

- Si Xp > 0 :
X? = ((SQRT(Xp² + Yp²) * |Xt - Xt1|) / (SQRT(Xp² + Yp²) - V)) - Xt1
- Si Xp < 0 :
X? = ((SQRT(Xp² + Yp²) * |Xt - Xt1|) / (SQRT(Xp² + Yp²) - V)) + Xt1
- Si Yp > 0 :
Y? = ((SQRT(Xp² + Yp²) * |Yt - Yt1|) / (SQRT(Xp² + Yp²) - V)) - Yt1
- Si Yp < 0 :
Y? = ((SQRT(Xp² + Yp²) * |Yt - Yt1|) / (SQRT(Xp² + Yp²) - V)) + Yt1

Voila, démonstration terminée. Je crois que je n'ai pas fait d'erreur, il suffit de convertir ça dans le langage de votre choix et normalement ça marche. Indiquez-moi si vous avez une méthode plus simple pour le calcul, vu que là il n'est pas très simple quand même, je suis preneur ^^

Bonne soirée,

Ekilio

Edit : en reprenant ma démonstration pour l'adapter en code, j'ai simplifié un peu la formule au final. Je n'inscrit pas les simplifications en toutes lettres, mais en gros, ça donne les formules suivantes :

Posons Vd = sqrt(Xp² + Yp²)

- Si Xp > 0 :
X? = Xt + ((V * abs(Xp)) / Vd)
- Si Xp < 0 :
X? = Xt - ((V * abs(Xp)) / Vd)
- Si Yp > 0 :
Y? = Yt + ((V * abs(Yp)) / Vd)
- Si Yp < 0 :
Y? = Yt - ((V * abs(Yp)) / Vd)

Ce qui permet de dire d'une manière plus générale :

Soit P l'ancien pas pour une coordonnée et P' le pas recherché, donc respectivement le déplacement pour l'angle et le déplacement à la vitesse voulue, on a :

P' = (V * abs(P)) / Vd

Voila, et désolé si il y a des fautes dans la démonstration générale ^^" J'ai testé la dernière version en tous cas, celle ci-dessus, et elle marche.


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - Dolphy - 04-05-2008

A première vue il ne me semble pas y avoir d'erreurs majeures mais bon je n'ai que survolé la démonstration. Pour plus de simplicité tu aurais pu le faire avec des vecteurs et des équations cartésiennes de droite mais bon le résultat est là (enfin j'ai la flème de refaire une démonstration pour vérifier :p)


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - keke - 05-05-2008

Heu, et cosinus et sinus ... ça pourrait pas simplifier les calculs ?

Sans refaire un cours de math, tu pourrais ainsi gérer ta vitesse ... et ta direction. Pour cela tu définis un angle téta (en radian de préférence) et tu calcules ton déplacement selon
x = V * T * cos (téta)
et
y = V * T * sin (téta)

T étant le temps de rafraichissement et V ta vitesse.

Kéké.


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - Ekilio - 05-05-2008

C'est possible aussi, effectivement. Mais le truc, c'est qu'à la base j'avais entre autres comme contrainte justement de ne pas passer par un angle mais bien par deux "augmentations", comme j'ai indiqué en haut (lié à la façon dont fonctionnent certains des bonus pour le casse-brique). Donc en fait, re-calculer les angles puis repasser sur les coordonnés me semblait plus pénible que de le faire comme ça.


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - keke - 06-05-2008

Citation :Donc je vous explique le principe général. J'ai un casse-brique, avec donc une balle qui se déplace dans deux direction (vertical et horizontal). Si je le gère uniquement avec des angles de 90°, pas de problèmes. Mais moi, j'aimerais pour varier un peu le jeu que les angles changent.

Donc, pour faire changer les angles, la solution la plus simple est de ne pas se déplacer à la même vitesse sur les repères X et Y : ainsi, si pour 1 pas à droite j'en fait 2 en haut, je me déplacerais pas au même angle que si pour 1 à droite j'en fait 1 en haut.

Mais arrive alors un autre problème : dans ce cas, la vitesse de la balle fluctue en fonction de l'angle avec lequel la balle se déplace. C'est logique, si sur une boucle je fais 3 pas en haut et 1 à droite, je me déplace plus que si je fais 1 en haut et 1 à droite.

Donc la solution pour éviter ça (du moins celle que j'ai trouvée, si vous en avez une meilleure je suis preneur) est de tracer une "ligne imaginaire" entre la position actuelle de la balle (qui est connue) et la position où la balle se trouverais si on la déplaçait selon l'angle prévu.
Ben je pensais que c'était une meilleur solution ... dans ta méthode, ta vitesse dépend de ton angle ... avec la trigonométrie tu en fais abstraction. Après, le problème d'un bonus qui tombe ... ben c'est la même chose, sauf que l'angle est défini (vers le bas.)
Pour calculer si ta balle touche ou non un bonus (pour le détruire par exemple) ben c'est un simple calcul de distance si ton bonus est rond ... ou à peine plus compliqué si le bonus est bêtement rectangulaire... (et pourquoi on fait des casse brique avec des cases rectangulaires ? hein ?)
L'avantage de la trigonométrie associé à ton problème ... c'est que tu peux faire accélérer la balle de manière constante (sans effet d'acoups comme sur Alphabounce) , tu peux faire des effets de rebonds comme tu le veux (si les cases ne sont pas avec des surfaces planes exemple : les petits monstres d'alphabounce)

Tu peux aussi donner un effet de gravité, de balle troublée, de balle ondulée, de ...

Enfin, c'est ton jeu. Me semble juste qu'à peu de frais, tu peux améliorer ton système. Mes amis trouvent que je fais toujours des choses compliqués. J'ai tendance à leur répondre que j'essaye de faire les choses de manière un peu plus réaliste.

kéké.


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - Ekilio - 06-05-2008

Bonjour,

Je me suis mal exprimé. Cette façon de faire (par la trigo) est effectivement nettement plus simple, et ce n'est pas par rapport à la chute des bonus que se pose le problème (ils ne varient de toutes manières pas de vitesse).

C'est juste que les différents bonus et technologies achetables pour le joueur se basent sur cet effet de, justement, un pas en haut, un pas à droite. Et que donc justement je dois l'utiliser pour le calcul, puisque sinon je dois repasser ça en angle, et ensuite utiliser ta formule.

J'aurais pensé à cette formule avant, quand je concevais le casse-brique, je l'aurais surement mise. Mais là... Ben, je vais quand même regarder, vu qu'il n'est pas encore en ligne, ce sera l'objet de la prochaine mise à jour, mais c'est un poil plus dur ^^ Cela dit, je vais quand même regarder, cela m'inspirera peut-être d'autres bonus ^^

Merci,

Ekilio


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - keke - 07-05-2008

un poil plus dur ? hum ... peut-être. Tu as bien compris que je t'encourage le plus vivement à aller dans ce sens. Il te sera tout aussi simple de faire un bonus qui accelère, qui donne de l'inertie, du poids à la balle.

J'ai personnellement du mal avec les jeux qui ne sont pas trop réaliste ... l'explication de pas à gauche, ou pas à droite me semble particulièrement simpliste et peu adapté sur un casse-brique. Veux-tu que je zieute une version de test de ton jeu pour te donner mon avis ? tu peux m'envoyer un lien par MP si tu le souhaites.

Kéké.
PS : je suis en congé jusqu'à la semaine prochaine ^^


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - Ekilio - 09-05-2008

Salut,

Désolé pour le temps de réponse, periode d'exam = revisions ^^"

Sinon, donc pour répondre, je n'ai pas mis en ligne la version de test pour l'instant, mais j'ai repris un peu le code pour adapter avec des angles, parce que ça a un très net avantage pour une chose, c'est le rebond sur les briques. On peut donner un angle préçis plutôt qu'un changement de pas, et ça c'est bien ^^

Je compte utiliser ceci pour le rebond :

Je considère que les briques sont des rectangles. Pour mon rebond, j'ai donc ça :

12345678987654321
50000000000000005
90000000000000009
50000000000000005
12345678987654321

Ca c'est ma brique. Mon but est que plus l'endroit où la balle tape est proche de 9, plus l'angle de rebond est proche de 180°

Attention pour la suite, le repère de Flash est inversé : le point 0,0 est en haut à gauche.

Donc, pour calculer l'endroit où ça tape, j'ai besoin d'abord de savoir sur quel coté la balle tape. Pour ça, je me base sur la direction (tous mes angles dans le calcul sont en degré pour éviter d'écrire pi, mais dans le code en radian) :

- Si l'angle est entre 1 et 90, la balle monte vers la droite, donc ça peut taper à gauche ou en bas
- Entre 91 et 180, la balle monte vers la gauche, donc ça peut taper à droite ou en bas
- Entre 181 et 270, la balle descend vers la gauche, donc ça peut taper à droite ou en haut
- Entre 271 et 360, la balle descend vers la droite, donc ça peut taper à gauche ou en haut

Maintenant, tout le problème est de définir où ça tape.

Pour ça, je pensais à calcul l'équation de la droite : connaissans l'endroit précédent et le suivant, donc X, Y et X', Y', j'ai donc pour équation :

Soit A le coefficient directeur de la droite, tel que A = (Y' - Y) / (X' - X)

y = Ax + Y - AX

Je vais noter B = Y - AX

Donc, maintenant je prends le coin correspondant. Par exemple, si j'ai un angle de 40°, je prends l'angle en bas à gauche. Je connais ses coordonnés (soit u et v les coordonnés de la brique quand je l'ai positionnée, c'est u, v+h où h est la hauteur de la brique). Je vais les nommer U, V.

Je calcul alors le point Xt, Yt qui est le point de la droite tel que Yt = V :

Yt = AXt + B
<=>
V = AXt + B
<=>
-AXt = B - V
<=>
Xt = (B - V) / -A

Donc, maintenant c'est simple :

- Si Xt > U, alors la droite est à gauche du coin et donc ne touche pas le bord du bas mais celui de gauche
- Si Xt <= U, alors la droite est à droite du coin et donc touche le bord du bas et pas celui de gauche (j'inclue arbitrairement le coin dans ce bord)

Maintenant, pour calculer l'endroit précis, c'est très simple :

- Si Xt > U, je calcul le point Xt1, Yt1 tel que Xt1 = U :

Yt1 = AU + B

C'est l'endroit où ça cogne la brique

- Si Xt <= U, alors la balle cogne la brique en Xt, Yt

Est-ce qu'il y a des moyens plus simples de faire ? Je suis pas doué en maths ^^"


RE: La gestion de l'évolution de la balle dans un casse-brique (maths inside) - keke - 13-05-2008

Hum ... En fait, j'ai un soucis de conceptualisation (je suis vieux aussi. mon annif est dans 2 jours)

Pourquoi la balle rebondirait différemment selon le côté de la brique ? Il me semble que ta brique est rectangulaire. Un rectangle étant formé de quatre segment de droite, l'angle de rebond devrait être inverse à celui de la rentrée en contact.
J'ai l'impression que tu souhaiterais le comportement d'une brique en ellipse. Bon, dans tous les cas, mathématiquement il faut connaitre la tangente au niveau du point d'impact. Le rebond se calcul tout seul.
Dans le cas d'un segment de droite, la tangente est confondue avec le segment de droite. Pas de problème dans le calcul. Pour toute autres formes, c'est peut-être plus difficile à calculer.

J'imaginais que tu pourrais faire des briques triangulaires. Les rebonds pourraient être vachement space ^^.

Pour finir. Il me semble aussi qu'utiliser des calculs de droites (avec Y = Ax + B) est aussi préférable à faire un système de Pas, dépendant du nombre de pixel de ton écran. Tu peux ainsi avoir A et B en nombre décimal, ce qui est bien plus appréciable.

Bonne journée à toi.

kéké.