1

C'est juste quelques amusements, pas sur que ça aboutisse un jour (surtout que l'algo pour connaitre si le joueur a perdu semble pas facile) mais ça vaut le coup d'oeil j'imagine.
Alors voici un embryon de "oilcap". Toujours pas de gestion de l'ecran sous forme de tableau, mais quelques ruses en plus (un liste permet de donner les tubes à afficher par exemple avec comparaison bit à bit pour reconstituer un tube).

Bon voila un petit screenshot, et on en parle après :

oilcap.gif

Le clignotement c'est normal y a un call _DispHL qui traine wink

2

J'ai jamais vraiment joué à PipeMania & co, donc le but c'est bien d'aligner des tuyaux entre eux suivant les pièces qu'on te donne ? Si c'est ça ce serait vraiment plus efficace d'utiliser une matrice, surtout si tu veux afficher le liquide qui commence à avancer au bout d'un certain temps.

Enfin c'est ce que j'ai cru piger de http://en.wikipedia.org/wiki/Pipemania

3

Je connais pas le jeu, tu donnes un peu plus d'infos?

4

C'est effectivement un clone de pipemania.

Donc le but du jeu est de créer un circuit le plus long possible avec les pièces qui sont fournies.
A la fin d'un certain temps, le liquide se mets à couler et le circuit s'il n'est pas fermé fait perdre le joueur.
Chaque level necessite un cirtuit de plus en plus long.
Et sur mon screenshot, il manque la vanne de départ.
Lorsqu'on remplace un pièce on perd des point. Chaque case du circuit (s'il est valide) rapporte des point.

edit: je jouais quand j'étais petit à "OILCAP" sous DOS (vers 92/93 je pense)...
Mais il existe de multiples clones comme "TUBZ" sur iphone par exemple...

5

Voici un screenshot un peu plus explicite (avec quelques améliorations) :

oilcap2.gif

La on voit comment on peut passer un niveau (meme si pour l'instant c'est qu'une demo).
Y a un robinet de depart et le prochain tube qui est affiché en bas à droite.

6

Ajout d'un timer :

oilcap3.gif

J'ai quelques questions pour deeph :
- Comment sont gérés les timers habituellement, est-ce qu'il y a quelque chose de prévu dans la calc pour ça ou faut faire soi-même comme j'ai fait là (je ne peux pas utiliser de waitkey sinon le timer s'arrete)?
- Comment faire pour ralentir la calc (dans le sens eviter les keypress multiples involontaires), j'ai implémenté mon propre systeme pour éviter que la calc pose plein de tuyau avec un seul click (peut-être est-ce seulement du à l'émulation).

En gros là il me reste à faire les points (perdre des points si on pose des tuyaux sur des emplacements déjà pris) et la fin du jeu (tester le circuit et remplir d'eau) et le mécanisme de réussite
Et la fin du jeu est largement le plus difficile (et il faut que j'utilise la technique de la matrice avant d'attaquer cette partie).

Mais so far so good wink

7

On peut gérer le temps avec les interruptions, c'est ce qu'il y a de plus précis je pense.

Pour ralentir un programme j'utilise la commande halt (bien que nop peut être aussi utilisée) :

wait:
	ei

wait_loop:
	halt
	djnz wait_loop
	ret


À noter que les interruptions doivent être activées (ei) sinon la prochaine instruction n'arrivera jamais (ion les désactive par défaut).

8

Moi aussi jouais à ce jeu quand j'étais (plus) petit et je suis très content de le voir ici! Est-ce qu'il n'y en avait pas une version pour les ti83/+ avant de celle-ci? Qu'est-ce qu'il te faut encore pour le finir?

Et pour un timer, pour le 83+ SE (et je suppose pour les autres nouvelles modèles aussi) il y'a une horloge que tu pourrais peut-être utiliser. Sinon, tu peux aussi rechercher les "interruptions" (je sais pas s'il y'en a de documentation en français), mais, moi, je crois que c'est bien comme tu le fais maintenant.

Quant à ralentir le calc, je dirais que tu pourrais aussi garder la dernière clé poussée et attendre à qu'on la laisse pour continuer, c'est à dire si on doit pousser [2nd] pour mettre un tuyau, on ne peut pas en mettre un autre à moin qu'on ait déjà laissé [2nd]. Je ne sais pas si je m'explique.

9

Les interruptions du z80 sont plus ou moins expliquées un peu partout sur internet, comme sur Quasar Net dans le cas des CPC, mais c'est vrai que trouver un code source prêt à l'emploi c'est un peu compliqué, et encore plus lorsqu'il s'agit de la TI 83+. Aussi je recopie l'exemple d'SNG pour TI 82 au cas où :

NEW_INTERRUPT: ;DE=adresse de l'interuption
 DI
 PUSH AF
 PUSH BC
 PUSH HL
 PUSH DE
 LD A,(APD_BUF) ; APD_BUF = nombre d'interruptions
 INC A
 LD (APD_BUF),A
 CP 1
 JR NZ,rajoute_int
 ld hl,TABLE
 ld de,TABLE+1
 ld (hl),CODE8
 ld bc,$0100
 ldir
 LD HL,instal_interruptions
 ld de,CODE
 LD BC,instal_interruptions_fin - instal_interruptions
 LDIR
 EX DE,HL
 JR ajoute_code

rajoute_int:
 DEC A
 LD H,0
 LD L,A
 LD BC,3
 CALL MUL_HL_BC
 LD BC,CODE+$1A
 ADD HL,BC
ajoute_code:
 POP DE
 PUSH DE
 ld (hl),$CD ;=call
 inc hl
 ld (hl),E
 inc hl
 ld (hl),D
 inc hl
 EX DE,HL
 LD HL,instal_interruptions2
 LD BC,instal_interruptions_fin2 - instal_interruptions2
 LDIR
 ld a,TABLE8
 ld i,a
 im 2
 POP DE
 POP HL
 POP BC
 POP AF
 EI
 ret

STOP_INTERRUPT: ;A=numero de l'instruction
 DI
 LD H,0
 LD L,A
 LD A,(APD_BUF)
 DEC A
 LD (APD_BUF),A
 OR A
 JR Z,arrete_interrupt
 LD BC,3
 CALL MUL_HL_BC
 LD BC,CODE+$1A
 ADD HL,BC
 LD D,H
 LD E,L
 INC HL
 INC HL
 DEC DE
ecrase_appel:
 INC HL
 INC DE
 LD A,(HL)
 LD (DE),A
 CP $4D
 JR Z,teste_arret_ecrase_appel
 LD C,B
 LD B,A
 JR ecrase_appel
teste_arret_ecrase_appel:
 PUSH HL
 LD HL,$EDFB
 CALL CP_HL_BC
 POP HL
 JR NZ,ecrase_appel
 EI
 ret
arrete_interrupt:
 im 1
 EI
 ret

Quant à utiliser l'horloge je pense que c'est inutile, déjà parce qu'elle n'est pas présente sur les calculettes antérieures et ensuite parce qu'elle est sûrement basée sur les interruptions et très difficilement utilisable en ASM...

Ensuite pour ma part je pense que le plus simple est bien d'utiliser halt pour ralentir le programme (l'optimum ce serait justement de l'allier aux interruptions pour avoir un fps +/- constant).

10

deeph (./9) :
Quant à utiliser l'horloge je pense que c'est inutile, déjà parce qu'elle n'est pas présente sur les calculettes antérieures et ensuite parce qu'elle est sûrement basée sur les interruptions et très difficilement utilisable en ASM...
Premièrement, merci pour le lien, je vais y passer un peu plus tard pour lire son contenu plus soigneusement smile

Moi aussi je crois qu'il y a de meilleures choses à l'utiliser pour cette même raison: ça ne fonctionne pas qu'en les dernières modèles. Mais je ne crois pas qu'il se sert (complètement) des interruptions, il y a une "minuteur", quelque chose comme une horloge "réelle". Tout de même, je ne savais pas si on utilisait encore les modèles antérieures.

Mais, l'autre chose que j'ai proposée, tu pourrais faire quelque chose comme ceci:
 ld hl,pousser2nd
 cp k2nd ;si on a poussé 2nd
 jr z,_2nd
 ld (hl),0 ;si nous sommes ici, c'est qu'on ne pousse pas 2nd
...

_2nd:
 ld a,(hl)
 or a
 ret nz
 inc (hl)
...etc

pousser2nd:
 .db 0


ou même:
 ld hl,_2nd
 cp k2nd ;si on a poussé 2nd
 jr z,_2nd
 ld (hl),0 ;$00 = nop
...

_2nd:
 nop
 ld (hl),$C9 ;je crois que C9 = ret
...etc

Je ne sais pas comment tu as organisé ton code, mais tu sauras comment l'y adapter.

11

C'est vrai que ça permettrai de ne pas ralentir tout le programme, mais ça fait quand même un peu lourd à coder...

12

Salut,

Merci pour tous vos liens et commentaires très instructifs.
Je ne pense pas utiliser d'interuptions car je pense que ça risque de complexifier le jeu et je ne m'en sens pas capable.

Voici ce que j'ai fait pour les timers (ne tenez pas compte des labels il ne sagit pas de milliseconde et microsecondes) :

; Mettre a jour le timer c'est a dire :
; Charger les milli secondes, decrementer
; Si milli seconde == 0, charger secondes et decrementer
; Si seconde = 0, mettre timeup a 0
UPDATE_TIMER:
	push	hl
	push	de
	push	af
	push	bc	

	;ld	a,(hl)
	;ld	h, 0
	;ld	l, a
	;call	_dispHL
	;call	WAITKEY
	
	ld	hl, microsec
	ld	a,(hl)
	dec	a
	jp	z, moins_une_milliseconde
	ld	(hl), a
	jp	fin_timer

moins_une_milliseconde:
	ld	hl, millisec
	ld	a, (hl)
	dec	a
	jp	z, moins_une_seconde
	ld	(hl), a
	ld	hl, microsec
	ld	a,(hl)
	ld	a, 100
	ld	(hl), a
	call	PRINT_MILLISEC
	call	PRINT_SEC
	call	UNLOCK_KFLAG
	jp	fin_timer

moins_une_seconde:
	ld	hl, sec
	ld	a, (hl)
	dec	a
	jp	z, timeup
	ld	(hl), a
	ld	hl, millisec
	ld	a,(hl)
	ld	a, 100
	ld	(hl), a
	call	PRINT_SEC
	jp	fin_timer

temps_ecoule:
	ld	hl, timeup
	ld	(hl), 0

fin_timer:
	pop	bc
	pop	af
	pop	de
	pop	hl

	ret	
	

PRINT_MILLISEC:
	push	hl
	push	de
	push	af
	push	bc	

	ld     hl, 0
	ld     (CURROW),hl
	ld     hl, 9
	ld     (CURCOL),hl
	ld     hl, (millisec)
	ld	h, 0
	call	_dispHL	
	;call	WAITKEY



	pop	bc
	pop	af
	pop	de
	pop	hl

	ret	


PRINT_SEC:
	push	hl
	push	de
	push	af
	push	bc	

	ld     hl, 0
	ld     (CURROW),hl
	ld     hl, 4
	ld     (CURCOL),hl
	ld     hl, (sec)
	ld	h, 0
	call	_dispHL	
	;call	WAITKEY
	

	pop	bc
	pop	af
	pop	de
	pop	hl

	ret	

UNLOCK_KFLAG:
	push	hl
	push	de
	push	af
	push	bc	

	ld	hl, kflag
	ld	a, (hl)
	cp	0
	jp	z, ne_rien_faire
	dec	a
	ld	(hl), a

ne_rien_faire:
	pop	bc
	pop	af
	pop	de
	pop	hl

	ret	





PRINT_HEADER:
	push	hl
	push	de
	push	af
	push	bc	

	ld	a, 0
	ld	e, a
	ld	a, 88
	ld	hl, oclock
	call	DRWSPR	
	

	pop	bc
	pop	af
	pop	de
	pop	hl

	ret

	
timeup:
	.db 1

sec:
	.db 30
millisec:
	.db 100
	
microsec:	
	.db 100



@chickendude : J'ai trouvé une solution pour eviter les doubles keypress et c'est facilement parametrable mais j'aimerai bien que tu expliques tes 2 morceaux de codes qui ne me semblent pas très très clairs...
Voici ma solution pour eviter le double keypress :
; Test if the player selects a block  
SELECT_SCAN_KEY:
	push hl
	push de
	push bc
	ld     a,$FF          
        out    (1),a           
	ld     a,$FD       	; scanner le groupe
	out    (1),a         
	in     a,(1)        
	;bit	0,a
	cp	191
	jp	z, select
	cp	254
	jp	select_end

	
select:
	
	; Verifier qu'on ne pose pas 10 tubes a la suite
	ld	hl, kflag
	ld	a, (hl)	
	cp	0
	jp	z, ok
	jp	select_end

ok:
	; Si c'est bon activer le flag	
	ld	hl, kflag
	ld	a, 10
	ld	(hl), a 	

	call	TUBE_LOAD
	call	TUBE_PRINT
	call	TUBE_LOAD
	call	TUBE_PREVIEW_PRINT
	call	BUFCOPY
	CALL	PRINT_MILLISEC
	CALL	PRINT_SEC
	
	;call	WAITKEY

select_end:
	pop	bc
	pop	de
	pop	hl

	ret

kflag:
	.db 0


Vous remarquerez que le deblocage du kflag se fait dans le timer ... (voir code au dessus).

Sinon pour finir il me reste à coder l'algo qui permet de verifier si le circuit est valide, or il faut pour cela traiter soit 0, 1, 2, 3 case adjacentes.
Pour 0 ou 1 c'est facile mais pour plus il faut empiler les cases non traitées et faire une sorte d'algo recursif (parcours en profondeur d'un graphe?) enfin je ne sais pas encore et je pense que ce n'est pas franchement facile.
De plus il faut que je stocke la map dans une matrice pour savoir si on pose un tuyau sur un emplacement pris (perdre des points) ou sur une case non libre (si j'ajoute des block dur dans la map).
Et donc du coup il faut que je gère les points et la fin du niveau.

Encore merci pour vos suggestions.
J'espère pouvoir avancer un peu ce jeu dans la semaine.

Thibault





13

J'ai (enfin) ajouté un gestion de la map par matrice (comme tu me l'avais fortement conseillé deeph et à juste titre d'ailleurs).
Pour l'instant je l'utilise pour lire un emplacement et savoir s'il est pris, et inversement de stocker un tuyau dans un emplacement.

Ca donne quelque chose comme ceci :
; Lire le contenu a l'emplacement (b,c) tel que b = x et c = y 
MATRIX_READ:

	push	hl
	push	de
	push	bc
	push	af

	;ld b,3    ;on prends les coordonnées (3,2)
	;ld c,2    ;

	ld	a, (xcoord)
        ld      d,0             ; Do x/8
        ld      e,a 
        srl     e   
        srl     e   
        srl     e   
	ld	b, e
	push	bc
	
	;ld     hl, 0
	;ld     (CURROW),hl
	;ld     hl, 0
	;ld     (CURCOL),hl
	;ld  	h, 0
	;ld	l, b
	;call	_dispHL
	;call	WAITKEY

	
	ld	a, (ycoord)
	ld	d, 0
	ld	e, a
	srl	e
	srl	e
	srl	e
	ld	b, a
	ld	a, e
	sub	1
	
	pop	bc
	ld	c, a
	
	;ld     hl, 0
	;ld     (CURROW),hl
	;ld     hl, 0
	;ld     (CURCOL),hl
	;ld  	h, 0
	;ld	l, c
	;call	_dispHL
	;call	WAITKEY
	;call	WAITKEY
	;call	WAITKEY

lecturematrice:
	ld a,c   ;\
	add a,a  ; |
	add a,a  ; |a=c*16
	add a,a  ; |
	add a,a  ;/
	sub c
	sub c
	sub c
	sub c
	sub c
	sub c
	add a,b	; ajouter le x
	ld e,a
	ld d,0
	ld  hl, map
	add hl,de
	ld a,(hl)
	
	ld     hl, 0
	ld     (CURROW),hl
	ld     hl, 0
	ld     (CURCOL),hl
	ld  	h, 0
	ld	l, a
	call	_dispHL
	call	WAITKEY
	call	WAITKEY
	call	WAITKEY

	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret


; Sauver un block dans la matrice 
MATRIX_SAVE_BLOCK:

	push	hl
	push	de
	push	bc
	push	af

	ld	a, (xcoord)
        ld      d,0             ; Do x/8
        ld      e,a 
        srl     e   
        srl     e   
        srl     e   
	ld	b, e
	push	bc
	
	ld	a, (ycoord)
	ld	d, 0
	ld	e, a
	srl	e
	srl	e
	srl	e
	ld	b, a
	ld	a, e
	sub	1
	
	pop	bc
	ld	c, a

lecturematrice2:
	ld a,c   ;\
	add a,a  ; |
	add a,a  ; |a=c*16
	add a,a  ; |
	add a,a  ;/
	sub c
	sub c
	sub c
	sub c
	sub c
	sub c
	add a,b	; ajouter le x
	ld e,a
	ld d,0
	ld  hl, map
	add hl,de
	push	hl

	ld	hl, tub_index
	ld	a, (hl)
	ld	b, a
	ld	ix, liste
	dec	ix

inc_ix2:
	inc	ix
	djnz	inc_ix2
	
	ld	a, (ix) 
	
	pop	hl
	ld	(hl), a
	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret

(liste est la liste qui contient les tubes, tub_index est le decalage dans la liste, (ix) est donc le tuyau courant)


Et la matrice :
map:
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0




J'ai également fait le score dans la foulée (on perd 2 points si on pose sur une case prise, on gagne un point si on pose sur une case vide)
Si mes souvenir sont bons, la gestion du score se faisait comme ça (mais avec des 10aines de points + 10 et -20).
Il me reste donc que la fin du jeu à faire (gros morceau) et les niveau, page de demarrage, amélioration de l'affichage et toutes les bricoles de ce genre.

Voici un screenshot de la version actuelle (avec score) :

oilcap4.gif
(c'est normal que les derniers tubes ne sont pas bons car on sort de la liste et ce sont donc des valeurs piochées en mémoire xD)

J'espère arriver à faire l'algo de fin, je vais retrousser mes manches et j'aurai surement besoin de votre aide à tous les 2.

Merci encore.

14

Avec quoi compiles-tu ton projet ? Spasm ? Parce que "call _dispHL" me semble bizarre, théoriquement ce serait plutôt "bcall _disphl"...

Sinon ta routine est pas mal mais un peu laborieuse je trouve, ça peut s'optimiser. Je t'ai mis quelques annotations en commentaire, mais déjà évite d'utiliser trop souvent la pile, car y accéder c'est plus lent que d'utiliser les registres.

UPDATE_TIMER: 
	push	hl 
	push	de 		; sert à rien
	push	af 
	push	bc 		; sert à rien
 
	;ld	a,(hl) 
	;ld	h, 0 
	;ld	l, a 
	;call	_dispHL 
	;call	WAITKEY 
	 
	ld	hl, microsec 
	ld	a,(hl) 
	dec	a 
	jp	z, moins_une_milliseconde 
	ld	(hl), a 
	jp	fin_timer 
 
moins_une_milliseconde: 
	ld	hl, millisec 
	ld	a, (hl) 
	dec	a 
	jp	z, moins_une_seconde 
	ld	(hl), a 
	ld	hl, microsec 
	ld	a,(hl)		; sert à rien
	ld	(hl),100	; pas besoin de l'accu
	call	PRINT_MILLISEC 
	call	PRINT_SEC 
	call	UNLOCK_KFLAG 
	jp	fin_timer 
 
moins_une_seconde: 
	ld	hl, sec 
	ld	a, (hl) 
	dec	a 
	jp	z, timeup 
	ld	(hl), a 
	ld	hl, millisec 
	ld	a,(hl) 		; sert à rien
	ld	(hl),100		; pas besoin de l'accu
	call	PRINT_SEC 
	jp	fin_timer 
 
temps_ecoule: 
	ld	hl, timeup 
	ld	(hl), 0 
 
fin_timer: 
	pop	bc 		; sert à rien
	pop	af 
	pop	de 		; sert à rien
	pop	hl
 
	ret	 
	 
 
PRINT_MILLISEC: 
	push	hl
	push	de		; sert à rien (n'est pas détruit par _dispHL me dit google)
	push	af 
	push	bc 
 
	ld     hl,$0900		; charge 0 dans currow et 9 dans curcol qui suit (un registre 16 bit va copier la moitié dans le premier octet etc...)
	ld     (CURROW),hl
	ld     hl, (millisec)
	ld	h, 0		; sert à rien
	call	_dispHL
	;call	WAITKEY 
 
 
 
	pop	bc 
	pop	af 
	pop	de		; sert à rien
	pop	hl 
 
	ret	 
 
 
PRINT_SEC: 
	push	hl 
	push	de 		; sert à rien
	push	af 
	push	bc	 
 
	ld	hl,$0400 		; idem
	ld	(CURROW),hl
	ld	hl, (sec) 
	ld	h, 0 		; sert à rien
	call	_dispHL	 
	;call	WAITKEY 
	 
 
	pop	bc 
	pop	af 
	pop	de 		; sert à rien
	pop	hl 
 
	ret	 
 
UNLOCK_KFLAG: 
	push	hl 
	push	de 		; sert à rien
	push	af 
	push	bc		; sert à rien	 
 
	ld	hl, kflag 
	ld	a, (hl) 
	or	a 		; va bien plus vite (cf http://quasar.cpcscene.com/doku.php?id=iassem:z80init#ld_a_0 )
	jp	z, ne_rien_faire 
	dec	a 
	ld	(hl), a 
 
ne_rien_faire: 
	pop	bc 		; sert à rien
	pop	af 
	pop	de 		; sert à rien
	pop	hl 
 
	ret	 
 
 
 
 
 
PRINT_HEADER: 
	push	hl 
	push	de 
	push	af 
	push	bc		; plus ou moins utile suivant que la routine DRWSPR l'explose ou pas
 
	ld	e,0		; pas besoin de l'accumulateur
	ld	a,88
	ld	hl,oclock
	call	DRWSPR
	 
 
	pop	bc		; idem
	pop	af 
	pop	de 
	pop	hl 
 
	ret 
 
	 
timeup: 
	.db 1 
 
sec: 
	.db 30 
millisec: 
	.db 100 
	 
microsec:	 
	.db 100


; Test if the player selects a block   
SELECT_SCAN_KEY: 
	push hl		; sert à rien
	push de 		; sert à rien
	push bc 		; sert à rien
	ld     a,$FF	; sert à rien
        	out    (1),a	; sert à rien
	ld     a,$FD       	; scanner le groupe 
	out    (1),a          
	in     a,(1)         
	;bit	0,a	; justement tu devrais l'utiliser :D
	cp	191 	; bit 6,a selon http://tift.tuxfamily.org/asmpourlesnuls.html et http://quasar.cpcscene.com/doku.php?id=iassem:z80init#les_instructions_de_controle_et_de_test_de_bit
	jp	z, select 
	cp	254 	; bit 0,a mais sert à rien du coup
	ret

select:
	; Verifier qu'on ne pose pas 10 tubes a la suite
	push hl
	push af
	ld	hl, kflag 
	ld	a, (hl)	 
	cp	0	; or a
	call z,ok		; plus optimisé
	pop af
	pop hl
	ret

ok:
	; Si c'est bon activer le flag	 
	ld	hl, kflag
	ld	(hl),10	; pas besoin de l'accu
 
	call	TUBE_LOAD 
	call	TUBE_PRINT 
	call	TUBE_LOAD 
	call	TUBE_PREVIEW_PRINT 
	call	BUFCOPY 
	CALL	PRINT_MILLISEC 
	CALL	PRINT_SEC 

	;call	WAITKEY 
	ret
 
kflag: 
	.db 0 


edit : cross

15

Tiens j'ai commencé à relever quelques trucs :

; Lire le contenu a l'emplacement (b,c) tel que b = x et c = y  
MATRIX_READ: 
 
	push	hl 
	push	de 
	push	bc 
	push	af 
 
	;ld b,3    ;on prends les coordonnées (3,2) 
	;ld c,2    ; 
 
	ld	a, (xcoord) 
	srl	a	; Do x/8 
	srl	a
	srl	a
	ld	b,a
	push	bc

	;ld     hl,0 
	;ld     (CURROW),hl 
	;ld	l, b 
	;call	_dispHL 
	;call	WAITKEY 

	ld	a, (ycoord) 
	srl	a
	srl	a
	srl	a
	sub	1
	pop	bc
	ld	c,a 

	;ld     hl, 0 
	;ld     (CURROW),hl 
	;ld	l, c 
	;call	_dispHL 
	;call	WAITKEY 
	;call	WAITKEY 
	;call	WAITKEY


Par contre je comprend pas trop comment tu gères tes coordonnées... Au début tu calcules des valeurs "rondes" en divisant par huit pour lire la matrice ?

Le principe c'est qu'en gros tu fais la taille de ta matrice multiplié par y puis tu ajoutes x pour obtenir l'adresse d'une cellule de ta matrice, donc techniquement y'a plus simple (par exemple j'ai uploadé récemment gurk.z80, bien qu'il travail avec une matrice encodée mais bon c'est pareil).

16

Merci pour tes conseils/optimisations je les applique sur mon code en ce moment même.

J'utilise spasm avec ti83asm.inc. Je n'ai jamais vu de bcall pour ti83 car il s'agit de "simples sauts" contrairement aux ti83plus.

Pour la matrice, je ramènes les coordonnées pixel à une case du tableau (tu as bien compris).
C'est pas très beau mais je n'ai pas encore épluché gurk.z80.

Je commence à travailler sur le remplissage à présent.

17

Ah ok tu travailles pour les 83... Si tu veux je peux essayer de t'améliorer la lecture et l'écriture de ta matrice dès que j'ai 5min smile

18

Toujours 83 même si je sais coder un peu pour 83+ et convertir du code de l'une à l'autre.
Si tu veux je peux essayer de t'améliorer la lecture et l'écriture de ta matrice dès que j'ai 5min


Oui je veux bien smile

19

Ca y est j'ai fait la partie graphique du remplissage des tubes.
Me reste donc :
- Faire l'algorithme pour parcourir les tubes (parcours en largeur d'un graphe/arbre de préference)
- Ajouter quelques fioritures (ecran d'accueil, levels, difficulté etc...)

Il faut vraiment qu'on m'aide pour l'algo, j'ai commencé à regarder c'est franchement hard. Il faudrait que j'empile les cases non traitées lorsque je tombe sur un tube avec sortie multiple, et donc que je depile au bon moment en tenant compte que l'adresse est empilee sur la pile aussi (dans le cas ou je fais des call recursifs).
Bref Deeph et chickendude votre aide est franchement la bienvenue (gh aussi s'il passe par ici).

Voici une demo du remplissage des tubes (toute la map est parcourue et remplie) :

oilcap5.gif

Allez une autre pour la route :

oilcap6.gif

Allez encore un (gros) effort et c'est bon wink

edit : le projet est à présent hebergé sur google code (patch tag ne veut plus marcher chez moi grrrr) : http://code.google.com/p/oilcap/source/browse/#svn%2Ftrunk

20

J'ai trouvé comment gérer le parcours.
Je fais un parcours en profondeur (même si un parcours en largeur est mieux mais bon).
Je verifie les cases adjacentes et j'appelle pour chacunes d'elles la methode de parsing donc recursivement.

Mais si vous regardez le code j'ai enlevé la recursivité... Tout simplement pour éviter les retours en arrière !
J'ai donc decoupé la methode en 4 et selon d'ou on arrive ce n'est pas la meme qui est appelée.

Si on va sur la case de gauche, on sait que la case de droite est deja occupée et valide, donc on n'essaye pas d'aller dessus.

Voici un petit test (le liquide part du centre et il y a des waitkeys entre chaque case) :

oilcap7.gif

Allez un autre :

oilcap8.gif

Je suis soulagé de n'être plus bloqué sur ce problème par contre le code est absolument abominable :
algo

; Parser les tubes en partant de l'emplacement (b,c)
PARSE_TUBE:
	push	hl
	push	de
	push	bc
	push	af

	push	bc
	call	WAITKEY
	; Recuperer le tube, charger le sprite et afficher
	call	GET_TUBE
	call	OIL_LOAD
	call	OIL_PRINT	

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000001b
	and	(ix)
	jp	z, pas_de_haut	
	
	; Tester haut et call avec c - 8
	ld	a, c
	sub	8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000010b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_HAUT
	
		
pas_de_haut:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000010b
	and	(ix)
	jp	z, pas_de_bas

	; Tester haut et call avec c + 8
	ld	a, c
	add	a, 8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000001b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_BAS


pas_de_bas:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000100b
	and	(ix)
	jp	z, pas_de_gauche
	
	; Tester bas puis call avec b - 8
	ld	a, b
	sub	8
	ld	b, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00001000b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_GAUCHE

pas_de_gauche:
	pop	bc
	push	bc

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00001000b
	and	(ix)
	jp	z, pas_de_droite	

	; Tester bas puis call avec b + 8
	ld	a, b
	add	a, 8
	ld	b, a
	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000100b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_DROITE


pas_de_droite:
	pop	bc
	
	jp	pt_fin

perdu:
	ld	hl, leak
	ld	(hl), 0
	call	_dispHL
	call	WAITKEY
	call	WAITKEY
	

pt_fin:	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret


; Parser les tubes en partant de l'emplacement (b,c)
PARSE_TUBE_EN_HAUT:
	push	hl
	push	de
	push	bc
	push	af

	push	bc
	call	WAITKEY
	; Recuperer le tube, charger le sprite et afficher
	call	GET_TUBE
	call	OIL_LOAD
	call	OIL_PRINT	

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000001b
	and	(ix)
	jp	z, pas_de_haut1	
	
	; Tester haut et call avec c - 8
	ld	a, c
	sub	8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000010b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_HAUT
	
		
pas_de_haut1:
y_a_un_bas:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000100b
	and	(ix)
	jp	z, pas_de_gauche1
	
	; Tester bas puis call avec b - 8
	ld	a, b
	sub	8
	ld	b, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00001000b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_GAUCHE

pas_de_gauche1:
	pop	bc
	push	bc

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00001000b
	and	(ix)
	jp	z, pas_de_droite1	

	; Tester bas puis call avec b + 8
	ld	a, b
	add	a, 8
	ld	b, a
	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000100b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_DROITE


pas_de_droite1:
	pop	bc
	
	jp	pt_fin1

perdu1:
	ld	hl, leak
	ld	(hl), 0
	call	_dispHL
	call	WAITKEY
	call	WAITKEY
	

pt_fin1:	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret


; Parser les tubes en partant de l'emplacement (b,c)
PARSE_TUBE_A_DROITE:
	push	hl
	push	de
	push	bc
	push	af

	push	bc
	call	WAITKEY
	; Recuperer le tube, charger le sprite et afficher
	call	GET_TUBE
	call	OIL_LOAD
	call	OIL_PRINT	

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000001b
	and	(ix)
	jp	z, pas_de_haut2
	
	; Tester haut et call avec c - 8
	ld	a, c
	sub	8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000010b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_HAUT
	
		
pas_de_haut2:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000010b
	and	(ix)
	jp	z, pas_de_bas2

	; Tester haut et call avec c + 8
	ld	a, c
	add	a, 8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000001b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_BAS


pas_de_bas2:
y_a_un_gauche:
	pop	bc
	push	bc

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00001000b
	and	(ix)
	jp	z, pas_de_droite2	

	; Tester bas puis call avec b + 8
	ld	a, b
	add	a, 8
	ld	b, a
	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000100b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_DROITE


pas_de_droite2:
	pop	bc
	
	jp	pt_fin2

perdu2:
	ld	hl, leak
	ld	(hl), 0
	call	_dispHL
	call	WAITKEY
	call	WAITKEY
	

pt_fin2:	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret


; Parser les tubes en partant de l'emplacement (b,c)
PARSE_TUBE_EN_BAS:
	push	hl
	push	de
	push	bc
	push	af

	push	bc
	call	WAITKEY
	; Recuperer le tube, charger le sprite et afficher
	call	GET_TUBE
	call	OIL_LOAD
	call	OIL_PRINT	

y_a_un_haut:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000010b
	and	(ix)
	jp	z, pas_de_bas3

	; Tester haut et call avec c + 8
	ld	a, c
	add	a, 8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000001b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_BAS


pas_de_bas3:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000100b
	and	(ix)
	jp	z, pas_de_gauche3
	
	; Tester bas puis call avec b - 8
	ld	a, b
	sub	8
	ld	b, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00001000b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_GAUCHE

pas_de_gauche3:
	pop	bc
	push	bc

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00001000b
	and	(ix)
	jp	z, pas_de_droite3

	; Tester bas puis call avec b + 8
	ld	a, b
	add	a, 8
	ld	b, a
	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000100b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_DROITE


pas_de_droite3:
	pop	bc
	
	jp	pt_fin3

perdu3:
	ld	hl, leak
	ld	(hl), 0
	call	_dispHL
	call	WAITKEY
	call	WAITKEY
	

pt_fin3:	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret

; Parser les tubes en partant de l'emplacement (b,c)
PARSE_TUBE_A_GAUCHE:
	push	hl
	push	de
	push	bc
	push	af

	push	bc
	call	WAITKEY
	; Recuperer le tube, charger le sprite et afficher
	call	GET_TUBE
	call	OIL_LOAD
	call	OIL_PRINT	

	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000001b
	and	(ix)
	jp	z, pas_de_haut4	
	
	; Tester haut et call avec c - 8
	ld	a, c
	sub	8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000010b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_HAUT
	
		
pas_de_haut4:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000010b
	and	(ix)
	jp	z, pas_de_bas4

	; Tester haut et call avec c + 8
	ld	a, c
	add	a, 8
	ld	c, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00000001b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_EN_BAS


pas_de_bas4:
	pop	bc
	push	bc
	; Tester la morphologie du tube courant	
	call	GET_TUBE
	ld	ix, tube_squelette
	ld	a, 00000100b
	and	(ix)
	jp	z, pas_de_gauche4
	
	; Tester bas puis call avec b - 8
	ld	a, b
	sub	8
	ld	b, a

	call	GET_TUBE_TEST
	ld	ix, tube_a_tester
	ld	a, 00001000b
	and	(ix)		
	jp	z, fin_du_jeu

	call	PARSE_TUBE_A_GAUCHE

pas_de_gauche4:
y_a_un_droite:
	pop	bc
	
	jp	pt_fin4

perdu4:
	ld	hl, leak
	ld	(hl), 0
	call	_dispHL
	call	WAITKEY
	call	WAITKEY
	

pt_fin4:	
	pop	af
	pop	bc
	pop	de
	pop	hl

	ret




(je vous avais prévenus).

21

J'ai pas eu le temps de trop regarder le code mais déjà tu n'utilises pas de shell ? Donc tu vas être limité à ~8ko si mes souvenirs sont bon... Donc si jamais tu veux aller au delà je te conseil Ion, qui permettra d'avoir la compatibilité 83/83+.

Ensuite si j'ai bien compris tu ne te sert de la matrice que pour l'algo de détection de victoire ? Si c'est le cas c'est assez dommage puisque l'utiliser pour tout (l'affichage notamment) ça optimiserait pas mal...

Dès que j'ai un peu plus de temps je regarde à ton algo, mais à première vue y'a moyen de regrouper pas mal de tests en un seul.

Et sinon je me répète mais c'est vraiment utile d'utiliser la pile dans chaque routine ? Non seulement ça ralentit le programme mais en plus je suis pas certain que t'ai à tout prix besoin de sauvegarder tout le temps tes registres... Et d'un autre côté ça t'empêche de faire un "ret" n'importe quand (au moins regroupe tout tes "pt_fin" en un seul grin).

22

Salut ! Je vais essayer de lire tout ce que tu as écrit un peu plus tard, pour le moment j'ai quelques suggestions. Tu savais qu'il y avait une commande "dec (hl)"?:
UPDATE_TIMER:  
	push	hl  
	push	de 
	push	af  
	push	bc 		;je crois que tu pourras bien utiliser les variables "shadow" (d'ombre):
				;exx pour accéder á bc', de', et hl' et encore une fois pour les normales,
				; et ex af,af' pour af' (le " ' " veut dire que c'est le variable shadow)
				; c'est plus rapide et plus petit qu'utiliser le stack.
				; mais, c'est vraiment nécéssaire garder tous ces variables ?
	ld	hl, microsec
	dec	(hl)
	jp	z, moins_une_milliseconde
	jp	fin_timer

J'en ai plus, mais maintenant je dois me coucher. Ah ! J'ai télécharger ton code mais il ne veut pas fonctionner pour moi, je reçois toujours une "ERRsorryYNTAX" :/ Demain j'essayerai de t'expliquer un peu le code de l'autre jour (s'il n y a personne qui te l'aura expliquer avant que moi wink).

23

par 1 ...etc pousser2nd: .db 0
Voici une petite explication du code: ld hl,pousser2nd
 cp k2nd ;si on a poussé 2nd
 jr z,_2nd
 ld (hl),0 ;si nous sommes ici, c'est qu'on ne pousse pas 2nd
...

_2nd:
 ld a,(hl)     ;retrouver le valeur de "pousser2nd"
 or a          ;or a = cp 0 (on pourrait aussi écrire "and a"), mais plus vite et plus petit.
 ret nz        ;si pousser2nd n'est pas 0 (c'est á dire, s'il est 1), nous n'avançons pas, nous quittons.
 inc (hl)      ;si on avance, il faut accroître pousser2nd

Ce que nous faisons: premièrement il faut voir si on a poussé 2nd. Si oui, nous allons à _2nd. Là, nous voyons si on a déjà poussé 2nd avec le variable pousser2nd. Si son valeur n'est pas 0, on l'a déjà poussé et ne l'a pas encore laissé, alors, nous ret (où jr/jp, ce que tu voudras).

 ld hl,_2nd
 cp k2nd ;si on a poussé 2nd
 jr z,_2nd
 ld (hl),0 ;$00 = nop
...

_2nd:
 nop
 ld (hl),$C9 ;je crois que C9 = ret. Quand on arrive ici, nous mettons $C9 (le valeur hex de "ret") au octet préalable.
...etc
Ici, quand on pousse 2nd, nous changeons le nop à ret (c'est "code automodifiable"). La prochaine fois qu'on y va, on ne pourra entrer à cause du "ret". C'est seulement quand on l'aura laissé qu'on pourra y accéder de nouveau, car alors on changera le ret pour un nop ($00, ce n'est qu'un petit délai).

24

Pourquoi utilises-tu des variables 16-bit ? Je crois qu'il serait plus efficace (et plus facile) d'utiliser des variables 8-bit.

Et d'autres commandes utiles:
ld hl,variable
ld a,(hl) ;1 octet, 7 "t-states"
...
ld (hl),a

ou si tu ne veux pas actualiser le variable, tu peux tout simplement:
ld a,(variable)

25

J'ai fait des optimisations un peu partout le programme et je l'ai changé un peu pour être compatible avec le 83 et le 83+ (je crois qu'il fonctionne encore avec le ti 83 !). Je sais pas si tu veux les voir.
Ici par exemple j'ai changé le code pour aficher le "map" (qui n'est qu'un sprite répété sur tout l'écran):
MAP_LOAD:
	ld hl,gbuf+(12*8)		;sauter les premiers 8 fils
	ld b,7
lm_loop:
	push bc
	ld c,8
	ld de,block
lm_loop_out
	ld b,10
lm_loop_in:
	ld a,(de)
	or (hl)
	ld (hl),a
	inc hl
	djnz lm_loop_in
	inc de
	inc hl
	inc hl
	dec c
	jr nz,lm_loop_out
	pop bc
	djnz lm_loop
lm_fin:
	; Afficher le robinet (depart)
    ld      e, 32
    ld      a, 80
    ld      hl, robinet 
    call    DRWSPR
	ret

Si tu affichais le pointeur aprés la grille, tu pourrais effacer le "ld a,(de) \ or (hl)". Et je crois bien que tous (ou presque tous) les push/pops sont superflus.

26

A deeph :
Donc tu vas être limité à ~8ko si mes souvenirs sont bon... Donc si jamais tu veux aller au delà je te conseil Ion, qui permettra d'avoir la compatibilité 83/83+.


Je n'utilise pas de shell et et mon code est squishé (2 fois plus long et 2 fois plus gros). Je pense utiliser Ion mais une fois le jeu fini seulement.
Ensuite si j'ai bien compris tu ne te sert de la matrice que pour l'algo de détection de victoire ? Si c'est le cas c'est assez dommage puisque l'utiliser pour tout (l'affichage notamment) ça optimiserait pas mal...


J'utilise la matrice pour tester si une case est prise et pour l'algo de fin. Je ne vois pas ce que cela pourrait optimiser si je l'utilisais pour l'affichage car je mets à jours qu'une case à la fois et je n'ai pas besoin de mémoire pour cela.

Je suis quasi persuadé qu'une enorme partie de mes push pop sont inutiles puisque je fais bien attention à ne pas utiliser des registres dont le contenu est incertain mais pour l'instant je préfère ne pas prendre de risque et tout sauver quitte à enlever ça progressivement.
Dans ce le jeu, il n'y a pas de problème de vitesse, c'est bien assez rapide et le restera quoi que je fasse. Le probleme c'est eventuellement la place (donc utiliser Ion pour avoir un code 2 fois plus petit) et optimiser donc le code mais pour gagner de la place.

A chickendude : Je ne connaissais pas dec (hl) merci ça va simplifier pas mal de trucs.

J'ai remarqué que :
ld ix, tube_test
and (ix)

ne se comporte pas comme :
and (tube_test)

Savez vous pourquoi ?

Pourquoi utilises-tu des variables 16-bit ? Je crois qu'il serait plus efficace (et plus facile) d'utiliser des variables 8-bit.


Bah generalement je n'utilise pas de variables 16bits si ce n'est pas utile, quelles sont celles dont tu parles?
ld (hl),$C9 ;je crois que C9 = ret. Quand on arrive ici, nous mettons $C9 (le valeur hex de "ret") au octet préalable.


Je confirme C9 = ret
Merci pour tous ces conseils smile

Je connais les registres cachés tongue pourrais tu cependant me donner un exemple d'utilisation.
Je dois faire 2 exx un avant pour echanger et un après pour remettre en place il me semble.

Merci beaucoup pour tout, je continue à travailler un peu sur ce projet, je pense qu'il sera releasé dans quelques semaines maxi (enfin j'espère).

Chickendude : je veux bien ta version modifiée, j'ai pas trop le temps ce soir on en reparle dans quelques jours si possible.





27

Contra (./26) :
A deeph :
Donc tu vas être limité à ~8ko si mes souvenirs sont bon... Donc si jamais tu veux aller au delà je te conseil Ion, qui permettra d'avoir la compatibilité 83/83+.

Je n'utilise pas de shell et et mon code est squishé (2 fois plus long et 2 fois plus gros). Je pense utiliser Ion mais une fois le jeu fini seulement.

Ton programme peut être plus de ~8k, mais tu ne pourras pas exécuter rien après ce point-là. Tu peux y mettre tous tes données -- les variables, la matrice, les textes (si tu en as), tout ça -- mais pas de codes exécutables.
Bah generalement je n'utilise pas de variables 16bits si ce n'est pas utile, quelles sont celles dont tu parles?

On voit par exemple:
xcoord	= saferam1+4
ycoord	= 	xcoord+2
oldxcoord	= 	ycoord+2
oldycoord	= 	oldxcoord+2
select_flag	= 	oldycoord+2
tub_index	= select_flag+2
Quand tu les utilises tu utilises toujours les registres 16bits, bien qu'il n'est pas possible qu'ils passent d'un octet.

Et je ne sais pas pourquoi ce code ne fonctionnerait pas, où l'utilises-tu ? A propos, ix/iy sont très lents et occupent beaucoup d'espace car ils prennent un décalage. Quand tu dis "and (ix)" le calc l'interprète comme "and (ix+0)".

Et quant aux registres "cachés" (grin), voici un morceau de code pour dessiner un sprite de 16x16 pixels:
	exx
		ld hl,saferam1	;donde guardar el mapa antes de dibujarlo a la pantalla, es decir, el gbuf
		ld de,13		;numero de columnas en gbuf menos uno (por el inc hl')
		ld bc,$0705	;dibujar 7 columnas y 5 filas de sprites (en la pantalla caben 6x4))
...
	exx
...
	ld b,16		;16 filas en sprite
dibSprite:
	ld a,(hl)	;pixeles del sprite a dibujar
	inc hl		;proximo conjunto de pixeles
	exx		;cambiar a registros alternativos
		ld (hl),a
		inc hl	;proximo byte en gbuf
	exx
	ld a,(hl)
	inc hl		;2º conjunto (pixels 16x16: 2 bytes de ancho)
	exx
		ld (hl),a
		add hl,de	;bajar a la proxima fila del gbuf
	exx
	djnz dibSprite
On se sert d'exx pour changer les registres bc, de et hl avec leurs équivalents cachés, et ex af,af' pour changer af avec af'. (une apostrophe veut dire que c'est un registre caché). Si tu n'as pas besoin de conserver leurs valeurs, il n'est pas comme la pile, si tu ne changes pas aux registres normales avant de quitter ce n'est pas grave. Le calc ne fait pas de distinction entre les deux et utilisera les cachés comme les normales.

28

DRWSPR:

        push    hl              ; Save sprite address

;ÛÛÛÛ   Calculate the address in graphbuf   ÛÛÛÛ
        ld      hl,0            ; Do y*12
        ld      d,l
        add     hl,de
        add     hl,de
        add     hl,de
        add     hl,hl
        add     hl,hl
        rra
        rra
        rra
        ld e,a
        add     hl,de

        ld      de,gbuf
        add     hl,de           ; Add address to graphbuf
ALIGN:                          ; Blit an aligned sprite to graphbuf
        pop     de              ; de->sprite
        ld      b,8
ALOP1:  ld      a,(de)
        or      (hl)            ; xor=erase/blit
        ld      (hl),a
        inc     de
        push    bc
        ld      bc,12
        add     hl,bc
        pop     bc
        djnz    ALOP1

DONE1:
        ret




;ÜÛÛÛÛÛÛÛÛÛÛÛÛß CLRSPR ßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
;³ Clear 8x8 sprite þ a=x, e=y, hl=sprite address                             ³
;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
CLRSPR:
        push    hl              ; Save sprite address

;ÛÛÛÛ   Calculate the address in graphbuf   ÛÛÛÛ
        ld      hl,0            ; Do y*12
        ld      d,l
        add     hl,de
        add     hl,de
        add     hl,de
        add     hl,hl
        add     hl,hl
		rra					; tous les sprites sont deja alignes
		rra					; x/8
		rra
        ld      e,a			; d=0
        add     hl,de

        ld      de,gbuf
        add     hl,de           ; Add address to graphbuf

ALIGN2:                         ; Erase an aligned sprite in graphbuf
        pop     de              ; de->sprite
        ld      b,8
ALOP2:  ld      a,(de)
        cpl
        and     (hl)
        ld      (hl),a
        inc     de
        push    bc
        ld      bc,12
        add     hl,bc
        pop     bc
        djnz    ALOP2

DONE5:
        ret
Chaque fois que tu affiches un sprite il est toujours aligné, pour ça tu peux effacer la partie qui s'agit des sprites non-alignés. (J'ai changé ton addresse pour gbuf pour être plus facile de compiler entre le 83/+).tromb Fichier joint : oilcap.zip

N'hésite pas à me demander si tu as des questions. Je ne me souviens pas de tout ce que j'ai fait, mais pour le moment jette un coup d'oeuil à:
move/select_scan_key
map_load
les algos pour afficher des sprites
le timer

Il faut aussi faire quelque chose pour que le timer n'aille pas si lentement quand on déplace le pointeur, mais je ne sais pas quoi.

Ah, et une dernière chose: tu peux utiliser saferam pour garder vos matrices et ainsi gagner de l'espace.

29

Bonjour/soir à tous,
hier soir j'ai joué un peu avec les interruptions et je crois que j'ai (finalement!) un bon timer basé sur les interruptions qui ne ralentit jamais pour ton jeu.

30

hier soir j'ai joué un peu avec les interruptions et je crois que j'ai (finalement!) un bon timer basé sur les interruptions qui ne ralentit jamais pour ton jeu.


euh tu es vraiment fort ...^^

Pour le timer sans interruption, une idee pour eviter les ralentissement serait de placer des "CALL UPDATE_TIMER" dans la partie keypress (il n'y en a pas du coup lorsqu'on se deplace on ne met pas à jour le timer). Mais si tu as réussi avec les interruptions je suis vraiment curieux de voi ça et l'adapter. Est-ce que cela va marcher sur ti83 "regular" ?
hier soir j'ai joué un peu avec les interruptions et je crois que j'ai (finalement!) un bon timer basé sur les interruptions qui ne ralentit jamais pour ton jeu.

Les sprites sont toujours alignés donc tu as raison c'est inutile pour le damier mais certains sprites utilisent cette routines sans etre aligné comme le tube suivant qui n'est pas forcement sur une case alignée. Je tiens à preciser que ce n'est pas ma routine mais celle de "movax" ...

Concernant la limite de 8k, j'ai eu ce probleme avec bomberman je crois.
Comment etre sur d'avoir que des données après les 8k?
Placer les includes des fichiers de données en dernier suffit j'imagine?

Concernant les variables 16 bits tu as raison c'est une erreur de ma part je n'ai pas fait attention.

Merci encore pour tous ces très très bon conseils. tu m'apprends beaucoup de choses.


Je n'ai pas eu beaucoup de temps cette semaine, j'en aurais surement un peu plus la semaine qui vient pour étudier tes améliorations et tes suggestions.

Merci encore grin