Okay. It might be a little pathetic ... I've spent some time figuring out an algorithm for properly handling slopes in my platformer, but i didn't found the time to properly inject it into code, so I just speed-typed it in a draft post. One of the key ideas is that you won't try to adjust frame t's horizontal speed to the slope you have to cross, but instead defer the effect of climbing dy pixels to the next frame's horizontal speed. This allows a one-pass while all my previous attempt had to iterate until they find the position you'd actually take given the slope you have to climb.
- dx : horizontal speed for this step.
- tile(x) : returns the tile holding a given coord.
- end_of_tile(x, dir) : last pixel of tile containing x ends when you go towards dir.
- next_tile(x,dir) : first pixel of the tile after tile containing x when you go towards dir. next_tile(x, dir) == end_of_tile(x, dir) + (dir>0)?1:-1
- ground_height(x,y) : in the tile under (x,y), the height of the ground at specific location (x,y). 0 means "this is a sky tile", there is no ground to stand here. -1 is the lowest pixel of the tile, at -7, you should be on the highest pixel of the tile, and at -8, you should actually not be on this tile, but on the lowest pixel on the one just ahead.
Now, we know what height we have when we enter tile(new_x). We just have to compute where we'll end in that tile and we've finally done.new_x = x + dx
while (tile(new_x) != tile(x)) {
gh = ground_height(end_of_tile(x,dx),y);
if (gh!=0) y = end_of_tile(y,1) +gh;
x = next_tile(x,dx);
}
Quick Note : the 'x' and 'y' are copies of the object's hotspot position, and the result of the algorithm is the new_x, new_y position at which the GOB's hotspot should be moved. I still have to figure out where cando(new_x, new_y) should be applied to ensure walking slopes do not allow one to move through walls, etc. I also have to figure out how to integrate this properly with the OO model I have so far : what is under the responsibility of iWorld, iGobController and GameObject.if (ground_height(new_x, y) == 0) {
new_y = end_of_tile( next_tile(y,1), 1) + ground_height(new_x, next_tile(y,1));
} else {
new_y= end_of_tile( y, 1) + ground_height(new_x, y);
}
C'est par manque de temps que ce petit algorithme de gestion des pentes se retrouve sur ce blog plutôt que dans le code. Une des idées simplificatrices de base (par rapport aux essais précédents) est qu'il n'est pas nécessaire de traiter immédiatement l'effet de la pente sur la vitesse horizontale (je ne sais pas vous, mais moi, je vais généralement moins vite en montée qu'en descente). A la place, je peux utiliser l'élévation du sprite à l'instant t-1pour ajuster sa vitesse horizontale à l'instant t... Le résultat, c'est que le calcul de la position actuelle peut être effectué en une seule passe, se basant exclusivement sur la fonction ground_height() qui retourne pour chaque position horizontale dans un tile pentu la hauteur de la pente depuis la base du tile.
ancien post-scriptum: je ne vous ai pas oublié, mes lecteurs francophones (près de 50% d'entre-vous). Vous aurez peut-être compris que ce billet fait office de "pseudo-code retapé en vitesse et commenté". Le temps de loisir est distillé au compte-goutte ces temps-ci, entre les dents de *deline et les grands rangements de la maisonnette qui en a bien besoin.
5 comments:
Hello ^^
Vu que c'est en anglais j'ai peut être pas tout compris. Dernièrement, j'ai mal réfléchi à cette partie du moteur pour la suite d'Inside the Machine. J'ai choisi d'implémenter les slopes sur la même base que mon ancien moteur mais en améliorant la chose. Je sauvegarde la hauteur de chaque tile pentu donc j'ai simplement une fonction qui me donne la hauteur un tile en fonction de la position X du joueur dessus. Finalement, plutôt que de m'embêter pour savoir si le prochain tile est une pente par exemple. J'ai encore plus multiplié les test points qu'avant. Pour un personnage, je dirais que j'ai facilement 5 test points qui résolvent différents problèmes comme : Un perso qui passe d'un tile pentu à un autre tile pentu ou un perso qui decend vite le long d'une pente et qui doit rester "collé" à la pente (comprendre, ne pas activer son animation "en l'air" alors qui descend le long de la pente).
@uldéric: je serai tenté de comparer ça avec cette approche-ci dès que j'aurai vérifié qu'elle marche effectivement. Théoriquement, j'ai testé tous les cas sur papier, mais on verra à l'usure.
5 test. Etonnant. Ici, les "tests" sont essentiellement dans la fonction ground_height() qui donne effectivement l'ajustement en Y pour un point dont on donne les coordonnées (X,Y). A priori, si la vitesse horizontale est < à la taille d'un tile, on devrait rester à 3 tests.
Et encore, c'est peut être abusif mais en gros j'ai 14 tests points par persos (tous ne sont pas actifs en même temps :p) : 1 en haut, 2 à gauche et 2 à droite, 3 en bas (2 deux pour les collisions simple et 1 pour les pentes). Sans compter les différentes variantes pour régler les cas particuliers dont je te parlais plus haut. Je n'ai pas cherché à optimiser ça plus (car il y a de quoi faire je pense) mais bon, je n'ai pas de soucis de perfs, même avec 20 ennemis à l'écran (bon il n'y aura jamais 20 ennemis à l'écran).
En tout cas, étant en pleine phase de dev c'est toujours intéressant de voir un peu comment un autre procède. Faudrait que je me décide à poster un peu l'avancement de mon jeu sur mon blog mais je n'ai pas le courage :p
Juste. C'est vrai que j'ai éliminé un grand nombre de test-points au profit d'un test plus global sur les propriétés des zones baptisé "cando(...)", qui s'inspire du code de Xargon.
http://sylvainhb.blogspot.com/2009/02/xargon-may-source-be-with-you.html
au passage, je serais aussi curieux de connaître ton avis sur cet article : http://sylvainhb.blogspot.com/2009/07/les-plate-formes.html
Post a Comment