Obligement - L'Amiga au maximum

Jeudi 25 avril 2024 - 07:38  

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

 


Programmation : C - Gestion des VSprites sous Workbench
(Article écrit par Pascal Amiable et extrait d'Amiga News Tech - octobre 1991)


Suite au dernier article sur la gestion des sprites matériels, nous allons ce mois-ci poursuivre notre exploration du monde de l'animation sur Amiga.

Le mois dernier, nous avons vu qu'il était possible d'animer jusqu'à huit sprites matériels simultanément sur l'écran. Mais que pouvons-nous faire si nous désirons en avoir plus ? Eh bien il existe une solution, ce sont les VSprites, pour "Virtual Sprite".

Les VSprites, qui sont-ils ?

Le VSprite est la plus petite entité logicielle utilisable pour l'animation. Il repose d'ailleurs presque entièrement sur les sprites matériels. Lorsque vous réservez un sprite matériels, celui-ci vous appartient entièrement, jusqu'à ce que vous indiquiez explicitement au système que vous le libérez (par la fonction FreeSprite). Avec un VSprite, c'est différent. Le système prend à sa charge la gestion de la partie matérielle, c'est-à-dire seulement lorsque vous décidez d'afficher ce VSprite à l'écran. Il n'allouera à ce VSprite un vrai sprite matériel que durant le temps nécessaire à son affichage. Cela signifie que vous pouvez très bien afficher trois VSprites en utilisant le même sprite matériel si ceux-ci sont suffisamment bien disposés.

Du point de vue programmation, un VSprite est représenté par une structure C qui définit sa taille, son aspect, ses couleurs, ses coordonnées à l'écran et la conduite à tenir en cas collision.

Pour créer un VSprite (Cf. programme ci-joint) les étapes à réaliser sont donc les suivantes :
  • Initialiser le système GEL (Graphic ELements) une bonne fois pour toute avec la fonction InitGel().
  • Définir le VSprite (hauteur, position à l'écran, image, couleurs, drapeaux).
  • Ajouter le VSprite à la liste des GEL.
Il est alors possible de changer sa forme, sa couleur ou sa position en modifiant les paramètres adéquats associés à l'élément graphique. Je vous conseille d'étudier le programme ci-dessous qui reprend un à un les points cités ci-dessus.

/*****************************************************************/
/*  Programme de gestion de Vsprites sous Workbench              */
/*                                                               */
/*  Pprogrammation des VSprites sous Intuition & Graphics        */
/*         - VSprites                                            */
/*         - Detection de collisions (initialisation)            */
/*         - Gestion de la souris                                */
/*         - Création de structures Image                        */
/*                                    P. AMIABLE 1991            */
/* ------------------------------------------------------------- */

/* --------------------------------------------------------------*/
/*  Quelques includes utiles......                               */
/* --------------------------------------------------------------*/
#include  exec/types.h>
#include  exec/memory.h>
#include  intuition/intuition.h>
#include  stdio.h>
#include  graphics/gels.h>
#include  graphics/gfxmacros.h>

/* --------------------------------------------------------------*/
/*  Les defines maintenant...                                    */
/* --------------------------------------------------------------*/
#define INTUITION_REV 0L /* Version d'Intuition (la dernière)    */
#define GFX_REV       0L /* Version de Graphics (la dernière)    */
#define NBRSPRITES    10 /* Nb VSprites affichés simultanément   */

/* --------------------------------------------------------------*/
/*  Définition des variables externes                            */
/* --------------------------------------------------------------*/

/* Declararation des fonctions définies dans le programme */
void main(), referme(), init();
void detruit_vsprites();
void ouvrefenetre();
void refermegel();
int initgel();
void graphique();
void deplace();
int bidon();

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Window *fenetre = NULL;
struct Screen *ecran = NULL;
struct RastPort *rastport = NULL;
struct ViewPort *viewport  = NULL;
struct VSprite *tete = NULL;
struct VSprite *queue = NULL;

struct NewScreen nouvecran = {
	0, 0,         /* LeftEdge, TopEdge                       */
	320, 256,     /* Width, Height                           */
	5,            /*  Depth, soit 32 couleurs possibles      */ 
	1, 0,         /* DetailPen, BlockPen                     */
	SPRITES,      /* ViewModes valeur 0 = basse resolution   */
	CUSTOMSCREEN, /* Type d'ecran                            */
	NULL,         /* Font -> NULL = fonte par defaut         */
	"titre ",     /* DefaultTitle pour le titre -> aucun     */
	NULL,         /* gadgets, aucun                          */
	NULL };       /* adresse de la CustomBitmap -> aucune ici*/

struct NewWindow nouvfenetre =
{
	0, 0,              /* LeftEdge, TopEdge                  */
	150, 15,           /* Width, Height                      */
	0, 1,              /* DetailPen, BlockPen                */
	NULL,              /* IDCMPFlags                         */
	SMART_REFRESH|     /* Flags                              */
	     ACTIVATE,
	NULL,              /* FirstGadget                        */
	NULL,              /* CheckMark                          */
	"Virtual Sprites", /* Title                              */
	NULL,              /* Screen                             */
	NULL,              /* BitMap                             */
	150,               /* MinWidth                           */
	15,                /* MinHeight                          */
	150,               /* MaxWidth                           */
	15,                /* MaxHeight                          */
	CUSTOMSCREEN       /* Type                               */
};

SHORT vitesse[]={ 1, 2, -1, -2 }; /* Echelle de vitesse utilisée */
SHORT xmouv[NBRSPRITES], ymouv[NBRSPRITES];     /* Directions    */
short max_cree = 0;              /* nombre maxi de sprites crées */
struct VSprite *vsprite[NBRSPRITES];
struct GelsInfo gelinfo;

/* Données du sprite */
UWORD chip sprite[]=
{
	0x0000,0x3000,0x0000,0x7800,0x0000,0xcc00,0x0000,0xcc00,
	0x0000,0xcc00,0x0460,0xfc60,0x067e,0xfe00,0x077e,0xcf00,
	0x07f8,0xcfe0,0x06f8,0xcee0,0x0678,0xce60,0x0678,0x0660,
	0x0678,0x0660,0x0018,0x0000
};

UWORD tablecouleur[] = {
	0x0000,0x0e30,0x0fff,0x0b40,0x0fb0,0x0bf0,0x05d0,0x0ed0,
	0x07df,0x069f,0x0c0e,0x0f2e,0x0feb,0x0c98,0x0bbb,0x07df,
	0x0000,0x0e30,0x0fff,0x0b40,0x0fb0,0x0bf0,0x05d0,0x0ed0,
	0x07df,0x069f,0x0c0e,0x0f2e,0x0feb,0x0c98,0x0bbb,0x07df
};

UWORD palette0[] = { 0x0e30, 0xffff, 0x0b40 };
UWORD palette1[] = { 0x0bf0, 0x05d0, 0x0ed0 };
UWORD palette2[] = { 0x069f, 0x0c0e, 0x0f2e };
UWORD palette3[] = { 0x0c98, 0x0bbb, 0x07df };
UWORD *palette[] = { palette0, palette1, palette2, palette3 };
int choix_couleur;

/* Port A du CIA dont le bit - bouton gauche de la souris */
char *bouton_gauche = (char *) 0xbfe001;

/* --------------------------------------------------------------*/
/*         Programme principal                                   */
/* --------------------------------------------------------------*/
void main()
{
int i = 0;

	init();             /* Ouverture des bibliothèques système   */
	ouvrefenetre();     /* Ouverture de l'écran et de la fenêtre */
	initgel();          /* initialisation du système GEL         */
	graphique();

	while(!((*bouton_gauche & 0x40)-64))
	{	deplace();      /* On bouge les sprites                  */
		WaitTOF();      /* Attente de trame                      */
	}

	for(i = 0; i   max_cree; i++)
		detruit_vsprites(vsprite[i]); /* Détruit les VSprites    */

	refermegel();           /* on désalloue la structure gelinfo */
	referme();              /* on referme le reste               */
}

/* --------------------------------------------------------------*/
/*  Init() Ouvre la bibliothèque                                 */
/* --------------------------------------------------------------*/
void init()
{
char *OpenLibrary();

	IntuitionBase = (struct IntuitionBase *)
	  OpenLibrary("intuition.library",INTUITION_REV);
	if(!IntuitionBase)
		exit(FALSE);

	GfxBase = (struct GfxBase *)
	  OpenLibrary("graphics.library",GFX_REV);
	if(!GfxBase)
	{	referme(); 
		exit(FALSE);
	}
}
 
/* --------------------------------------------------------------*/
/*  ouvrefenetre() ouvre la fenetre et l'ecran                   */
/* --------------------------------------------------------------*/

void ouvrefenetre()
{
void referme();

	if(!(ecran = (struct Screen*)OpenScreen(&nouvecran)))
	{	referme();
		exit(FALSE);
	}
	nouvfenetre.Screen = ecran;

	if(!(fenetre=(struct Window*)OpenWindow(&nouvfenetre)))
	{	referme();
		exit(FALSE);
	}

	rastport = fenetre->RPort;
	viewport = (struct ViewPort *)ViewPortAddress(fenetre);
	LoadRGB4(viewport, &tablecouleur[0], 32);
}

/* --------------------------------------------------------------*/
/*  Cette fonction referme la fenetre et les bibliothèques       */
/* --------------------------------------------------------------*/
void referme()
{
	if(fenetre)       CloseWindow(fenetre);
	if(ecran)         CloseScreen(ecran);
	if(IntuitionBase) CloseLibrary(IntuitionBase);
	if(GfxBase)       CloseLibrary(IntuitionBase);
}

/* --------------------------------------------------------------*/
/*  Cette fonction déplace les max_cree sprites                  */
/* --------------------------------------------------------------*/
void deplace()
{
short i;

	for (i=0; i max_cree; i++)
	{	vsprite[i]->X = xmouv[i]+vsprite[i]->X;
		vsprite[i]->Y = ymouv[i]+vsprite[i]->Y;

		/* Test de dépassement de l'écran */
		if(vsprite[i]->X >= 290 || vsprite[i]->X  = 0)
			xmouv[i]=-xmouv[i];
		if(vsprite[i]->Y >= 230 || vsprite[i]->Y  = 0)
			ymouv[i]=-ymouv[i];
	}

	SortGList(rastport);   /* On réordonne la liste des VSprites */
	DrawGList(rastport, viewport);

	MakeScreen(ecran);  /* on régénère l'écran                   */
	RethinkDisplay();   /* et on visualise le tout               */
}

/* --------------------------------------------------------------*/
/*  Routine appelée lors de la détection de collision            */
/* --------------------------------------------------------------*/
/* on étudiera cela plus en détail le mois prochain */
int bidon()
{
	return(0);	/* pour l'instant, on ne fait rien...            */
}

/* --------------------------------------------------------------*/
/*  Cette fonction initialise la structure Gels.                 */
/* --------------------------------------------------------------*/
int initgel()
{
	if ((tete = (struct VSprite *)AllocMem(sizeof(struct VSprite),
	  MEMF_PUBLIC | MEMF_CLEAR)) == 0)
		return(-1);

	if ((queue = (struct VSprite *)AllocMem(sizeof(struct VSprite),
	  MEMF_PUBLIC | MEMF_CLEAR)) == 0)
	{	refermegel();
		FreeMem(tete, sizeof(struct VSprite));
		return(-2);
	}

	/* Les sprites 0 et 1 sont réservés pour Intuition           */
	gelinfo.sprRsrvd = 0xFC;

	if ((gelinfo.nextLine = (WORD *)AllocMem(sizeof(WORD) * 8,
	  MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
	{	refermegel();
		FreeMem(tete, sizeof(struct VSprite));
		FreeMem(queue, sizeof(struct VSprite));
		return(-3);
	}
 
	if ((gelinfo.lastColor = (WORD **)AllocMem(sizeof(LONG) * 8,
	  MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
	{	refermegel();
		FreeMem(tete, sizeof(struct VSprite));
		FreeMem(queue, sizeof(struct VSprite));
		return(-4);
	}

	/* On prépare une table de pointeurs vers des routines qui
	 * seront exécutées quand la fonction DoCollision détectera
	 * une collision.
	 * Nous étudierons le fonctionnement d'un tel système en
	 * détails le mois prochain
	 */
	if (!(gelinfo.collHandler = (struct collTable *)
	  AllocMem(sizeof(struct collTable), MEMF_PUBLIC|MEMF_CLEAR)))
	{	refermegel();
		FreeMem(tete, sizeof(struct VSprite));
		FreeMem(queue, sizeof(struct VSprite));
		return(-5);
	}

	/* quand une partie d'un objet passe à travers les frontières,
	 * il déclenche l'appel à la routine de gestion de collision
	 * (pour le moment, bidon())
	 */
	gelinfo.leftmost = 0;
	gelinfo.rightmost = rastport->BitMap->BytesPerRow * 8 - 1;
	gelinfo.topmost = 0;
	gelinfo.bottommost = rastport->BitMap->Rows - 1;

	rastport->GelsInfo = &gelinfo;
	InitGels(tete, queue, &gelinfo);
	SetCollision(0, bidon, &gelinfo);
	WaitTOF();
}

/* ------------------------------------------------------------- */
/*  Cette fonction désalloue la structure gels .                 */
/* ------------------------------------------------------------- */
void refermegel()
{
	if (gelinfo.collHandler)
		FreeMem(gelinfo.collHandler, sizeof(struct collTable));
	if (gelinfo.lastColor)
		FreeMem(gelinfo.lastColor, sizeof(LONG) * 8);
	if (gelinfo.nextLine)
		FreeMem(gelinfo.nextLine, sizeof(WORD) * 8);
	if (gelinfo.gelHead)
		FreeMem(gelinfo.gelHead, sizeof(struct VSprite));
	if (gelinfo.gelTail)
		FreeMem(gelinfo.gelTail, sizeof(struct VSprite));
}

/* --------------------------------------------------------------*/
/*  Cette fonction crée un VSprite.                              */
/* --------------------------------------------------------------*/
struct VSprite *cree_vsprites(hauteur, image, tablecol, x, y)
SHORT hauteur;  /* hauteur du VSprite en nombre de lignes        */
WORD *image;    /* dessin du VSprite (c'est une table de mots)   */
WORD *tablecol; /* couleurs du VSPrite                           */
SHORT x, y;     /* position intiale du sprite                    */
{
struct VSprite *vsprite;

	if ((vsprite=(struct VSprite *)AllocMem(sizeof(struct VSprite),
	  MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
		return(0);

	vsprite->Flags  = VSPRITE; /* C'est un VSprite et non un Bob */
	vsprite->Y      = y;
	vsprite->X      = x;
	vsprite->Height = hauteur;
	vsprite->Width  = 1;  /* Toujours 16 pixels (1 mot) de large */
	vsprite->Depth  = 2;  /* Toujours quatre couleurs            */
	vsprite->MeMask = 1;  /* sert à la détection de collision    */
	vsprite->HitMask = 1;
	vsprite->ImageData = image;	/* on associe l'image au vsprite */

	if ((vsprite->BorderLine = (WORD *)AllocMem(sizeof(WORD),
	  MEMF_PUBLIC | MEMF_CLEAR)) == 0)
	{	FreeMem(vsprite, sizeof(struct VSprite));
		return(0);
	}

	if ((vsprite->CollMask = (WORD *)AllocMem(sizeof(WORD)*hauteur,
	  MEMF_CHIP | MEMF_CLEAR)) == 0)
	{	FreeMem(vsprite, sizeof(struct VSprite));
		FreeMem(vsprite->BorderLine, sizeof(WORD));
		return(0);
	}

	vsprite->SprColors  = tablecol;
	vsprite->PlanePick  = 0x00;
	vsprite->PlaneOnOff = 0x00;

	InitMasks(vsprite);
	return(vsprite);
}

/* --------------------------------------------------------------*/
/*  Cette fonction détruit un VSprite et libére ses ressources   */
/* --------------------------------------------------------------*/
void detruit_vsprites(vsprite)
struct VSprite *vsprite;
{
register long VMEM;
register APTR ptr;

	if (vsprite != NULL)
	{	VMEM = vsprite->Width * vsprite->Height * vsprite->Depth;
		if (vsprite->VSBob != NULL)
		{	if (vsprite->VSBob->SaveBuffer != NULL)
				FreeMem(vsprite->VSBob->SaveBuffer, sizeof(SHORT) * VMEM);
			if (vsprite->VSBob->DBuffer != NULL)
			{	if (vsprite->VSBob->DBuffer->BufBuffer != 0)
					FreeMem(vsprite->VSBob->DBuffer->BufBuffer, sizeof(SHORT) * VMEM);
				FreeMem(vsprite->VSBob->DBuffer, sizeof(struct DBufPacket));
			}
			FreeMem( vsprite->VSBob, sizeof(struct Bob));
		}
		if (vsprite->CollMask != NULL)
			FreeMem(vsprite->CollMask, sizeof(WORD)*vsprite->Height*vsprite->Width);
		if (vsprite->BorderLine != NULL)
			FreeMem(vsprite->BorderLine, sizeof(WORD)*vsprite->Width);
		FreeMem(vsprite, sizeof(struct VSprite));
	}
}

/* --------------------------------------------------------------*/
/*  Cette fonction crée l'ensemble des éléments graphiques       */
/* --------------------------------------------------------------*/
void graphique()
{
int erreur, i, x, y;

	erreur = initgel(&gelinfo, rastport);

	for(i=0; i   NBRSPRITES; i++)
	{	x = 10 + RangeRand(280);
		y = 10 + RangeRand(230);

		xmouv[i] = vitesse[RangeRand(4)];
		ymouv[i] = vitesse[RangeRand(4)];

		vsprite[i] = cree_vsprites(14,sprite,
		                           palette[choix_couleur], x, y);
		if(vsprite[i] == 0)
			break;

		AddVSprite(vsprite[i], rastport);

		max_cree++;
		choix_couleur++;
		if(choix_couleur >= 4)
			choix_couleur = 0;
	}
}

Le système d'animation de l'Amiga, dénommé GELS (pour Graphics ELements System), est constitué d'un certain nombre de couches logicielles superposées, chacune utilisable indépendamment des autres. Ainsi, lorsque nous avions étudié les sprites matériels (simple sprites), nous avons utilisé la couche la plus basse du GELS qui consiste littéralement en une interface pour piloter les circuits spécialisés de l'Amiga.

En programmant des VSprites, nous avons utilisé la couche supérieure du GELS : en effet, un VSprite n'existe pas physiquement, il ne s'agit que d'une représentation virtuelle (d'où son nom !) qui est utilisée par le GELS pour créer, animer et détruire des "simple sprites" à l'écran. Cette phase de création, animation et destruction n'étant plus contrôlable par l'utilisateur, mais gérée automatiquement par le système.

Le "simple sprite" alloué pour un VSprite ne l'est que le temps nécessaire à sa visualisation, ce qui permet d'avoir plus de huit VSprites à l'écran, pour peu qu'ils ne soient pas positionnés à plus de huit sur les mêmes lignes au même instant.

Un VSprite possède une structure de données associée contenant la position du sprite, sa taille, son image et ses couleurs propres, ce qui permet au système d'animation de travailler convenablement.

Avantages et inconvénients

Le gros avantage d'utiliser les VSprites est que l'on a plus à se préoccuper exactement de la manière d'allouer les sprites matériels : on indique seulement où les sprites doivent apparaître et le GELS fait le reste. Autre avantage, la possibilité d'utiliser plus de huit VSprites en même temps, sachant que le système peut réutiliser le même sprite matériel pour afficher deux objets différents à des endroits différents de l'écran.

Malheureusement, il n'y a pas que des avantages dans l'utilisation des VSprites et un certain nombre de contraintes sont à prendre en compte si l'on ne veut pas avoir la désagréable surprise de voir son programme fonctionner de manière stochastique...

Comme mentionné plus haut, le matériel de l'Amiga n'autorise que huit "vrais" sprites maximum. Cela signifie que si l'on demande au système d'afficher plus de huit VSprites à une même coordonnée, certains ne seront pas affiché. C'est comme cela et on y peut rien. Mais là où le problème se corse (comme disait Napoléon), c'est que, pratiquement, on ne peut pas allouer les huit sprites : le sprite 0 est réservé à Intuition pour afficher le pointeur de souris, il est donc inutilisable. Et comme le sprite 1 lui est associé (les sprites matériels allant par paire), il est également déconseillé de s'en servir. En effet, cette paire de sprites utilise les mêmes registres de couleur (17 à 19, le 16 étant considéré comme transparent). Toute modification de la couleur du sprite 1 entraînera donc une modification de celle du sprite 0 et vous aurez la désagréable surprise de voir clignoter votre pointeur de souris.

Un deuxième problème peut survenir dans le cas de superposition des sprites : il faut savoir que les sprites matériels, lorsqu'ils se superposent, se cachent mutuellement suivant un ordre de priorité bien établi. Celui ayant le plus faible numéro étant toujours "au-dessus" de l'autre (c'est pour cela que le pointeur de souris ne peut jamais être caché). Quand l'on utilise des VSprites, le système graphique associe arbitrairement un numéro de sprite à chaque VSprite, et ce dynamiquement. Cette allocation dont l'utilisateur n'est pas maître pose donc deux problèmes :
  • On ne sait pas quel sprite passera "au-dessus" de l'autre.
  • Il peut arriver que, lors d'un changement d'assignation, il y ait basculement des deux sprites, ce qui a pour effet de les permuter à l'écran.
Troisième contrainte, si tous vos VSprites utilisent des couleurs différentes, vous ne pouvez pas avoir au maximum huit sprites mais seulement quatre. Pourquoi ? Eh bien c'est fort simple : comme chaque sprite d'une paire utilise les mêmes registres de couleurs que son petit copain, le système ne peut afficher les huit sur une même ligne... Pour se simplifier la tâche, il n'en affiche que quatre.

Enfin, quatrième contrainte, mais qui est propre à l'utilisation des sprites en général, plus l'on utilise de sprites, moins l'on a de couleurs disponibles pour le champ de jeu. N'oublions pas que les circuits de gestion des sprites matériels utilisent les registres de couleurs 17 à 19, 21 à 23, 25 à 27, 29 à 31, qu'il ne faudra donc pas utiliser pour le champ de jeu, ou alors très judicieusement.

GELS

Que vous désiriez utiliser des VSprites, des BOB ou tout autre objet géré par le GELS, il faudra commencer par l'initialiser. Le système d'animation graphique tient à jour une liste chaînée des éléments graphiques à visualiser, liste qui doit toujours au minimum contenir deux éléments "bidons", c'est-à-dire deux VSprites qui ne seront jamais représentés à l'écran, mais qui servent au GELS à repérer facilement le début et la fin de la liste. Ces VSprites sont appelés "sprite de tête" et "sprite de queue" puisque tous les objets créés ensuite seront insérés entre eux. La première chose qu'il faut faire est donc créer cette liste de deux éléments bidons.

Par défaut, le système de gestion des sprites s'alloue tous les sprites disponibles, y compris le sprite 1, ce qui, nous l'avons vu précédemment, peut entraîner des problèmes avec le pointeur de souris. Pour palier à cela, il suffit d'indiquer quels sprites doivent être réservés par le système : il existe un champ dans la structure "GelsInfo" qui permet cela, le champ "sprRsrvd". Ainsi, pour réserver les sprites 2 à 7, on tapera la ligne suivante :

struct GelsInfo *gel;
       gel->sprRsrvd = 0xFC; /* en binaire %11111100 */

Si l'on veut réserver le maximum de sprites disponibles (hors les sprites 0 et 1), il faudra se renseigner au préalable quels sont les sprites utilisés par d'autres tâches (pour éviter les conflits). On est capable de savoir quels sont les sprites effectivement réservés par d'autres tâches en regardant le champ SpriteReserved de la structure GfxBase. Chaque sprite est visualisé par un bit de ce champ : si le bit est à 1, le sprite correspondant est réservé.

Pour s'allouer les sprites encore disponible on tapera donc :

gel->sprRsrvd = 0xFC & (!(GfxBase->SpriteReserved)),

Le système d'animation a besoin de certaines données d'entrée pour décider quel sprite matériel il va utiliser pour visualiser le prochain VSprite. Ces variables d'état sont placées dans la structure GelsInfo et comprennent deux tableaux, nextLine et lastColor.

Dans nextLine, le système stocke le numéro de la prochaine ligne écran ou sera disponible chaque sprite matériel. Ceci lui permet de savoir quels sont les sprites matériels qui peuvent être candidats pour afficher un VSprite à une position donnée, et ceux qui ne peuvent le faire car déjà occupés.

Dans lastColor, le système stocke pour chaque sprite matériel un pointeur vers le jeu de couleurs utilisées en dernier. Ainsi, lorsqu'un VSprite a besoin d'être utilisé, le système recherche dans le tableau lastColor et en fonction des sprites susceptibles d'être utilisés, quel sprite matériel possède le même jeu de couleurs que le VSprite à afficher. S'il en existe un, il l'utilise en premier car cela évite des modification des registres de couleurs associés au sprite, très coûteuses en temps-machine.

Ces deux champs de la structure GelsInfo doivent bien entendu être alloués dans votre programme, ce qui se fera sans problème de la manière suivante :

gel->nextLine = (WORD *)AllocMem(sizeof(WORD) * 8, MEMF PUBLIC|MEMF_CLEAR));

et :

gel->lastColor = (WORD *)AllocMem(sizeof(WORD) * 8, MEMF_PUBLIC|MEMF_CLEAR));

Création du VSprite

La création d'un VSprite s'effectue de manière simple. La première étape consiste à remplir une structure VSprite, soit déclarée statiquement, soit allouée dynamiquement avec AllocMem(). Cette structure possède un certain nombre de champs dont certains ont les mêmes fonctions que ceux de la structure SimpleSprite décrite dans un précédent numéro.

Pour placer à l'écran un VSprite, il faut d'abord indiquer sa position dans les champs v->X et v->Y. Ensuite, sa largeur et sa hauteur seront placées dans v->Width (la largeur s'exprime en mots de 16 bit et un VSprite a toujours une largeur de 16 pixels, donc de 1 mot) et y->Height. La profondeur v->Depth doit également être indiquée : pour un VSprite, la profondeur est toujours égale à 2, mais on peut avoir plus de couleur avec un BOB (qui utilise la même structure). On associe ensuite l'image du sprite au champ v->ImageData et sa couleur au champ v->SprColors.

On continue en mettant dans le champ v->Flag la valeur VSPRITE pour indiquer qu'il s'agit d'un VSprite et non d'un BOB, et on termine allègrement par la gestion des collisions :
  • En mettant la valeur 1 dans v->MeMask et v->HitMask afin d'avoir une détection de collision sur les bordures de l'écran.
  • En réservant de la mémoire pour le champ v->BorderLine, qui contiendra une image rectangulaire, sur un seul plan de bits, du VSprite afin de permettre une détection plus rapide, bien qu'approximative, des collisions.
  • En réservant également de la mémoire pour le champ v->CollMask qui contiendra une image de la projection du VSprite sur un plan de bits afin de faire des détections exactes de collision.
Que reste-t-il à faire ? Presque rien, sinon mettre à 0 les champs v->PlanePick et v->PlaneOnOff qui ne servent que pour les BOB et appeler la fonction InitMasks() de la graphics.library, qui finira automatiquement le travail en créant effectivement les deux masques CollMask et BorderLine.

Pour ajouter le VSprite ainsi créé, il suffit de faire appel à la fonction AddVSprite() qui fait le travail tout seul. On lui passe en paramètres l'adresse (de la structure) du VSprite à ajouter et celle du RastPort de l'écran visé.

Affichage et déplacement

Nos VSprites sont maintenant dans la liste, tout est donc pour le mieux. Pour déplacer un VSprite, on modifiera les champs v->X et v->Y et on lancera un processus qui consiste à réactualiser l'ensemble de la visualisation pour prendre en compte cette modification de position.

Les VSprites devant être affichés du haut de l'écran vers le bas, il faut commencer par trier la liste des éléments graphiques à afficher, en appelant la fonction SortGList(). On crée ensuite les instructions Copper de visualisation des sprites pour le ViewPort, en appelant la routine DrawGList(), avec comme argument le RastPort et le ViewPort.

Enfin, on demande à Intuition d'effectuer elle-même les modifications sur l'écran et de le réafficher gràce à la séquence MakeScreen()/RethinkDisplay(). Si on n'utilise pas Intuition, MakeVPort() et LoadView() seront mises à contribution.

Fin du travail

Une fois nos VSprites devenus inutiles, il faut les effacer et libérer proprement les ressources utilisées, à savoir la structure "v" elle-même, v->CollMask et v->BorderLine, sans oublier v->VSBob->SaveBuffer, y->VSBob->DBuffer et v->VSBob si notre VSprite était un BOB.

Un petit bout de code valant des fois mieux qu'un long discours, voici la routine permettant de libérer toutes ces ressources.

VSprites

Ensuite on détruira le GELS, ce dernier n'ayant désormais plus de raison d'être. On libérera donc les zones collHandler, lastColor, nextLine, gelHead et gelTail.

Soit par programme :

VSprites

Le mois prochain, nous terminerons cette partie animation sur Amiga par les BOB, ou Blitter Objects. Vous pourrez faire ainsi la comparaison avec les VSprites et utiliser l'un ou l'autre selon la nature de votre application. En attendant, je vous souhaite une bonne lecture et vous dis : "à dans un mois".


[Retour en haut] / [Retour aux articles] [Article précédent]