Obligement - L'Amiga au maximum

Mercredi 30 avril 2025 - 17:04  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Dossier : Les routines de traçage dans les jeux Amiga de Graftgold
(Article écrit par Andrew Braybrook et extrait de uridiumauthor.blogspot.com - janvier 2018)


Introduction

Lorsque j'ai commencé à travailler sur Amiga, j'avais beaucoup à apprendre. Nous étions en 1989, et la première incursion de notre société Graftgold dans le monde des machines 16 bits était déjà en cours, et allait devenir Simulcra. Dominic Robinson écrivit un système d'exploitation multitâche tout en cherchant à savoir comment tracer des objets en 3D. Il ne s'était pas trop préoccupé d'une routine de tracé pour les objets de type sprite, car il n'en avait pas besoin.

La première routine que j'ai écrite était en fait un traceur de polices de caractères. Elle est moins complexe qu'un traceur de sprites parce que le texte est toujours écrit entièrement sur l'écran (et non pas à moitié sur et à moitié hors de l'écran), de sorte qu'il n'est pas nécessaire de programmer un écrêtage, il suffit de vérifier que les coordonnées X et Y sont dans les limites.

Vos routines de tracé doivent être aussi efficaces que possible. Toute instruction superflue dans ces routines affectera le nombre d'objets que vous pouvez afficher dans une image de jeu. Lorsque vous avez écrit une routine de tracé, même une qui utilise le Blitter, vous pouvez voir combien de lignes de code assembleur il faut (environ 800 en fait) pour faire ce qu'un sprite matériel fait presque sans effort, et vous commencez à apprécier à quel point elles sont utiles, et à quel point la puce graphique du C64 est intelligente.

Je ne me souviens pas du temps qu'il nous a fallu pour écrire la première routine de tracé complète, mais cela a dû prendre quelques jours pour que tout soit parfait. Pratiquement tous les jeux Amiga qui n'ont jamais existé devaient en avoir un. Cela aurait dû faire l'objet d'un listing dans un magazine !

Formats d'écran

L'écriture du traceur de polices m'a familiarisé avec la disposition de la mémoire de l'écran. J'ai commencé par la version Atari ST, qui avait chaque 16 pixels horizontalement entrelacés en quatre mots consécutifs (16 bits x 4). C'était légèrement différent de ce que l'Amiga pouvait faire. Vous pouviez placer les plans de bits de l'Amiga dans des zones complètement différentes de la mémoire vidéo, mais il vous fallait alors quatre ou cinq pointeurs sur chaque plan de bits. Chaque plan de bits fournit un bit par pixel et est combiné pour créer un index dans la palette, qui donne à chaque pixel sa couleur. Nous avons choisi d'entrelacer les plans de bits par ligne de trame. Chaque plan de bits a commencé à 40 octets d'intervalle dans un bloc mémoire. Cela nous permet d'utiliser le Blitter pour tracer tous les plans de bits en une seule opération. Pour faciliter cette opération, les objets que nous avons tracés devaient également avoir des masques de plans de bits et des données graphiques entrelacés.

Pour une opération de Blitter plus lente et utilisant moins de données, nous devrions continuer à réinitialiser les pointeurs de masque pour chaque plan de bits et faire les plans de bits un par un. Je m'avance un peu, car nous avons commencé par écrire des routines sur Atari ST, et nous les avons converties pour Amiga en utilisant seulement du code, pas de Blitter.

La puce graphique lit les plans de bits qui ont été utilisés pour l'affichage de gauche à droite et ensuite sur une ligne, et en commençant par le bit zéro, combine 1 bit de chaque plan de bits pour faire un numéro de couleur pour ce pixel. Le numéro de couleur indexe votre palette définie de 16 ou 32 couleurs. Cette recherche indirecte peut vous permettre de réaliser des effets intéressants, car vous pouvez modifier chaque instance d'une couleur à l'écran en changeant simplement l'une des couleurs de la palette. Le fondu à l'écran est très simple.

Une fois que vous avez transféré les pixels à l'écran en utilisant le processeur, vous pouvez essayer de vous familiariser avec le Blitter. Cela réduira la quantité de code dans la routine de traçage et rendra les opérations de traçage un peu plus rapides. Je me souviens d'avoir passé un certain nombre d'appels téléphoniques à l'assistance technique de Commodore à cette époque, car le Blitter était une bête difficile à apprivoiser. Vous devez vous assurer que votre programme vérifie que le Blitter a terminé son opération précédente avant de commencer à charger ses registres pour l'opération suivante. En y réfléchissant, deux Blitters auraient été vraiment bien, ou trois ?

Graphismes

Au départ, nous avons utilisé les Atari ST comme machines graphiques. Nous pouvions enregistrer un graphisme individuel sous la forme d'un fichier binaire, puis inclure ce fichier, avec quelques informations supplémentaires sur la taille, dans un fichier graphique assemblé. Ce fichier serait finalement chargé au moment de l'exécution. Plus tard, nous avons écrit un découpeur de sprites qui pouvait prendre des feuilles de graphismes et générer plus facilement les graphismes et les informations de taille dans différents formats pour les différentes plates-formes.

Nous avons décidé de limiter nos graphismes à une largeur de 16 ou 32 pixels. Si nous voulions quelque chose de plus grand, nous devrions tracer les objets avec plusieurs appels. Cela serait moins efficace au moment de l'exécution, mais nécessiterait moins de code. Nous ne prévoyions pas beaucoup de graphismes de grande taille, nous préférions utiliser davantage d'objets plus petits.

Nous avions tendance à utiliser la coordonnée supérieure gauche de chaque objet comme origine. C'est probablement dû au fait que nous avons travaillé avec des caractères et que le haut gauche est toujours le point de départ. Cela rend le tracé plus facile à penser, ainsi que la détection des collisions. De nos jours, j'utiliserais le centre gravitationnel de l'objet comme origine car nous avons tendance à utiliser plus de physique, et comme nous avons inclus des décalages de pixels pour X et Y, cela n'a pas vraiment d'importance.

Très souvent, un objet tracé n'a pas exactement 16 pixels sur 16, ou 32 sur 32. Pour gagner de la place et du temps lors du traçage, nous avons toujours supprimé les lignes vierges du haut et du bas. Les pixels étant regroupés par 16 sur l'écran, il n'était pas pertinent de supprimer les pixels vides horizontalement. Le format graphique pour un objet graphique d'une largeur de 16 bits était alors le suivant :
  • Un en-tête définissant la profondeur de l'objet et un décalage par rapport à la première ligne tracée, c'est-à-dire le nombre de lignes vierges à sauter avant que le graphisme ne commence, ou à reculer en utilisant des décalages négatifs. Il y aurait également un décalage X au cas où nous voudrions faire glisser le cadre graphique sur le côté.
  • Pour chaque ligne de trame, nous aurions un masque de données de deux octets. Il s'agirait de l'opposé logique des quatre plans de bits combinés par "OU". La routine d'enregistrement de l'éditeur graphique pourrait s'en charger pour nous.
  • Pour chaque plan de bits, nous aurions deux octets de données graphiques.
Les traceurs d'une largeur de 32 pixels nécessitaient un graphisme source avec quatre octets de masque et quatre octets de données de plan de bits par ligne de trame.

Chaque objet du jeu avait généralement un certain nombre d'images pour son animation. Nous gardions toutes ces images consécutives en mémoire pour faciliter l'animation. L'image de base est la première de l'ensemble des images du jeu. Nous avons pu générer des graphismes réfléchis gauche-droite pour les jeux latéraux au moment du chargement, et pour les jeux de haut en bas, la direction dans laquelle se trouvait un objet décidait d'un numéro de base secondaire pour obtenir généralement l'un des huit ensembles de graphismes. L'éclairage étant directionnel, les graphistes devaient dessiner l'objet et le ré-éclairer pour huit directions. Nous n'avions pas de logiciel 3D à l'époque, et même si nous en avions eu un, il aurait probablement été excessif pour un jeu qui ne disposait que de 16 couleurs pour le rendu. La tâche des graphistes consistait à faire en sorte que l'objet soit beau dans les huit directions.

Commencer simplement

Lorsque vous essayez pour la première fois d'écrire à l'écran, vous devez être conscient que le fait de rater l'écran et d'écrire ailleurs peut entraîner un désastre pour le programme. Il est vital que vous traciez le programme une instruction à la fois et que vous vérifiiez toutes les destinations d'écriture aussi précisément que possible. À l'époque des machines 8 bits, nous n'avions pas de traçage en une seule étape, ce qui entraînait de nombreux plantages. Heureusement, une pichenette sur l'interrupteur marche/arrêt vous permettait de repartir en une seconde. Je me demande pourquoi ils ont arrêté de faire ça ?

Une routine de traçage simple et agréable pour commencer est une simple ligne de 16 pixels qui est toujours alignée avec les mots de l'écran. Vous commencez avec les coordonnées X et Y de l'écran où vous voulez tracer votre ligne. Nous vérifions tout d'abord que nous voulons tracer la ligne sur l'écran. À cette fin, nous vérifions simplement que notre coordonnée Y est comprise entre 0 et 255, et que la coordonnée X est comprise entre 0 et 319. Nous devrons en fait nous débarrasser des quatre derniers bits de la coordonnée X car ils représentent des positions de pixel que nous ne gérons pas avec notre traceur aligné sur le mot. Nos coordonnées pour ces routines représentent la partie supérieure gauche de la ligne ou de l'objet que nous traçons.

Vous devez connaître le format de l'écran afin d'obtenir la position et les couleurs correctes de votre routine de traçage. Les écrans Amiga étaient généralement divisés en quatre plans de bits pour un système à 16 couleurs, et nous avons arrangé nos plans de bits entrelacés par ligne sur l'écran. Ce que nous voulons calculer alors, c'est la distance dans la mémoire de l'écran que nous devons décaler pour atteindre le mot que nous voulons modifier. Après avoir décidé que notre ligne irait sur l'écran, nous utilisons la formule suivante :

Décalage en octets = (coordonnée Y x octets par ligne x nombre de plans de bits)+ ((coordonnée X / 16) x 2)
                   = (coordonnée Y x 160) + (coordonnée X / 16) x 2

Les 16/2 correspondent au nombre de pixels regroupés dans un mot (deux octets) de données, puisqu'un pixel peut se déplacer sur 16 positions de bits avant de passer au mot suivant. Il est important d'être aligné sur les mots lorsque l'on écrit des mots de données, et nous voulons travailler par blocs de 16 bits pour des raisons d'efficacité. L'écriture de 32 bits en une seule fois ne doit se faire que sur une frontière de 16 bits puisque nous n'avons qu'un bus de données de 16 bits et qu'il faudra deux opérations du processeur pour écrire 32 bits.

Puisque nous avons utilisé 40 octets par ligne et quatre plans de bits, nous avons multiplié la coordonnée Y par 160, ce qui peut être fait en cherchant la réponse dans une table de 160, ou vous pourriez choisir de multiplier Y par 32, de stocker ce résultat, puis de le multiplier par quatre et d'ajouter les deux ensemble, puisque 32+128 fait 160. Le processeur ne multiplie pas non plus par des puissances de 2, vous pouvez simplement décaler la valeur binaire vers la gauche d'autant de puissances de 2 que nécessaire, c'est-à-dire 5 pour 32 fois. Cependant... pour un système plus polyvalent, il pourrait y avoir un multiplicateur à l'intérieur.

Si vous savez que votre ligne sera solide et d'une seule couleur, vous pouvez écrire quatre plans de données à partir du décalage calculé dans les données de l'écran, en ajoutant 40 octets pour atteindre le plan de données suivant. La couleur que vous obtenez dépend du fait que vous écrivez des zéros ou des uns dans chaque plan de bits particulier. En général, les couleurs des lignes prédéfinies sont enregistrées à l'avance dans la mémoire, ou bien vous les avez dessinées dans un logiciel de dessin et vous les avez sauvegardées sous forme de données binaires.

Nous avons écrit un découpeur de sprites personnalisé qui pouvait lire une feuille de graphismes et sortir une série d'images graphiques dans notre format personnalisé, avec toutes les tailles X et Y dans le format dont nous avions besoin pour l'Amiga. Le logiciel recevait un fichier script qui lui indiquait les feuilles graphiques à charger, l'emplacement des images sur la feuille et leur taille, et si nous voulions ajouter des décalages pour décentrer les graphismes (ou peut-être les recentrer s'ils avaient des bits "collants" d'un côté). Le résultat était un fichier binaire contenant tous les graphismes du jeu, coupé pour éliminer les lignes vides, et un fichier d'en-tête assembleur définissant tous les numéros d'image pour que le programme sache quelle image se trouve à quel endroit. Cela nous a permis d'ajouter facilement des images d'animation à un objet et, tandis que toutes les images ultérieures étaient déplacées, l'assembleur connaissait les nouveaux numéros d'image lors de la prochaine compilation.

Traçage

Plutôt que de commencer sur l'Amiga et de plonger immédiatement dans le Blitter pour qu'il trace les graphismes, nous avons commencé par faire le travail en code, principalement parce que nous avions déjà une routine Atari ST qui faisait presque l'affaire. Vous pouvez également vérifier le code ligne par ligne dans le débogueur, alors que si vous chargez le Blitter avec un mauvais paramètre, il a le pouvoir de mettre un vrai bazar dans votre mémoire vidéo. Commencez simplement.

Nous avions déjà des routines de traçage sur Dragon 32 et ZX Spectrum, nous savions donc quelle était la tâche à accomplir. Puisque 16 pixels consécutifs sur chaque plan de l'écran sont contenus dans un mot de 16 bits, nous devons faire glisser les graphismes à l'intérieur du mot jusqu'à la bonne position. Ce n'est pas trop difficile sur Amiga puisqu'il a des registres de 32 bits, nous pouvons effacer une moitié du registre et charger 16 bits de zéro dans l'autre moitié, puis faire pivoter le graphisme en position, commodément avec une instruction qui prend 1-15 comme paramètre dans un autre registre.

Pour continuer sur le thème de l'utilisation de graphismes qui sont bien alignés avec les mots 16 bits sur l'écran, et peut-être vos tuiles de fond si vous avez utilisé des blocs 16x16 pour faire le fond, étendons l'exemple ci-dessus pour écrire un bloc de couleur 16x16.

En utilisant la procédure ci-dessus pour vérifier que la coordonnée X est sur l'écran, nous avons deux cas supplémentaires à vérifier par rapport à la coordonnée Y. Si la coordonnée Y est inférieure à la coordonnée X, il faut vérifier que la coordonnée Y n'est pas inférieure à la coordonnée X. Si la coordonnée Y se trouve à moins de 16 pixels du bas de l'écran, nous allons devoir arrêter le tracé prématurément, c'est tout. Deuxièmement, si la coordonnée Y est inférieure à 0 mais supérieure à -16, nous devrons commencer au début de l'écran et, une fois encore, interrompre le traçage prématurément. Pour le traçage d'un simple bloc de couleur, il n'est pas nécessaire d'ajuster le point de départ dans un graphisme plus complexe.

Après avoir déterminé l'endroit où nous allons commencer à tracer sur l'écran, ainsi qu'une boucle interne parcourant les quatre (ou le nombre de) plans de bits que nous utilisons, nous avançons le pointeur de sortie d'un autre plan de bits pour atteindre la ligne Y suivante sur l'écran et nous avons une boucle externe pour compter le nombre de lignes que nous traçons, soit les 16 lignes complètes, soit moins si nous avons traversé le haut ou le bas de l'écran.

En réalité, nos graphismes peuvent tous avoir des profondeurs et des largeurs différentes, et nous devons gérer cela efficacement. Les données graphiques contiendront un en-tête nous indiquant, pour chaque image, si nous pouvons ignorer les lignes vierges de début et combien de lignes exactement nous devons tracer.

Masquage

La routine simple décrite ci-dessus ne fait que tracer un bloc solide de 16x16 pixels d'une seule couleur. Ce n'est pas particulièrement utile. En général, nous voulons qu'un graphisme de forme bizarre glisse joliment sur l'arrière-plan sans perturber l'arrière-plan qui l'entoure. Pour cela, nous devons faire ce que nous appelons du "masquage", c'est-à-dire que nous découpons une forme dans l'image d'arrière-plan afin de pouvoir appliquer notre objet sur l'arrière-plan dans la forme dont nous avons besoin. Notre utilitaire de découpe de sprites a été en mesure d'élaborer le masque, ce qui se fait en effectuant un OU logique sur tous les mots du plan de bits (quatre ou plus) et en inversant le résultat. Cela vous donne des "1" binaires là où vous ne voulez pas tracer de couleur, et des "0" là où vous avez des pixels de couleur. En fait, lorsque nous avons utilisé le Blitter pour tracer les objets, nous avons dû faire en sorte que le découpeur de sprites n'inverse pas le masque car le Blitter voulait l'inverser pour nous.


En fait, notre découpeur de sprites est allé un peu plus loin, car il devait faire la différence entre un pixel transparent et un pixel réel de couleur zéro. En règle générale, nous définissions la couleur zéro comme étant le noir et la couleur 15 comme étant le blanc, et nous classions les autres couleurs par groupes en fonction de leur luminosité. D'habitude, je voulais aussi faire quelque chose d'un peu intelligent avec quelques-unes des autres couleurs, comme des effets lumineux ou une lumière clignotante. Dans le script de découpage des sprites, nous pouvions donc désigner pour chaque sprite la couleur transparente parmi les 16.

La plupart de nos graphismes comportaient alors, pour chaque ligne de graphisme, un mot ou une longueur de masque, puis quatre plans de bits ou plus de données de couleur, également sous forme de mots ou de longueurs. Pour tracer votre objet, vous devez alors faire un "ET" du masque par rapport à l'arrière-plan dans tous les plans de bits, afin d'enlever la couleur de l'endroit où vous voulez tracer, puis faire un "OU" de votre nouveau graphique sur l'arrière-plan, ce qui définit les sélections de couleurs dans les plans de bits.

Passer à droite

Une fois que nous avons décidé de positionner les pixels X individuellement, nous devons être en mesure de décaler les graphismes le long des mots des plans de bits de l'écran. Vous devez lire le masque et les graphismes dans les registres du processeur et les faire pivoter dans les positions requises avant de les appliquer à la zone de l'écran. Pour des raisons de rapidité, certaines personnes ont pu réaliser des graphismes précalculés pour de petits objets. Si vous dessinez une petite balle dans 16 positions différentes de pixels X dans l'ordre, vous pouvez décider de l'image à afficher en fonction du demi-octet (nybble) de l'octet de poids faible de la coordonnée X. Pour la position zéro, nous aurions la valeur suivante : "0", "0", "0", "0", "0", etc. Pour la position zéro, nous tracerions un graphisme de 16 pixels de large, et pour les autres, nous tracerions un graphique de 32 pixels de large. Nous n'avons jamais fait cela, mais si vous vouliez beaucoup de petits graphismes identiques sur l'écran, cela vous ferait gagner un peu de temps.

Découpage

Les choses commencent à se compliquer. Si nous ne voulons pas que nos graphismes ne sortent pas des limites de l'écran, nous devrons également contrôler le tracé d'une partie de nos graphismes près des bords de celui-ci. De nombreux jeux n'ont pas besoin de faire ce que nous appelons du "clipping" (découpage), mais les jeux à défilement en ont généralement besoin car les objets peuvent arriver et partir par les bords.

Si votre objet arrive par le haut de l'écran, il vous suffit de sauter le haut manquant du graphisme et de commencer au bon endroit. Si l'objet arrive par la droite, il faut tracer la gauche de l'objet et non la droite.

En outre, vous devez être en mesure de traiter l'objet arrivant par le coin supérieur droit, ce qui implique de sauter une partie du graphisme et de ne tracer que le côté gauche. Il y a huit cas de ce type pour les quatre côtés. Il y a également trois autres cas pour notre système de défilement Amiga : lorsque l'écran défile vers le bas, nous redémarrons la mémoire de l'écran comme s'il s'agissait d'un tonneau rotatif. Si un graphisme doit traverser la limite, nous devons tracer le haut du graphisme en bas de l'écran, et le bas du graphisme en haut ! Le système d'affichage de l'écran recoudra le tout. Là encore, notre objet peut traverser les bords gauche ou droit.

Restauration

Lorsque nous traçons des graphismes sur l'écran, nous devons enregistrer les emplacements de la mémoire de l'écran que nous avons modifiés afin de pouvoir préparer l'écran pour son prochain affichage. Que nous ayons deux ou trois tampons d'affichage, nous devons conserver une liste de restauration pour chacun d'entre eux. Les routines de tracé ont calculé les emplacements de l'écran qu'elles modifient, il est donc logique que nous enregistrions simplement l'adresse en mémoire, ainsi que la largeur et la hauteur que nous avons modifiées.

Une fois de plus, l'écran à barillet peut nécessiter deux tampons de restauration pour un seul objet. Il n'y avait pas besoin d'une liste liée pour les conserver, un simple tableau était tout ce dont nous avions besoin.

Le système de restauration peut à nouveau être confié au Blitter puisqu'il s'agit simplement de copier des rectangles de la mémoire tampon vierge vers la mémoire tampon invisible. Certains peuvent se chevaucher, mais cela prendrait plus de temps que de faire les zones qui se chevauchent plus d'une fois. Nous n'avons pas le temps de copier l'intégralité du tampon vierge. Les graphismes d'une image pourraient ne couvrir que 15% de la surface de l'écran si vous les disposiez tous proprement, nous avons donc réduit la tâche à 15% de ce qu'elle pourrait être.

Variations

La façon dont vous organisez vos couleurs dans la palette peut vous aider à réaliser des tours de passe-passe avec les routines de traçage. Les machines d'arcade nous ont montré qu'un changement de palette d'un ensemble normal de couleurs à, disons, une palette teintée d'orange peut vous indiquer qu'un ennemi est endommagé ou a été touché. Pour ce faire, il suffisait de régler le sprite pour qu'il utilise une deuxième palette teintée.

Tout comme le choix de votre palette est fondamental pour ce que vous pourrez dessiner, la séquence de ces couleurs est également importante. Séparer les plans de bits signifie que vous pouvez écrire sélectivement sur un ou plusieurs d'entre eux, ou modifier l'un d'entre eux pour changer les couleurs qui sont écrites.

J'ai essayé de laisser les graphistes choisir les couleurs de la palette, mais je leur ai toujours demandé d'organiser les couleurs de manière ordonnée plutôt qu'arbitraire. Cela m'a permis de réaliser quelques astuces graphiques dans les routines de traçage.

Ombres

La façon la plus simple de créer des ombres est de tracer une forme noire du sprite sous le sprite réel, décalée de quelques pixels vers le bas et la droite, ou à l'opposé de l'endroit où vous avez placé la source de lumière dans vos images d'objets. Si vous tracez cela une image sur deux, et rien du tout dans les images intermédiaires, cela permet aux couleurs de l'arrière-plan de transparaître, mais elles apparaissent assombries. Le scintillement à 25 images par seconde n'est pas trop grave. En définissant le noir comme couleur zéro dans votre palette, vous pouvez tracer en couleur zéro très rapidement car tout ce que vous avez à faire est d'appliquer le masque à l'écran d'arrière-plan et il n'y a pas de données à ajouter. Le travail est fait.

Si vous organisez vos couleurs par paires de manière à ce que la couleur inférieure soit plus foncée que la couleur supérieure tout au long de la palette, vous pouvez supprimer les données dans le plan binaire le plus bas et laisser les autres tranquilles pour obtenir une couleur plus foncée. Vous pouvez ensuite tracer ce graphisme à chaque image, car c'est assez rapide à faire, et votre ombre ne vacille plus. J'ai utilisé cette méthode dans Uridium 2 version AGA. Nous devions éviter d'utiliser la couleur 1 dans les arrière-plans car elle devenait la couleur de l'espace lorsqu'une ombre passait dessus.

Blanc

Une astuce d'arcade courante consiste à faire clignoter un objet, généralement en changeant de palette, mais nous pouvons le faire en réglant toutes les données du plan de bits sur les mêmes valeurs, ce qui donne à tous les pixels la couleur supérieure de la palette, que nous avons réglée sur le blanc. Pour ce faire, nous pouvons utiliser les données du masque inversées en tant que données graphiques, et nous n'avons pas besoin de masque du tout puisque nous réglons chaque bit de notre graphisme sur "1" pour obtenir la couleur supérieure lorsque n'importe quelle couleur existe dans le graphisme. Pour le Blitter, nous pouvons utiliser le masque déjà inversé comme données dans tous les plans de bits, c'est aussi plus rapide qu'un tracé normal car il n'y a que deux sources, et non trois.

Glace bleue

D'une manière légèrement plus sophistiquée que le traceur blanc, nous avons arrangé les couleurs pour notre jeu Fire And Ice en quatre blocs de quatre couleurs, encore une fois avec le blanc comme couleur la plus haute, et les nuances de bleu sous le blanc, s'assombrissant au fur et à mesure que les couleurs descendent. Nous pouvions faire varier les autres groupes de quatre couleurs en fonction du niveau. Pour tracer un objet dans la seule gamme des quatre premiers bleus au blanc, nous avons tracé les deux premiers plans de bits avec le masque au lieu des données pour forcer les bits à être définis, puis nous avons tracé les deux premiers plans de bits avec les vraies données graphiques. Les couleurs 0, 4, 8 et 12 deviennent la couleur 12, les couleurs 1, 5, 9 et 13 deviennent 13, etc. Cela m'a permis d'avoir une version figée de tous les objets dans n'importe quelle pose sans avoir à les dessiner ou à les stocker.

Traceur de pixels

Nous disposions également d'une routine de traçage pour tracer un seul pixel, appelée "PlotSpot". Il était plus rapide de tracer le pixel dans le code que de configurer le Blitter. Nous avions également une variante pour les ombres. Le traceur de pixels a été utilisé pour les armes à particules dans Paradroid 90 et pour la pluie et la neige dans les nuages de tempête Fire And Ice.

Priorités et niveaux

Une dernière chose à propos des routines de tracé est qu'il est bon de contrôler l'ordre dans lequel vous tracez vos objets sur l'écran. Pour un jeu 3D sur PC ou console, la séquence est décidée initialement par la position de la caméra, et nous dessinerons les objets de loin à près. L'utilisation d'un tampon Z (de profondeur) nous permet d'éviter cela car il contient une distance pour le pixel courant tracé à chaque position sur l'écran, et seuls les pixels plus proches que le pixel courant sont tracés. Cela fonctionne jusqu'à ce que vous commenciez à utiliser une transparence partielle ! Toutes les superpositions d'écran sont ajoutées à la fin, le tampon Z étant désactivé.

Pour les jeux en 2D, vous pouvez contrôler un peu mieux la séquence de traçage. Il est généralement préférable que le joueur principal soit toujours au premier plan, à moins que vous ne souhaitiez que le graphisme soit placé derrière un élément de décor, sur lequel vous tracerez par la suite. En fait, dans Paradroid 90, les objets utilisaient la priorité d'affichage comme hauteur au-dessus du sol, ce qui déterminait ensuite le décalage des pixels X et Y par rapport à l'ombre.

Nous avons mis en place un système avec 16 couches arbitraires, appelées priorités d'affichage. Chaque objet du jeu n'a généralement pas besoin de changer de couche, elle est donc définie au moment de la configuration de l'objet, bien qu'il soit possible de la modifier en vol, par exemple lorsque la tête d'un robot Paradroid 90 tombe au sol. Tous les objets sont mis à jour dans un ordre largement arbitraire, bien que nous ayons trouvé que c'était une bonne idée de faire le joueur en premier car il définit la position de défilement, qui définit la position de tracé de l'écran pour tout le reste. Lorsqu'un objet est mis à jour, sa position à l'écran est calculée et nous le plaçons dans l'une des 16 listes liées à l'écran en fonction de sa priorité d'affichage.

Une fois que tous les objets ont été mis à jour, nous pouvons parcourir les listes liées de tracés dans l'ordre, en commençant par le plus bas, et afficher les graphismes à l'écran. Cela permet de contrôler complètement la séquence de traçage, car tout se fait à un seul rythme, plus ou moins. Techniquement, puisque certains tracés sont effectués avec le Blitter et d'autres avec le processeur, nous pourrions avoir des données tracées hors séquence, mais puisque le préambule dans les routines de tracé doit faire toutes les vérifications d'écrêtage et les calculs d'adresse, alors le tracé précédent est susceptible d'être achevé. Vous pourriez mettre une vérification "WaitForBlitter" dans les routines de tracé sans scintillement... Je n'ai jamais remarqué de problème.

Sprites matériels dans le mélange

Les sprites matériels Amiga peuvent être placés entre les champs de jeu, ou au-dessus, ou au-dessous. Il est préférable de les utiliser dans un seul but plutôt que de les mélanger arbitrairement avec les objets tracés par le logiciel. Je les ai utilisés pour les superpositions de scores dans Fire And Ice, et je les aurais utilisés pour le personnage, Coyote, sauf que je voulais qu'il aille derrière certains décors et devant d'autres. C'est l'une de ces bonnes idées qui a été abandonnée très tôt.

Dans Uridium 2, nous avions un meilleur multiplexeur de sprites et nous pouvions utiliser les sprites matériels pour certains objets de 16 pixels de large. Le plexeur a des limites sur le nombre d'objets que vous pouvez tracer sur une ligne horizontalement (probablement trois, puisque j'en utilisais un pour les étoiles de fond), donc bien que les sprites matériels soient préférés pour la vitesse, il doit y avoir un plan de secours pour tracer tous les objets dans le logiciel qui dépassent les capacités du plexeur. Cela se fait image par image.

Pour un sprite matériel, il suffit de copier le graphisme dans le tampon du sprite et de définir la position X et Y. Notez qu'en plus des priorités d'affichage des objets, nous devons également trier les sprites matériels dans une séquence de position Y vers le bas de l'écran. Si nous conservons tous les objets susceptibles d'être des sprites matériels dans une seule couche, nous pouvons nous permettre d'effectuer une recherche spécialisée et d'insérer cette couche de tracé en fonction de la position Y de l'objet, plutôt que de toujours le placer en tête de liste.

Conclusions

N'oubliez pas qu'avec l'assembleur, vous travaillez à un niveau très bas. Chaque instruction ne peut lire ou écrire que 1, 2 ou 4 octets consécutifs ou combiner un couple de nombres de différentes manières. Écrire un jeu complet, c'est comme construire un avion à partir de pièces détachées, éventuellement sans plan !

Tout ce code assembleur est tellement plus facile que de définir les coordonnées X et Y d'un sprite C64 dans quelques registres de la puce (mode sarcasme : annuler). Merci, Kryten. La puce graphique du C64 a fait beaucoup de travail pour nous au niveau de l'affichage, presque sans effort. Seules les machines d'arcade sont allées plus loin avec leurs puces personnalisées.


[Retour en haut] / [Retour aux articles]