CODING ★ COURS DE GRAPHISME - CHAPITRE 6 : REAGIR AU TEST DE COLLISION SUR LES COULEURS ★

Graphic - 21 - Reagir Au Test de Collision sur les Couleurs (SOS Programmeurs)

Comment réagir lors d'une rencontre entre 2 sprites ? Une seule réponse : Comme on veut ! Mais pas n'importe comment ... A titre d'exemple , nous poursuivons le développement du même programme comme suit :

Le sprite numéro 6 (Petit missile vert à ailes delta rouges) détruira tout autre sprite lorsqu'il en touchera un lors de son déplacement vers le haut . Une collision vers le bas ou latérale restera inoffensive . Facile à dire mais le faire c'est mieux ! Ce n'est pas aussi évident qu'on le croit.

Puis que seule la collision vers le haut est destructive , seule la sortie de cette routine sera modifiée . Il faudra différencier l'abandon du déplacement par rencontre avec une couleur de la rencontre avec la bordure écran . Cette sortie spécifique établie , il suffira de tester le numéro du sprite actif (Vous voyez qu'il à son utilité ...) , si ce n'est pas le 6 , on continuera comme par le passé , si c'est 6 , il faudra résoudre une série de problèmes :

1 : A ce stade on sait que le sprite numéro 6 vient de rencontrer un octet écran qui contient autre chose que la couleur du fond ET C'EST TOUT . Rien ne prouve en effet que cette couleur tombée du ciel appartienne à un sprite , cela pourrait éventuellement être un élément du décor . Il va donc faloir s'en assurer . Pour ceci , une routine (qui sera présentée plus loin) devra :
A / Mémoriser l'adresse de collision .

B / Tester toutes les positions écran mémorisées dans la table ZONESP pour voir si l'adresse de collision se situe sur l'emplacement de l'un des sprites .

C / Réagir en fonction du résultat obtenu .

2 : Si après ce test on s'apperçoit que le sprite 6 doit détruire celui qu'il vient de rencontrer il faut encore enterrer le cadavre en l'effaçant (par exemple) et le retirer du jeu pour ne pas le réafficher après sa destruction ce qui ferait désordre . L'octet STATSP prend toute sa signification car mis à 0 au lieu de #FF , il informera le programme que ce sprite n'est plus en jeu .


Pour obtenir ce petit miracle , on commencera par modifier la routine ENHAUT comme suit :

;
ENHAUT LD HL,(VISAD) ;Ce qui differe est commente en majuscules .
  LD B,4
TSH1 LD A,H
  ;SUB #C0
  JR NZ,OKHAUT
  LD A,L
  CP #50
  JR C,STOPUP
;
OKHAUT CALL ADSUP ;Monter avant le test couleurs ! Sinon on testerait
;       ;la ligne du sprite et le deplacement serait toujours
;       invalide !
;
;- Test couleur vers le haut VERSION 2 -
;
  LD D,H   ;Copier adresse en cours dans DE pour tester
  LD E,L   ;sans modifier HL
  LD C,LSP   ;Balayer la ligne sur la largeur du sprite
TSTUP LD A,(DE)
  OR A    ;Si contenu écran pas 0 , la ligne est occupee
  JR NZ,STOPCOL ;ON SAUTE AU TEST DU NUMERO DE SPRITE POUR VOIR
  INC DE   ;COMMENT REAGIR A LA COLLISION .
  DEC C
  JR NZ,TSTUP
  DJNZ TSH1
;
;- Deplacer vers le haut -
;
  LD (VISAD),HL
  LD HL,(COINBD)
  CALL ADSUP
  CALL ADSUP
  CALL ADSUP
  CALL ADSUP
  LD (COINBD),HL
;
  LD BC,LSP1
  AND A
  ;SBC HL,BC
  CALL ADINF
  LD (ADPROV),HL
  ;SCF
  RET
;
STOPCOL LD A,(NUMSP)  ;ICI LA SEULE COLLISION QUI NOUS PREOCCUPE EST CELLE
  CP 6    ;DU SPRITE NUMERO 6 AVEC UN AUTRE QUELCONQUE .
  JR NZ,STOPUP  ;SI CE N'EST PAS LE 6 CE N'EST RIEN ON CONTINUE .
  LD (ADCOLLIS),DE ;ON MEMORISE L'ADRESSE DE COLLISION ET ON VA VOIR
  CALL COLIUP   ;SI L'UN DES 25 SPRITES EST TOUCHE . LE CARRY EST
  RET C    ;MIS SI OUI ET ON ARRETE TOUT .
;
STOPUP RES 0,(IY+0) ;SINON LA COULEUR RENCONTREE N'APPARTIENT PAS A UN
  XOR A   ;SPRITE ET ON CONSIDERE QUE C'EST UN OBSTACLE .
  RET    ;Deplacement impossible enlever le bit correspondant
;

Ceci est très simple à comprendre mais reste a considérer la routine COLIUP qui est plus subtile il faudra en effet la rendre très rapide , de toute manière elle ralentira toujours le programme mais cela ne doit pas être décelable à l'œil nu ! Pour mieux comprendre son fonctionnement regardez ce croquis .

   ;+---------+
VISAD -->! *** !
   ;! * * * !
   ;! ******* !
   ;! *** !
   ;! ***** !
   ;! ******* !<-- & COINBD du sprite rencontré mémorisés dans ZONESPT.
   ;+---------+
   ; ^
   ; +------------- Adresse ADCOLIS ou ça va cogner .
   ; +---------+
VISAD ----->! * !<--- Le sprite numéro 6 qui monte vers un sprite
   ; ! * !  quelconque .
   ; ! * !
   ; ! *** !
   ; ! ***** !
   ; ! ******* !<---- & COINBD du sprite actif en zone programme .
   ; +---------+

La collision sera enregistrée sur la ligne du bas du sprite rencontré . On commencera donc le test depuis COINBD en balayant la ligne de droite à gauche pour gagner un maximum de temps . Si on devait effectuer un test similaire vers :
LE BAS : On balayerait de gauche à droite en commençant par VISAD .
LA GAUCHE : De bas en haut en commençant par COINBD .
LA DROITE : De haut en bas en commençant par VISAD .

Soit 1 routine différente par direction envisagée .

Voyons aussi le cas ci-dessous .

   ;+---------+
   ;! *** !
   ;! * * * !
   ;! ******* !<--- La collision sera enregistrée ici si le sprite
   ;! *** !     ; tamponneur monte en diagonale vers
   ;! ***** ! +---------+ la gauche .
   ;! ******* ! ! * !
   ;+---------+ ! * !
        ; ! * !
        ; ! *** !
        ; ! ***** !
        ; ! ******* !
        ; +---------+

 Il est visible qu'en diagonale la collision peut ne pas se produire sur la ligne la plus basse mais au milieu ou tout en haut . Si l'on veut augmenter l'efficacité du missile , il suffira de tester plus d'une ligne en remontant le test d'un cran vers le haut si la 1ère ligne ne valide pas la collision . Cela rallonge le temps d'exécution mais il faut aussi envisager
les cas suivants :

   ;+---------+
   ;!   ;! Pour une raison connue du seul créateur de la table de
   ;! *** ! sprites , celui-ci présente une ligne vide ici --+
   ;! *** *** !                        ;!
   ;! *** *** !                        ;!
 +----> ! *** !                        ;!
 !   !   ;! <-------------------------------------------------+
 !   +---------+
 +------------------------- La ligne de collision enregistrée par ENHAUT
   ;+---------+   ;ne sera pas la plus basse du sprite mais celle
   ;! * !   ;ou se trouvent les 1ères couleurs qui est au
   ;! * !   ;dessus de COINBD , il faudra donc tester 2
   ;! * !   ;lignes si l'on veut valider la collision .
   ;! *** !
   ;! ***** !
   ;! ******* !
   ;+---------+

Même problème ci-dessous , la zone testée est celle au dessus du sprite en cours et la couleur déterminant la collision ne se rencontre que sur la 3ème ligne .

   ;+---------+
   ;!   ;!
   ;! *** !
   ;! *** *** !
   ;! *** *** !. . . . <-- ADCOLLI est trouvée sur cette ligne .
   ;! ***. !   .
   ;! ***. !   .
   ;+------.--+   .
    ; .   ;.
    ; +---------+
    ; ! * !
    ; ! * !
    ; ! * !
    ; ! *** !
    ; ! ***** !
    ; ! ******* !
    ; +---------+

Donc dans le cas ou un sprite est entouré d'une ligne vide , ne tester qu'une ligne équivaut à le rendre indestructible ! Dans celui ou la ligne de collision laisse des vides , il sera d'autant plus difficile de le toucher que le nombre de lignes testées sera faible .

On pourrait résoudre ces inconvénients en supprimant le test sur les couleurs et en balayant la table des sprites à chaque test histoire de voir si un sprite bloque la route mais dans ce cas :

1 / La vitesse d'exécution du programme serait divisée par 2 .

2 / Si une couleur n'appartient pas à un sprite elle sera ignorée et effacée par le passage du sprite .

Alors restons en là et voyons la routine COLIUP ou l'on notera que le test de comparaison se fait en 2 fois , Comparaison sur l'octet fort puis sur l'octet faible . En effet , PUSHHL-ANDA-SBCHL,DE-POP HL- JRZ,TOUCHE est beaucoup trop long à exécuter ! Et on ne peut vraiment tester sur 8 bits seulement car certains groupes de 8 lignes écran (Comme le groupe 4 , voyez SCRENMAP de SOS5) commençant par #C0F0 voit 2 octets forts différents sur une meême ligne (De #C0FF on passe à #C100) et en ces points particuliers de l'écran , le test aurait du mal à s'effectuer !

;
;- Tester avec quel sprite on entre en collision (Par dessous) -
;
COLIUP LD B,NBTOANI  ;Nombre a animer donc a tester
  LD IX,ZONESPT ;Debut de la table des sprites
  LD DE,(ADCOLLIS) ;Adresse de collision detectee par ENHAUT
;
BCLCOLLIS PUSH BC   ;On preserve le nombre a tester
  LD A,(IX+7) ;Voir statut sprite
  INC A    ;Si <> de #FF , il est deja hors jeu , on abandonne
  JR NZ,NOTEST ;le test de celui-ci pour passer au suivant .
;
  LD B,2   ;Hauteur a tester 2 lignes sont raisonnables .
  LD C,LSP   ;Largeur d'un sprite
  LD L,(IX+4) ;Adresse de COINBD prise dans la table des sprites.
  LD H,(IX+5)
;
BCLC2 PUSH HL   ;Preserver COINBD en cours de test
  PUSH BC   ;et les hauteurs et largeurs de la zone a tester
;
BCLC1 LD A,H   ;Tester octet par octet gagne du temps
  CP D    ;On commence par l'octet fort des adresses
  JR NZ,PATOUCH
  LD A,L   ;Et on ne teste le faible que si la comparaison
  CP E    ;precedente est valide
  JR Z,TOUCHE ;Si les 2 adresses coincident le sprite teste
;        ;est touche par le sprite numéro 6 .
PATOUCH DEC HL   ;Sinon on continue a tester la ligne en cours
  DEC C
  JR NZ,BCLC1
;
  POP BC   ;Et si la collision n'est pas verifiee sur cette
  POP HL   ;ligne on va voir sur la ligne au dessus .
  CALL ADSUP
  DJNZ BCLC2
;
NOTEST LD BC,11   ;Un sprite vient d'etre teste , on passe au suivant
  ADD IX,BC   ;en avancant de 11 octets dans la table .
  POP BC
  DJNZ BCLCOLLIS
  XOR A    ;Ici on constate qu'aucun sprite n'est touche , on
  RET    ;enleve le CARRY et c'est fini
;
TOUCHE POP BC   ;Un sprite est touche , on remet la pile en etat
  POP HL
  POP BC
  LD (IX+7),0 ;On signale sa destruction en modifiant l'octet
  CALL EFFSP  ;qui correspond a STATSP , on l'efface
  ;SCF    ;et on met le CARRY pour signaler sa disparition
  RET    ;lors du retour en HAUTSP . Si l'on ne met pas le
;        ;CARRY , le sprite sera quand me^me détruit mais le
;        ;missile N.6 changera de direction à chaque choc .
;
;- Efface le sprite touche -
;
EFFSP LD BC,HSP  ;Ici IX pointe toujours sur le sprite détruit , on
  LD H,(IX+3) ;extrait donc VISAD de la table pour l'effacer et
  LD L,(IX+2) ;de cette maniere , les parametres du sprite en cours
;      ;restent inchanges au cours de toutes les operations
BCLEFF1 PUSH HL   ;de test et d'effacement .
  PUSH BC
  LD B,C
BCLEFF2 LD (HL),0
  INC HL
  DJNZ BCLEFF2
  POP BC
  POP HL
;
  LD A,H
  ADD A,8
  LD H,A
  JR NC,EXIEFF
  LD DE,#C050
  ADD HL,DE
EXIEFF DJNZ BCLEFF1
  RET
;

C'est tout ce qu'il faut pour supprimer un sprite suite à une collision , il ne reste plus qu'une petite modification à effectuer dans la boucle principale pour ignorer les cadavres .

;
;- Boucle pour deplacer un sprite -
;
NXTANIM CALL TRANSP
  LD A,(STATSP) ;VERIFIER QUE LE SPRITE N'EST PAS HORS JEU , SI C'EST
  OR A    ;LE CAS ON SAUTE TOUTE LA BOUCLE .
  JR Z,ESTMORT
;
  PUSH BC
  CALL TSTMOVE
  CALL AFFISP
  CALL SPTRANS
  POP BC
;
ESTMORT DJNZ NXTANIM
  JP RECOM
;

La démonstration mettra en évidence un problème majeur , plus on détruit de sprites , plus le programme accélére ! On aurait du mettre une petite temporisation pour compenser l'annulation de chaque sprite ... Nous allons faire encore mieux dans le prochain chapitre .

SOS PROGRAMMEURS

★ ANNÉE: ???
★ AUTEUR: MICHEL MAIGROT

Page précédente : Graphic - 20 - un Nouveau Test de Collisions sur les Couleurs
★ AMSTRAD CPC ★ DOWNLOAD ★

Other platform tool:
» SOS7DEMODATE: 2011-06-03
DL: 1512
TYPE: ZIP
SiZE: 8Ko
NOTE: 40 Cyls
.HFE: Χ

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding Src's » Grafikdemo (CPC Amstrad International)
» Coding Src's » Graphic - Circle (The Amstrad User)
» Coding Src's » ARTIFICE (CPC Infos)
» Coding Src's » Wave Interference (Popular Computing Weekly)
» Coding Src's » Nextline
» Coding Src's » Virages et loopings
Je participe au site:
» Vous avez des infos personnel, des fichiers que nous ne possédons pas concernent ce programme ?
» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 271 millisecondes et consultée 1762 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.