Et hop, nouvelle démo ! Cette semaine, on s'attaque au HBL... Si vous ne savez pas ce que c'est, regardez la vidéo de la démo et instruisez-vous.
Shadow of the BeastAlors, que voyez-vous de particulier sur cette démo ? Un oeil qui zoome ? Mouais... Un gars qui court ? Mouais... Ok, on ne tourne pas autour du pot, ce qui donne son charme à cette démo (remake de Shadow of the Beast), c'est une impression de profondeur, avec plusieurs niveaux qui scrollent à des vitesses différentes.
Bon, après cette courte mise en matière, on va donc voir ce qui nous intéresse cette semaine : le scrolling parallax et le scrolling différent sur un même fond.
Scrolling ParallaxAlors, le scrolling parallax, c'est quoi ? Tout simplement un mot pour dire que plusieurs fonds scrollent à des vitesses différentes, pour donner une sensation (assez réussie en générale) de profondeur. Pour comprendre le principe, c'est simple : montez dans votre voiture, et roulez... Allez sur une route de campagne bordée par des arbres. Les arbres les plus proches de la route semblent passer très rapidement devant la voiture. Le champ, en revanche, se 'déplace' par rapport à la voiture à une vitesse bien plus réduite. Quant à la petite forêt au loin, elle est encore plus lente, presque immobile... Dans la réalité, il n'y a pas juste 3 couches à vitesses différentes, mais une infinité. Sauf que nos jeux, on est limité par le nombre de fonds.

On applique donc cette effet de façon 'caricaturale' par rapport à la réalité, et en pratique ça donne un effet très simple à mettre en place, mais très sympa (cette démo n'a que 60 lignes...).
Dans un souci de simplification, on a ici la vitesse de scrolling de base (le sol), et les différentes couches vont de 2 fois plus rapidement (nuages du haut, barrière) à 4 fois plus lentement (les nuages les plus lointains).
Scrolling DifférentielCe qui marque dans cette démo, c'est qu'on a plusieurs scrollings différents... Personnellement, j'en compte 8 : 5 couches de nuages, les montagnes, le sol, et la barrière... 8 ?? Pourtant, la DS n'a que 4 fonds, non ? Et en plus, un des fonds est utilisé pour afficher le ciel avec la lune... Cherchez l'erreur !
Bon, en regardant plus attentivement, on remarque que la plupart des nuages ne se chevauchent pas. En fait, si on n'avait pas à leur appliquer un scrolling différent, on pourrait donc les avoir sur un seul et même fond... C'est le cas pour toutes les couches, en fait, sauf les nuages du haut et la barrière ! Voici les fonds utilisés :
Eh oui, un des fonds contient presque toutes les couches qui sont à des scrollings différents ! Pour comprendre comment cela marche, il faut savoir que la DS écrit l'écran ligne par ligne. À la fin de chaque ligne, il y a un très rapide 'temps mort' pendant lequel on peut exécuter un code court avant que la ligne suivante ne commence à être affichée. Ainsi, si on change la valeur du scrolling pendant ce temps mort, la ligne suivante sera décalée.

Il faut donc, dans un premier temps, initialiser la fonction qui sera chargée dans le temps mort, nommée HBL (Horizontal Blank Line) :
(c):
irqSet(IRQ_HBLANK, HBL_function); irqEnable(IRQ_HBLANK);
Voilà, tout simple, j'ai utilisé les fonctions libnds... Rien de bien méchant, la fonction que j'ai faite se nomme HBL_function (original, je sais).
À partir de là, on sait qu'à chaque HBL/temps mort on aura le chargement de cette fonction, quel que soit la position où l'on se trouve dans le code... Il reste donc à savoir à quelle ligne on est au moment du HBL. Si on sait où on est (verticalement, donc), on pourra en effet appliquer le bon scrolling.

(c):
void HBL_function(void){
s16 vcount = PA_GetVcount(); if(vcount > 192) vcount = 0; // Loop
if((vcount >= 0)&&(vcount < 67)) PA_BGScrollX(0, 1, layerscroll); // Normal
else if(vcount < 78) PA_BGScrollX(0, 1, layerscroll>>1); // 2 fois plus lent
else if(vcount < 86) PA_BGScrollX(0, 1, layerscroll>>2); // 4 fois plus lent
else if(vcount < 145) PA_BGScrollX(0, 1, layerscroll>>1); // 2 fois plus lent
else PA_BGScrollX(0, 1, layerscroll); // Normal
}
La fonction PA_GetVcount ne fait que lire dans un registre pour récupérer la valeur. Ce Vcount (Vertical Counter, littéralement compteur vertical, qui indique donc la ligne...) peut prendre des valeurs de 0 à 262. La DS possède 192 lignes, donc à partir de la valeur 192 ce n'est plus en train d'afficher.
Voici aussi la version hors PALib, pour ne pas faire de jaloux.

(c):
void HBL_function(void){
s16 vcount = REG_VCOUNT; if(vcount > 192) vcount = 0; // Loop
if((vcount >= 0)&&(vcount < 67)) BG1_X0 = layerscroll; // Normal
else if(vcount < 78) BG1_X0 = layerscroll>>1; // 2 fois plus lent
else if(vcount < 86) BG1_X0 = layerscroll>>2; // 4 fois plus lent
else if(vcount < 145) BG1_X0 = layerscroll>>1; // 2 fois plus lent
else BG1_X0 = layerscroll; // Normal
}
Il faut prendre en compte un détail assez important : quand on lit le numéro de la ligne, la DS a en fait déjà affiché celle-ci... Donc, si on lit par exemple le numéro 0, la DS a déjà affiché la ligne 0, il est donc trop tard pour lui appliquer le bon scrolling ! Pour remédier à ce souci, j'ai rajouté un simple
if(vcount > 192) vcount = 0;. En effet, puisque de toute façon à partir de 192 on est hors écran, on peut appliquer le scrolling que l'on veut, et ainsi on est sur de ne pas rater le 0.

Le reste de cette fonction me parait assez simple : en fonction de la ligne, on applique un scrolling différent.

Dans un souci de rapidité et de 'justesse', j'ai remplacé les divisions par des décalages de bits.
>>1 vaut
/2,
>>2 vaut
/4, etc. Quant à layerscroll, c'est juste une variable à laquelle on ajoute 1 à chaque frame, histoire de faire avancer le tout.
Mot de la FinVoilà, déjà fini ! Je ne vais pas commenter tout le reste du code, il est très très basique (initialisation d'un fond, déplacement d'un sprite...). Il a été fait avec PAlib, mais les noms de fonctions sont suffisamment explicites pour que tout le monde comprenne

Les fonds n'ont rien de particulier, tous convertis en tiles, 256x192... En fait, dans cette démo, la partie 'cruciale' du code fait moins de 10 lignes !
Cette démo permet de voir qu'avec un peu d'astuce on peut faire des effets bien sympas, et surtout qu'il ne faut pas se fier aux limites 'papier' d'une console, car il existe souvent des méthodes pour les dépasser/contourner...
Dev-Fr.org : Le JeuAllez, comme je suis sympa aujourd'hui je vous livre 2 démos pour le prix d'une.

En fait, cette démo est plus courte et plus simple à comprendre, et repose elle aussi sur le scrolling dans le HBL...
Je ne vais pas détailler tout le code, qui est VRAIMENT simple

, mais je vais montrer les 2 choses importantes...
(c):
#define TAILLE 16
s16 scroll[64] = {};
void HBL_function(void){
u16 vcount = PA_GetVcount()+1; if(vcount > 192) vcount = 0; // Loop
PA_BGScrollX(0, 3, scroll[vcount/TAILLE]); // Normal
}
Voici le début du code, tout simple. On définit la taille (en pixels), ici j'ai mis 16, parce qu'avec 8 c'était super dur

Le tableau scroll va servir à mettre les valeurs de scrolling différents. On peut donc avoir 64 valeurs, donc assez pour des zones de 3 pixels

Et enfin, la fonction HBL_function... Elle sera chargée comme tout à l'heure, pas la peine d'en reparler. Ici, le code est tout simple. À noter qu'on ajoute 1 à Vcount... Pourquoi ? Car le numéro est le numéro qu'on a à la fin de la ligne... Donc quand on sort le numéro de ligne 0, en fait on a déjà mis à jour la ligne 0, donc la ligne qui aura le nouveau scrolling est la ligne 1...
Je vous épargne le code qui charge le fond, et celui qui applique un scrolling différent à chaque bloc, au hasard.

On en arrive donc au code la boucle principale :
(c):
if(Stylus.Newpress){
partie = Stylus.Y /TAILLE; // Par tranches de 8...
oldx = Stylus.X;
}
if(Stylus.Held){
scroll[partie] -= Stylus.X-oldx;
oldx = Stylus.X;
}
En gros, quand on touche l'écran ça regarde quelle partie (en hauteur) on a touchée pour savoir quelle partie déplacer... Ceci permet de ne pas changer de ligne si la personne bouge en hauteur par la suite. Ensuite, tant que le stylet touche l'écran, on ajuste la valeur dans le tableau scroll en fonction du déplacement horizontal par rapport à la frame précédente... et c'est tout ! Eh oui, tout simple.

Maintenant, passez ça en 8 pixels ou moins, et essayez de faire le 'puzzle' en moins de 10 secondes pour voir.
SineBg : Faites des Vagues...Bon, j'en profite pour coller ici l'exemple de PAlib utilisant le HBL pour faire un effet de vague sur un fond scrollant... Rien de bien méchant, je vous laisse voir.
Bon, petit aperçu de la fonction en question :
(c):
void HBL_function(void){
s16 vcount = PA_GetVcount();
vcount++;
if(vcount > 192) vcount = 0; // Get correct vcount
PA_BGScrollX(0, 3, (scrollx&511) + ((PA_Sin((vcount+scrolly)*height+add)*width)>>8));
}
Voilà, rien de bien méchant.

En gros, on applique la fonction Sinus en fonction du numéro de ligne et en prenant en compte le scrolling vertical.

Les variables height et width permettent de modifier la hauteur et largeur de la vague (à 8 par défaut), et add est la valeur qui permet à la vague de se 'déplacer'... (on l'augmente de 4 à chaque frame).
Rien de sorcier, comme vous le voyez. Comme quoi, avec quelques lignes de code on peut faire des petits effets sympathiques.

Bonne fin de week-end à tous, et à la semaine prochaine.
