La Place des Développeurs Assembleur MSX pour les noobs cours en ligne
aoineko
Membre non connecté
Conseiller Municipal
Qu'entends-tu par « interaction sprites/décors » ?
A ma connaissance, les sprites sont toujours dessinés au dessus du décors et ne peuvent pas "interagir" avec lui.
A ma connaissance, les sprites sont toujours dessinés au dessus du décors et ne peuvent pas "interagir" avec lui.
On est toujours ignorant avant de savoir.
aïe, je m'exprime mal.
Dans un jeu tu peux avoir besoin de gérer les tiles suivant la position de ton personnage. Par exemple: tu rencontre un mur tu es bloqué, tu passe sur une clé tu le ramasses, tu rencontre une porte tu l'ouvres si tu as la clé, etc.
Dans un jeu tu peux avoir besoin de gérer les tiles suivant la position de ton personnage. Par exemple: tu rencontre un mur tu es bloqué, tu passe sur une clé tu le ramasses, tu rencontre une porte tu l'ouvres si tu as la clé, etc.
Le MSXien le plus à l'ouest ... ou presque
aoineko
Membre non connecté
Conseiller Municipal
Tu as plusieurs méthodes, mais qui ne ne sont pas spécifiques à l'assembleur :
- Les collisions entre sprites (entre le héros et la clef par ex.). En assembleur, on pourrait se brancher dans le Hook d'interruption et checker le registre de status S#0 du VDP pour voir si deux sprites se sont superposés. Sur MSX1, je ne sais pas comment on peut savoir lesquels des sprites ont collisionnés mais sur MSX2, tu peux facilement récupérer leurs numéros dans les registres du VDP et interagir en conséquence.
- Les collisions entre sprites (le héros par ex.) et des tiles du décors (une clef par ex.). Une solution simple c'est juste de "projeter" la position du sprite dans l'espace des tiles. Par ex., si tes tiles font 8x8 pixels, tu récupère la position du centre de ton sprite et tu la divise par 8 (3 shift à droite en asm). Ainsi, tu te retrouves avec la colonne et la ligne de ton sprite dans ton tableau de tiles et tu peux regarder si le contenu de cette case est un élément interactif et déclencher une réaction.
Je sais pas si ça réponds à ta question.
- Les collisions entre sprites (entre le héros et la clef par ex.). En assembleur, on pourrait se brancher dans le Hook d'interruption et checker le registre de status S#0 du VDP pour voir si deux sprites se sont superposés. Sur MSX1, je ne sais pas comment on peut savoir lesquels des sprites ont collisionnés mais sur MSX2, tu peux facilement récupérer leurs numéros dans les registres du VDP et interagir en conséquence.
- Les collisions entre sprites (le héros par ex.) et des tiles du décors (une clef par ex.). Une solution simple c'est juste de "projeter" la position du sprite dans l'espace des tiles. Par ex., si tes tiles font 8x8 pixels, tu récupère la position du centre de ton sprite et tu la divise par 8 (3 shift à droite en asm). Ainsi, tu te retrouves avec la colonne et la ligne de ton sprite dans ton tableau de tiles et tu peux regarder si le contenu de cette case est un élément interactif et déclencher une réaction.
Je sais pas si ça réponds à ta question.
On est toujours ignorant avant de savoir.
Sector28
Membre non connecté
Villageois
aoineko
Membre non connecté
Conseiller Municipal
Yep.
Tu as plusieurs solution pour faire ça efficacement.
Soit utiliser des flags pour identifier des comportements particuliers à traiter.
Par ex. :
- Tous tes objets collectables peuvent avoir un numéro de pattern avec le bit#7 à 1
- Les objets qui demande une interaction du joueur (un click de bouton par ex.), avoir le bit#6 à 1
- etc.
L'autre méthode, que je préfère, c'est d'avoir tous tes tiles interactifs en début de ta table de pattern (appelons N le nombre de pattern interactive dont tu as besoin pour ton jeu ; 8, 16, 32, ...).
- Quand tu récupères le pattern où se trouve le joueur, tu tests si sont numéro est inférieur à N (si c'est pas le cas, c'est qu'il est pas interactif et tu t'arrêtes là)
- Préalablement, tu as préparé un tableau de taille N avec les adresses des différentes fonctions qui vont traiter les interactions avec les tiles
- Du coup, tu as juste besoin de faire un truc du genre :
- Ce qui est cool avec ce système, c'est que ton tableau peux être modifié d'un niveau à l'autre en fonction des besoins (s'il est en RAM évidement) et que plusieurs cases du tableau peuvent pointer vers la même fonction.
Si ça vous voulez, je peux détailler un peu plus l'une et/ou l'autre de ces techniques.
Tu as plusieurs solution pour faire ça efficacement.
Soit utiliser des flags pour identifier des comportements particuliers à traiter.
Par ex. :
- Tous tes objets collectables peuvent avoir un numéro de pattern avec le bit#7 à 1
- Les objets qui demande une interaction du joueur (un click de bouton par ex.), avoir le bit#6 à 1
- etc.
L'autre méthode, que je préfère, c'est d'avoir tous tes tiles interactifs en début de ta table de pattern (appelons N le nombre de pattern interactive dont tu as besoin pour ton jeu ; 8, 16, 32, ...).
- Quand tu récupères le pattern où se trouve le joueur, tu tests si sont numéro est inférieur à N (si c'est pas le cas, c'est qu'il est pas interactif et tu t'arrêtes là)
- Préalablement, tu as préparé un tableau de taille N avec les adresses des différentes fonctions qui vont traiter les interactions avec les tiles
- Du coup, tu as juste besoin de faire un truc du genre :
Code ASM :
LD HL, _monTableau LD BC, _monTile ADD HL, BC CALL (HL)
- Ce qui est cool avec ce système, c'est que ton tableau peux être modifié d'un niveau à l'autre en fonction des besoins (s'il est en RAM évidement) et que plusieurs cases du tableau peuvent pointer vers la même fonction.
Si ça vous voulez, je peux détailler un peu plus l'une et/ou l'autre de ces techniques.
On est toujours ignorant avant de savoir.
aoineko
Membre non connecté
Conseiller Municipal
ericb59 :
oui oui vas y...
Bon, je vais vous faire ça en pseudo-code assembleur (ça sera plus compact et bcp plus facile pour moi à écrire).
Prenons un exemple concret (fictif) d’un jeu avec des tuiles représentants :
- les fond de décors (aucune interaction)
- les murs/sol (qui bloquent le joueur)
- de potions de vie/mana (qui remonte les HP/MP quand on passe dessus)
- des portes (qui s’ouvrent quand on passe dessus)
- des portes verrouillées (qui ne s’ouvrent que si on a une clef à utiliser)
- des clefs (qu’on peut accumuler)
Les murs/sols ne sont pas vraiment des objets interactifs donc je vais pas rentrer dans le détail. Il faut juste tester les coins du sprite du personnage avec ces tiles et ajuster sa position en fonction des collisions.
Méthode 1
Pour méthode 1 de gestion des interactions, on pourrait par ex. coder les numéros de pattern avec les règles suivantes :
En résumé :
- Les objets de fond du décor ont une valeur binaire de la forme [0XXX XXXX] (ou X peut prendre n’importe quelle valeur).
- Les murs/sols (blocker) ont une valeur de la forme [10XX XXXX].
- Les objets ramassables : [110X XXX]
-- Les clefs :[1100 0XXX]
-- Les potions de vie : [1101 0XXX]
-- Les potions de mana : [1101 1XXX]
- Les portes : [111X XXXX]
-- Les portes normales : [1110 0XXX]
-- Les portes verrouillés : [1110 1XXX]
L’avantage, c’est qu’on peut faire des traitements à différents niveaux de spécialisation de l’objet interactif. Par ex., une clef et une potion de vie étant tous les deux des « objets ramassables », on peut les faire disparaître quand le joueur passe dessus. Voici un pseudo code de traitement de ces objets :
Code TEXT :
DEBUT: si bit#7 de Pattern égal 0 goto FIN ; le décor, rien à faire si bit#6 de Pattern égal 0 goto CHECK_COL ; pas détaillé ici si bit#5 de Pattern égal 0 goto COLLECT ; objet ramassable ; sinon c’est une porte PORTE: si bit#3&4 de Pattern égal 00 goto OUVRIR_PORTE ; porte normale si bit#3&4 de Pattern égal 01 goto CHECK_CLEF ; porte verrouillée goto FIN CHECK_CLEF: si NombreDeClef égal 0 goto FIN ; pas de clef, la porte ne s’ouvre pas reduire NombreDeClef de 1 ; on consomme une clef OUVRIR_PORTE: ouvrir la porte goto FIN COLLECT: effacer le pattern à l’écran ; traitement commun à tous les objets ramassable si bit#3&4 de Pattern égal 00 goto CLEF si bit#3&4 de Pattern égal 10 goto POTION_VIE si bit#3&4 de Pattern égal 11 goto POTION_MANA goto FIN CLEF: augmenter NombreDeClef de 1 goto FIN POTION_VIE: augmenter PointDeVie de 1 goto FIN POTION_MANA: augmenter PointDeMagie de 1 goto FIN FIN: retour
Voilà.
Cette technique a ses avantages et ses inconvénients.
Elle peut être utile quand vous avez beaucoup d’objets différents mais qui partagent une grosse partie de leur traitement.
Si vous avez peu d’objet, la méthode 2 (ou un mix) est sûrement plus intéressant.
Mais ça, c’est une autre histoire…
On est toujours ignorant avant de savoir.
ericb59
Membre non connecté
Conseiller Municipal
Ha oui... ok... J'ai utilisé cette technique pour la suite de Treasure of Babylon (un jeu non fini, non sorti )
Bon, c'était moins fin, mais équivalent.
Bon, c'était moins fin, mais équivalent.
aoineko
Membre non connecté
Conseiller Municipal
Méthode 2
La methode 2 est encore plus simple.
Il suffit de réserver un nombre de tuile pour celles qui sont interactives.
Dans l’exemple précédent, réservons 8 tuiles et affectons les index suivants :
- 0 : Une clef
- 2 : Une potion de vie
- 3 : Une potion de mana
- 4 : Une porte normale
- 5 : Une porte verrouillée
Le pseudo code de traitement serait alors :
Code TEXT :
DONNEE: dw CLEF ; 0 dw RIEN_FAIRE ; 1 dw POTION_VIE ; 2 dw POTION_MANA ; 3 dw CHECK_CLEF ; 4 dw OUVRIR_PORTE; 5 dw RIEN_FAIRE ; 6 dw RIEN_FAIRE ; 7 DEBUT: si Pattern supérieur à 7 goto FIN ; tuile non interactive goto DONNEE + Pattern ; aucun test à faire FIN: retour CLEF: effacer le pattern à l’écran augmenter NombreDeClef de 1 retour POTION_VIE: effacer le pattern à l’écran augmenter PointDeVie de 1 retour POTION_MANA: effacer le pattern à l’écran augmenter PointDeMagie de 1 retour CHECK_CLEF: si NombreDeClef égal 0 goto FIN ; pas de clef, la porte ne s’ouvre pas reduire NombreDeClef de 1 ; on consomme une clef OUVRIR_PORTE: ouvrir la porte retour RIEN_FAIRE: retour
Le code est beaucoup plus performant que dans la méthode 1 (très peu de test pour accéder au code spécifique à chaque interaction).
Le seul défaut c’est la nécessité d’allouer un peu d’espace à la table de saut (celle qui relie un numéro de pattern avec une routine dans le programme) et les risques de redondance.
J’ai présenté ces deux techniques de façon séparée par souci didactique, mais en vrai, si j’étais confronté à cette situation, je ferais sûrement un mix des 2 techniques.
Par exemple, pour check si une tuile est un bloqueur (mur/sol), j’utiliserais plutôt le check de bit, alors que pour le reste, j’utiliserai plutôt une table de saut.
Pour les objets dont le traitement est très proche – comme la potion de vie et de mana – je garderais des bits pour les différencier et j’utiliserai un code générique. Par ex., on pourrait avoir un tableau avec la vie comme entrée d’index 0 et la mana comme entrée 1 ; on pourrait alors avoir un code commun qui incrémente la valeur dans le tableau en fonction du bit#0 du Pattern, sans tester s’il s’agit d’une potion de vie et ou de mana.
Voilà, j’espère que ça vous est utile.
On est toujours ignorant avant de savoir.
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie