La Place des Développeurs Limiter l'effet des limites de sprites
aoineko
Membre non connecté
Conseiller Municipal
Suite à une discussion sur MRC sur comment limiter les effets de disparitions de sprites quand on dépasse le nombre maximum de sprites par ligne (4 sur MSX1 et 8 sur MSX2), j'ai voulu tester une méthode assez simple à mettre en place.
Déjà, rappel du contexte:
- Sur tous les MSX, on peut (normalement) afficher jusqu'à 32 sprites à l'écran
- Les informations sur la position, la forme et la couleur des sprites sont rangé dans un tableau en VRAM (la SAT, pour Sprite Attribute Table)
- Pour chaque ligne de l'écran le processeur graphique va chercher dans la SAT les sprites présent sur cette ligne
- Il cherche dans l'ordre du tableau et s'arrête dès qu'il a atteint un certain nombre de sprite (4 sur MSX1 et 8 sur MSX2)
- S'il y a plus de sprites sur une ligne, ceux qui sont au-delà de la limite dans le tableau ne sont pas affichés
- C'est ce qui génère des effets de disparition de tout ou partie de certains sprites
C'est une limite matériel qu'on ne peut pas empêcher... mais dont on peut essayer d'atténuer les effets.
La méthode discuté sur MRC est assez simple.
Au lieu d'avoir 1 seul Sprite Attribute Table (SAT), on en prévoit 2 dans la VRAM.
Les informations de chaque sprite vont être rangé dans les 2 SAT, mais dans l'ordre inverse.
L'astuce consiste ensuite à changer à chaque frame la TAS utilisé par le processeur graphique.
Ainsi on change l'ordre des sprites et leur priorité... du coup, d'une frame à l'autre ce ne sont plus les mêmes sprites qui disparaissent.
En remplace la disparition complète d'une partie d'un sprite par un scintillement (vu que la partie est visible une fois sur deux).
J'ai fait un p'tit programme d'exemple pour ma lib pour tester ce principe sur MSX1 : s_sm1.rom.
Le résultat est assez intéressant.
Après, tout dépend des besoins (nombre de sprites, leur vitesse, etc.).
Par ex., sur mon projet Final Smash, je préfère gérer manuellement les priorités.
Déjà, rappel du contexte:
- Sur tous les MSX, on peut (normalement) afficher jusqu'à 32 sprites à l'écran
- Les informations sur la position, la forme et la couleur des sprites sont rangé dans un tableau en VRAM (la SAT, pour Sprite Attribute Table)
- Pour chaque ligne de l'écran le processeur graphique va chercher dans la SAT les sprites présent sur cette ligne
- Il cherche dans l'ordre du tableau et s'arrête dès qu'il a atteint un certain nombre de sprite (4 sur MSX1 et 8 sur MSX2)
- S'il y a plus de sprites sur une ligne, ceux qui sont au-delà de la limite dans le tableau ne sont pas affichés
- C'est ce qui génère des effets de disparition de tout ou partie de certains sprites
C'est une limite matériel qu'on ne peut pas empêcher... mais dont on peut essayer d'atténuer les effets.
La méthode discuté sur MRC est assez simple.
Au lieu d'avoir 1 seul Sprite Attribute Table (SAT), on en prévoit 2 dans la VRAM.
Les informations de chaque sprite vont être rangé dans les 2 SAT, mais dans l'ordre inverse.
Code TEXT :
SAT1 SAT2 ------------ #0 -> #31 #1 -> #30 #2 -> #29 ... ... #29 -> #2 #30 -> #1 #31 -> #0
L'astuce consiste ensuite à changer à chaque frame la TAS utilisé par le processeur graphique.
Ainsi on change l'ordre des sprites et leur priorité... du coup, d'une frame à l'autre ce ne sont plus les mêmes sprites qui disparaissent.
En remplace la disparition complète d'une partie d'un sprite par un scintillement (vu que la partie est visible une fois sur deux).
J'ai fait un p'tit programme d'exemple pour ma lib pour tester ce principe sur MSX1 : s_sm1.rom.
Le résultat est assez intéressant.
Après, tout dépend des besoins (nombre de sprites, leur vitesse, etc.).
Par ex., sur mon projet Final Smash, je préfère gérer manuellement les priorités.
On est toujours ignorant avant de savoir.
Avant d'arriver à cette solution (de 2 SAT en VRAM), il y en a une plus simple : alterner à chaque frame le sens de copie de la SAT de RAM en VRAM.
Frame paire : copie de la SAT de 0 à 31
Frame impaire : copie de la SAT de 31 à 0
Frame paire : copie de la SAT de 0 à 31
Frame impaire : copie de la SAT de 31 à 0
MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
aoineko
Membre non connecté
Conseiller Municipal
L'avantage d'avoir 2 SAT c'est qu'on a pas besoin de recopier tous son contenu entre 2 frames.
Y a juste besoin d'update les positions des sprites en mouvement.
Après, si tous les paramètres évolue chaque frame (position, pattern et couleur) alors oui, autant utiliser la même SAT et changer juste l'ordre d'écriture.
A mon avis, c'est surtout intéressant pour les sprites MSX2 ou la SAT passe de 128 octet à 8320 octets (avec la SCT). Dans ce cas, c'est très couteux de réécrire la SAT à chaque frame.
Y a juste besoin d'update les positions des sprites en mouvement.
Après, si tous les paramètres évolue chaque frame (position, pattern et couleur) alors oui, autant utiliser la même SAT et changer juste l'ordre d'écriture.
A mon avis, c'est surtout intéressant pour les sprites MSX2 ou la SAT passe de 128 octet à 8320 octets (avec la SCT). Dans ce cas, c'est très couteux de réécrire la SAT à chaque frame.
On est toujours ignorant avant de savoir.
aoineko
Membre non connecté
Conseiller Municipal
C'est cool, avec WebMSX, on peut créer un lien direct vers une ROM hébergé sur le MSXVillage : https://webmsx.org/?MACHINE=MSX1E&ROM=http://msxvillage.fr/upload/s_sm1.rom
Je vais regarder si on peut pas ajouter une nouvelle balise pour notre Forum pour le faire de façon plus simple.
Le top, ça serait même de pouvoir afficher directement une fenêtre WebMSX dans un post (à voir si l'auteur autorise ce genre d'usage).
Je vais regarder si on peut pas ajouter une nouvelle balise pour notre Forum pour le faire de façon plus simple.
Le top, ça serait même de pouvoir afficher directement une fenêtre WebMSX dans un post (à voir si l'auteur autorise ce genre d'usage).
On est toujours ignorant avant de savoir.
Salut ,
super intéressant tout ça
Aoineko , possibilité d'avoir le fichier en BASIC de ton programme ?
La ROM c'est bien mais ça permet juste de voir
Le fichier BASIC permettra de comprendre comment on met en oeuvre réellement...
super intéressant tout ça
Aoineko , possibilité d'avoir le fichier en BASIC de ton programme ?
La ROM c'est bien mais ça permet juste de voir
Le fichier BASIC permettra de comprendre comment on met en oeuvre réellement...
aoineko , possibilité d'avoir le fichier en BASIC de ton programme ?
La ROM c'est bien mais ça permet juste de voir
Le fichier BASIC permettra de comprendre comment on met en oeuvre réellement...
La ROM c'est bien mais ça permet juste de voir
Le fichier BASIC permettra de comprendre comment on met en oeuvre réellement...
ce n'est pas un programme BASIC c'est une rom en Langage Machine
J'ai fait un p'tit programme d'exemple pour ma lib pour tester ce principe sur MSX1 : s_sm1.rom
aoineko
Membre non connecté
Conseiller Municipal
msx45 :
Aoineko , possibilité d'avoir le fichier en BASIC de ton programme ?
Le programme de test est écrit en C (code source), mais je pourrais le retranscrir en pseudo-code pour expliquer comment ça marche si tu veux.
Je connais très peu le BASIC... et j'ai pas spécialement la motivation de m'y mettre.
On est toujours ignorant avant de savoir.
aoineko
Membre non connecté
Conseiller Municipal
@msx45 Dis-moi si c'est clair.
C'est un exemple pour MSX1, mais sur le principe, c'est la même chose pour le MSX2
Code C :
// Structure structure SPRITE // Attributs d'un sprite byte Y byte X byte Pattern byte Color // Variables SPRITE SpriteRAM[32] // Buffer en RAM avec les attribues de sprites byte FrameCounter = 0 // Compteur d'image word AdresseTAS[2] = [0x3E00, 0x3F00] // Adresses des TAS pour les images pairs et impairs // Programme Initialisation_du_VDP: VDP.ScreenMode = Screen3 // Initialiser les adresses des tables du VDP (d'autres valeurs sont possibles) VDP.Adresse_LayoutTable = 0x3800 VDP.Adresse_ColorTable = 0x2000 VDP.Adresse_PatternTable = 0x0000 VDP.Adresse_SpritePattern = 0x1800 VDP.Adresse_SpriteAttribute = AdresseTAS[0] Loading_des_patterns_de_Sprites_en_VRAM: CopyToVRAM NombreDeSprites * 8 bytes FROM TesDonnées TO VDP.Adresse_SpritePattern Initialisation_des_attribus_de_sprites: Loop i 32 // Générer des valeurs aléatoires SpriteRAM[i].Y = Random SpriteRAM[i].X = Random SpriteRAM[i].Pattern = Random SpriteRAM[i].Color = Random // Copier les attribues en VRAM dans les 2 TAS CopyToVRAM 4 bytes FROM SpriteRAM[i] TO VDP.Adresse_SpriteAttribute0 + 4*i CopyToVRAM 4 bytes FROM SpriteRAM[31-i] TO VDP.Adresse_SpriteAttribute1 + 4*i Boucle_principale: Halt // Pour attendre la prochaine intérruption qui a de bonne chance d'être la fin de l'affichage de l'image en cours byte odd = FrameCounter & 1 // 'FrameCounter & 1' vaut alternativement 0 et 1 VDP.Adresse_SpriteAttribute = AdresseTAS[odd] Si odd = 0 adresseVram = AdresseTAS[1] + 31 * 4 // se mettre sur la dernière entrée de la TAS #1 offsetVram = -4 Sinon adresseVram = AdresseTAS[0] // se mettre au début de la TAS #0 offsetVram = 4 Loop i 32 // Bouger les sprites SpriteRAM[i].Y = nouveauY SpriteRAM[i].X = nouveauX // Copier les attribues en VRAM dans la TAS non visible CopyToVRAM 2 bytes FROM SpriteRAM[i] TO adresseVram adresseVram += offsetVram // on avance dans la TAS #0 ou on recule dans la TAS #1 FrameCounter++ GOTO Boucle_principale
C'est un exemple pour MSX1, mais sur le principe, c'est la même chose pour le MSX2
On est toujours ignorant avant de savoir.
igal
Membre non connecté
Conseiller Municipal
aoineko
Membre non connecté
Conseiller Municipal
Il me semble avoir déjà vu ça dans pas mal de jeux, notamment Konami.
C'est moins "sale" qu'avoir un bout de sprite qui disparait complétement.
Mais comme souvent, ça dépend des besoins.
Cette technique était efficace quand les développeurs voulaient dépasser les limites tout en souhaitant que tous les sprites soient "visibles".
Dans un Shoot'em up par ex., ça serait très problématique (et injuste) si une balle disparaissait avant de toucher le joueur.
Dans ce genre de cas, le scintillement est bien moins grave que ne plus voir la balle du tout (surtout que les sprites sont petits et rapides).
Après, c'est pas magique.
Déjà, elle fait scintiller le double de sprites que ceux qui devraient disparaitre (si 2 sprites devaient disparaitre, 4 vont scintiller).
Et puis, si on dépasse le double du nombre de sprites max par ligne, les sprites vont continuer à disparaitre.
C'est moins "sale" qu'avoir un bout de sprite qui disparait complétement.
Mais comme souvent, ça dépend des besoins.
Cette technique était efficace quand les développeurs voulaient dépasser les limites tout en souhaitant que tous les sprites soient "visibles".
Dans un Shoot'em up par ex., ça serait très problématique (et injuste) si une balle disparaissait avant de toucher le joueur.
Dans ce genre de cas, le scintillement est bien moins grave que ne plus voir la balle du tout (surtout que les sprites sont petits et rapides).
Après, c'est pas magique.
Déjà, elle fait scintiller le double de sprites que ceux qui devraient disparaitre (si 2 sprites devaient disparaitre, 4 vont scintiller).
Et puis, si on dépasse le double du nombre de sprites max par ligne, les sprites vont continuer à disparaitre.
On est toujours ignorant avant de savoir.
Je ne sais pas si c'est lié, mais j'ai pu voir que sur certains jeux Konami, sous l'émulateur Meisei, il y a la TAS qui n'arrête pas de changer au cours du temps (voir captures ci-après prises à deux moments différents alors que le jeu est en pause).
MSX un jour, MSX toujours !
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie