PDA

Voir la version complète : [GBA][Aide] Sprite pas carré... ni -tall-... ni -wide-. Comment faire ?


Frenecrid-Jae
15/06/2006, 01h17
Salut,

Je tente d'intégrer à mon code le poisson qui se trouve dans ce PNG (honteusement piqué sur ShyGuy Kingdom :ph34r: ) :

http://tsgk.captainn.net/dld.php?s=gba&f=castlevaniaariaofsorrow_enemies-aquatic_sheet.png

J'ai utilisé USENTI de TONC qui m'a sortie une source que j'ai vérifié mais pas encore testé. Seulement après le triturage graphique du PNG pour extraire le poisson (une seule des images pour l'instant), j'en suis arrivé à le décomposer en 4x3 tiles, soit 32x24 pixels, et dans l'en-tête du fichier je vois bien marqué "12 tiles 4x1 metatiles".

Viens ensuite la définition des attributs du sprite en question. Et là, c'est le drame. Il n'est pas possible de définir un sprite de cette forme (4x3 pour ceux qui suivent pas). Du 32x16, 32x32, oui, mais 32x24 non. Du coup comment dire à la GBA que je souhaite que mon sprite soit composés des tiles, disons, 0 à 11 ??

Est-ce que je doit jouer subtilement (mais j'aimerai éviter, je suis un bourrin) et former mon sprite avec 2 groupes d'attributs de sprites de forme différentes (ou 3 attributs de même forme), ou il existe un moyen de spécifier ça autrement, que je n'ai pas plusieurs attributs pour former le même sprite ?

Kyros
15/06/2006, 01h45
Bonsoir ,

Si j'ai tout bien compris ... pourquoi ne pas faire en sorte que ton image source fasse 32x32 ( soit tu mets le poisson au centre , soit tu le met en haut ainsi les tiles du bas seront vides ) ? Ca serait plus simple il me semble et ca tomberait pile dans une de taille des sprites GBA .

Ou alors comme tu dis tu utilises les tiles 0 à 11 puis tu réserves les 12 à 15 , qui seront des tiles vides ( on revient au même cas ) .

Ou encore comme tu proposes, tu fais un sprites de 32x16 plus un sprites de 32x8 , et faut faire en sorte qu'ils soient toujours ensembles .

Enfin perso' j'opte pour la 1er solution ... ceci dit je connais pas Usenti ... j'connais juste paint shop et GBAgraphics :wub: .

^^ .

Nesgba
15/06/2006, 02h42
sachant que lorsque tu crée un sprite de 32x32 pour y stocker du 32x24 il te faut le combler de tiles vides donc pense a te reserver un tile vide (en principe le premier de ton tilset de sprite)
sinon l'autre solution qu'a proposé kyrios a l'avantage de t'eviter d'avoir a copier des tiles vides. donc au lieu d'avoir un seul sprite tu en a 2 (ou plus si y'en a besoin), c'est tres courrament utilisé dans les jeu pro.

il faut quand meme un moteur beton pour gerer tout ca, genre tu lui envoie un sprite de n'importe quele taille il te sort la configuration sprite/tiles la plus optimisée et te l'affiche sans que tu ai besoin d'y toucher =_= (faut pas non plus qu'il te sorte 1 tile = 1 sprite cf: magicwp -> prehistoric man :p)

Frenecrid-Jae
15/06/2006, 14h29
Si je fais en sorte que mon image ait une taille directement géré par la GBA, je me retrouve avec des tiles qui ne servent pas, prenant inutilement de la place en mémoire vidéo, où sont rangés les tile-set des sprites. L'avantage est que je n'ai pas à gérer plusieurs attributs d'objet dans OAM, un seul suffit pour le sprite entier. Je suis d'accord avec toi Kyros c'est la méthode la plus simple mais ce qui m'ennuie c'est la perte de place qu'engendre cette technique.

Je peux aussi, comme le suggères Nesgba, gérer mon sprite en insérant en mémoire uniquement les tiles nécessaires et en le découpant en plusieurs "sous-sprite" dont chacun aura son attribut propre. Charge à moi de faire en sorte que les deux attributs soient gérés ensemble pour faire apparaitre le sprite dans son entier. Mais là aussi apparaît un problème d'optimisation mémoire puisque un sprite sera en fait composé de plusieurs sprites avec chacun occupant un attribut en mémoire. Il est possible d'afficher au maximum 128 sprites et je me demande si cette méthode ne risque pas de me faire atteindre la limite plus vite que prévu.

c'est tres courrament utilisé dans les jeu pro

Je veux bien te croire. Et ca me parait fort probable étant donné que l'on peut trouver dans certains jeux des monstres occupant un tier de l'écran, ce qui est très gros sachant que le maximum gérable par un attibut est de 64x64 pixels. J'ai cherché des articles sur le net qui pourraient traiter de la gestion des sprites sur GBA mais je n'ai pu trouver aucun article expliquant comment faire un moteur de sprite. Est-ce que tu aurais connaissance d'un lien vers un article de ce genre ?

thoduv
15/06/2006, 14h35
Si je fais en sorte que mon image ait une taille directement géré par la GBA, je me retrouve avec des tiles qui ne servent pas, prenant inutilement de la place en mémoire vidéo, où sont rangés les tile-set des sprites. L'avantage est que je n'ai pas à gérer plusieurs attributs d'objet dans OAM, un seul suffit pour le sprite entier. Je suis d'accord avec toi Kyros c'est la méthode la plus simple mais ce qui m'ennuie c'est la perte de place qu'engendre cette technique.

Je peux aussi, comme le suggères Nesgba, gérer mon sprite en insérant en mémoire uniquement les tiles nécessaires et en le découpant en plusieurs "sous-sprite" dont chacun aura son attribut propre. Charge à moi de faire en sorte que les deux attributs soient gérés ensemble pour faire apparaitre le sprite dans son entier. Mais là aussi apparaît un problème d'optimisation mémoire puisque un sprite sera en fait composé de plusieurs sprites avec chacun occupant un attribut en mémoire. Il est possible d'afficher au maximum 128 sprites et je me demande si cette méthode ne risque pas de me faire atteindre la limite plus vite que prévu.



Je veux bien te croire. Et ca me parait fort probable étant donné que l'on peut trouver dans certains jeux des monstres occupant un tier de l'écran, ce qui est très gros sachant que le maximum gérable par un attibut est de 64x64 pixels. J'ai cherché des articles sur le net qui pourraient traiter de la gestion des sprites sur GBA mais je n'ai pu trouver aucun article expliquant comment faire un moteur de sprite. Est-ce que tu aurais connaissance d'un lien vers un article de ce genre ?

Pour voir comment font les jeux pros, je te conseille (:hum:) de récupérer une ou deux ROMS (c'est pour la bonne cause), de les lancer dans VBA et de regarder dans le "Visualisateur OAM". Tu va voir c'est impressionant: non seulement les images sont coupés en 2 ou en 4 sprites, mais en plus leur ID varie sans arret... :S
Comme le disais Nes, les jeux commerciaux on un moteur de gestion des sprites béton ... ;)

Je n'ai jamais vu d'articles expliquant comment faire un moteur de sprites, mais sans aller aussi loin, si tu as juste quelques sprites coupés en deux à gerer ca ne devrait pas poser trop de problèmes. Après si tu en a plus .... :whst:

Nesgba
15/06/2006, 15h27
il faut que tu oublie la gestion "hard" tu doit creer un moteur haut niveau, essaye de partir sur ce principe la.

moi quand j'ai a coder un truc j'essaye de parler a mon programme et voir comment il pourrai me repondre (oui je suis bien perché aussi :p)

exemple pour un moteur tres simpliste:

moi:
crée moi un sprite de 129*56 en 256 couleurs (il est bien le 129 la hein :D)

reponse moteur(selon les tailles de sprites dispo en hard):
largeur = 64+64+8
hauteur = 32+16+8

tableau des sprites utilisés:
(64*32) (64*32) (8*32)
(64*16) (64*16) (8*16)
(64*8) (64*8) (8*8)

total brute nb sprites: 3*3 = 9 sprites utilisés
total pixels: (64+64+8)*(32+16+8) = 7616 pixels
total tiles: ((64/8)+(64/8)+(8/8))*((32/8)+(16/8)+(8/8)) = 289 tiles

il faut pas croire qu'un moteur desprite est puissant parcque ca bouge partout dans l'oam, quand tu regarde bien l'exemple que je vien de faire est utilisé dans certains de jeux commerciaux pourtant il pourrai etre largement optimisé (notament sur le nombre de sprites utilisés) mais bon faut voir si ton moteur est gourmand en sprites ou non et surtout eviter les sprites de taille batard.

ps: oui comme le dit thoduv vba est ton ami ;)

MIKEGBA
15/06/2006, 15h42
:) Yop !

ben, moi franchement, le premier conseil que j'aurais a donné concernant le sujet, ben c'est toujours le même :

En fait, le premier truc à faire est de faire un prévisionnel de tes besoins en nombre de tiles et en nombre de sprite pour ton projet.

Parce que finalement , tu vas peut être t'appercevoir qu'avec 60 sprites, tu en as encore de trop, et que concernant la mémoire graphique pour les tiles, tu vas peut etre en utiliser aussi que la moitié. ( déja en passant à 16 couleurs, tu gagnes 50% de place en ram de tile.... ;) )

Conclusion, tu gacheras peut etre de la ram de tile , mais finalement ça t'empechera peut etre pas de boucler le projet, et ça t'évitera peut etre de faire un moteur de sprite qui ne te servira à rien pour le projet lui même ! ( à par pour l'aspect pédagogique de la chose ! )

à plus !

Alekmaul
15/06/2006, 16h54
Une autre solution, utilisée dans certains jeux commerciaux est de mettre à jour dynamiquement la mémoire tile pour le sprite concerné.
Ainsi, un sprite utilise toujours le même emplacement et c'est la mise à jour de la mémoire tile du sprite à chaque 'n' frames qui permet de modifier le graphique de ce dernier (exemple : un héro qui marche). On peut alors gérer tout plein de graphiques pour les sprites.
[MODE ATTACK NESGBA :whst: ON] Il va de soit que la mise à jour de la mémoire tile est mise à jour rapidement via des copies DMA ...
[MODE ATTACK NESGBA :whst: OFF] :D

MIKEGBA
15/06/2006, 17h05
:D [MODE DEFENSE NESGBA ON]

Il va de soit q'une bonne copie software bien optimisée est plus rapide qu'une copie dma particulierement si il faut copier des bout de tile non contigus en ram et sans danger pour la stabilité de cette bonne vieille gba... sans parler des recommandations de BigN à ce sujet ! :D

[MODE DEFENSE NESGBA OFF]

Alekmaul
15/06/2006, 17h26
:D Oui, il va de soit que pour ce genre de chose, il ne vaut mieux pas faire de copie DMA, c'est juste une vieille histoire entre nesgba et moi.
Par contre, MIKEGBA, toi qui est le roi de ASM (euh ... non, l'ARM :p ), est-ce qu'un ch'tit bout de code ARM pour copier un morceau de mémoire d'une source vers une destination est plus rapide qu'une bonne vieille boucle for où est-ce que le compilateur transforme la boucle en copie rapide à la compilation ?

Brunni
15/06/2006, 17h30
Je serais aussi très intéressé d'avoir un exemple de routine style memcpy/memmove/memset ultra rapide en software :)

MIKEGBA
15/06/2006, 17h37
:D Oui, il va de soit que pour ce genre de chose, il ne vaut mieux pas faire de copie DMA, c'est juste une vieille histoire entre nesgba et moi.
Par contre, MIKEGBA, toi qui est le roi de ASM (euh ... non, l'ARM :p ), est-ce qu'un ch'tit bout de code ARM pour copier un morceau de mémoire d'une source vers une destination est plus rapide qu'une bonne vieille boucle for où est-ce que le compilateur transforme la boucle en copie rapide à la compilation ?

...euh, c'est gentil Alek, mais à part être régulierement le roi à la maison quand on fait la galette :king: ( ...et encore parce que je triche avec la fève ), je vois pas de quoi d'autre je suis le roi...


....sinon, pour la copie ASM versus une copie boucle for en C, et bien d'aprés les bouts de code que j'ai pu voir générés par des compilos à partir de boucle de ce type, ben vaut mieux faire la fonction soit meme en ASM, surtout que c'est un type de code relativement simple à écrire.:)
ça serait dommage de s'en priver.

Nesgba
15/06/2006, 17h40
[MODE ATTACK NESGBA :whst: ON] Il va de soit que la mise à jour de la mémoire tile est mise à jour rapidement via des copies DMA ...
[MODE ATTACK NESGBA :whst: OFF] :D
:lol:

j'ai deja vu des jeux peu gourmands en tiles de sprites qui chargent toute une anim en memoire video sprite et qui modifient juste l'emplacement de la suite de tile dans les attributs du sprite, temp cpu = 0.
mais c'est difficile a faire sur une grosse animation :D

sinon alek tu peut faire un truc bien vicieu avec le hbl:

imagine que tu veuille creer des centaines de sprites de 8x8, tout d'abort tu crée des sprites a l'aide d'une structure, tu en crée dison 500 que tu place aleatoirement a l'ecran on les appelera les sprites 'phantom',
a chaque interuption de ligne tu va verifier si un sprite 'phantom' est sur cette ligne si tel est le cas tu prend son emplacement x et tu le copie sur l'attribut hard d'un sprite tu fait ca pour chaque sprite present sur la ligne.
et cela sur toute la hauteur de l'ecran.

donc cela va nous permettre d'afficher convenablement 160/8 = 20
20*128 = 2560 sprites hard :w00t:
puis qu'il y a quand meme la limite des 128 sprites tout les 8 pixels de haut (si on reattribue un sprite avant que le precedant soit fini d'etre affiché ben ca fait pas super joli)

c'est une technique assé farfelue mais bien marrante :D
bien entendu cette technique est ultra consommatrice en cpu et je l'ai jamais testée, si cela dit a quelqun de tester ^^

Alekmaul
15/06/2006, 17h45
....ben vaut mieux faire la fonction soit meme en ASM, surtout que c'est un type de code relativement simple à écrire.:)
ça serait dommage de s'en priver.
:notworthy :notworthy un exemple please, je suis nul en ARM ... :bigkiss:

Nesgba, je crois avoir déjà vu des démos qui font cela ... En tout cas, merci de l'info.

Brunni
15/06/2006, 17h47
Il y a aussi la limite du nombre de sprites par ligne que tu as oubliée nes ;)

Nesgba
15/06/2006, 17h48
Il y a aussi la limite du nombre de sprites par ligne que tu as oubliée nes ;)
ah oui j'ai oublié d'en parler, ca marche uniquement sur emulateur, sinon sur une vraie gba cela risque de faire assé bizzard effectivement :lol:

Frenecrid-Jae
15/06/2006, 22h56
ps: oui comme le dit thoduv vba est ton ami ;)

:w00t: Whaou! Je savais pas à quel point cet émulateur pouvais rendre service aux développeurs. La visualisation en temps réel des tiles et des palettes en mémoire est foutrement pratique, ya pas à discuter. Dommage que je n'ai pas vu ces fonctionnalité plus tôt, ça m'aurai aidé à comprendre certains point de la programmation GBA (surtout l'aspect graphique).

Maintenant je suis fixé concernant les animations des sprites. Il semblerai toutefois que les techiques d'animations utilisé par les moteurs pro ne privilégient pas une technique plus qu'une autre et selon le type représenté par le sprite (personnage du joueur, enemie, décor, ...) on a aussi bien la mise à jour directe de tile en mémoire que le chargement complet des anim'. Je viens de voir par exemple que les enemies ont seulement la mise à jour des attributs, le décor voit ses tiles mis à jour sans toucher aux attributs, et aussi le grand mix pour le joueur qui a les deux en même temps.

Bon, en fait je viens de voir ça sur 1 jeu seulement, mais je part du principe que ceux qui ont fait Metroid Fusion sont pas des branques. De toute façon je verrais plus tard avec d'autres jeux si c'est bien le cas. :rolleyes:

<idée>
Ce serai quand même bien de faire un papier sur la gestion des sprites sur GBA, un point que je trouve un petit peu "essentiel" si on veut pouvoir faire un jeu correcte. Et c'est dommage qu'on trouve rien là dessus sur la toile...
Enfin, moi je dis ça, je dis rien :whst:.
</idée>

Alekmaul
15/06/2006, 23h09
rhaaa, ok, y'a rien de vrai mais bon, regarde donc le dernier cours de l'afdac (le 7) sur le site http://afdac.org, tu auras quand même la base sur les registres à utiliser.
Ensuite, comme tu peux le voir sur ce topic, tout est question de point de vue / optimisation, à chacun sa technique pour gérer les sprites ...
Tiens, on a même pas parlé de la façon de gérer la compression hard avec la gba comme l'a fait Nrx, cela pourrait aussi servir pour les sprites à mon avis ;)

Nesgba
15/06/2006, 23h22
rhaaa, ok, y'a rien de vrai mais bon, regarde donc le dernier cours de l'afdac (le 7) sur le site http://afdac.org, tu auras quand même la base sur les registres à utiliser.
Ensuite, comme tu peux le voir sur ce topic, tout est question de point de vue / optimisation, à chacun sa technique pour gérer les sprites ...
Tiens, on a même pas parlé de la façon de gérer la compression hard avec la gba comme l'a fait Nrx, cela pourrait aussi servir pour les sprites à mon avis ;)

la decompression tu veut dire ? si c'est le cas c'est le bios qui gere ca donc je sais pas si on peut considerer ca comme "hard" :p

puis avec un moteur qui gere des tiles de facon dynamique c'est presque impensable d'utiliser une decompression en direct, a moin que tu mette tout tes tiles decompréssés en wram puis que tu fasse tes transfert wram->vram de facon dynamique. ;)

Alekmaul
16/06/2006, 10h31
Oui, Nesgba, la décompression, pardon, c'est ce que je voulais dire ...
Je testerais un jour pour voir ce que cela donne...

MIKEGBA
16/06/2006, 10h41
:) bon, pour ceux qui l'avait demandé, ci dessous un exemple concret de
routine en ASM de copie.

C'est vraiment concret, tiré de gt racers, c'est la routine qui efface l'écran à chaque frame et qui flippe les buffers hardware du mode 4.

C'est du code arm, donc 32 bits, il est donc efficace quand il est logé en iwram .

J'ai éssayé de commenter, ça devrait aller.

à plus !


DebutIwram:

/*****************************************/
/* */
/* EFFACE L'ECRAN ET FLIPPE LE BUFFER */
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
/* */
/*****************************************/

.align


EFFACE_ECRAN: Stmfd sp!,{r14}
ldr r2,Adr_1_MEMOIRE_VIDEO /* change l'adresse de la mémoire vidéo */
ldr r4,[r2]
mov r0,#AdresseRamVideo
cmp r4,r0
addeq r0,r0,#0xa000
str r0,[r2]

ldr r1,Adr_1_REG_DISPCNT /* flip le buffer haedware pour le mode 4 */
ldrh r2,[r1]
eor r2,r2,#0b10000
strh r2,[r1]

mov r14,#25 /* initialisation de la variable de boucle à 25 */
mov r1,#0 /* met à 0 les registres r1 à r12 */
mov r2,r1
mov r3,r2
mov r4,r2
mov r5,r2
mov r6,r2
mov r7,r2
mov r8,r2
mov r9,r2
mov r10,r2
mov r11,r2
mov r12,r2


loop_efface: stmia r0!,{r1-r12} /* efface l'écran */
stmia r0!,{r1-r12} /* routine débouclée répétée 25 fois */
stmia r0!,{r1-r12} /* chaque instruction stoque 12 registres à la fois */
stmia r0!,{r1-r12} /* 1 registre=32 bits, soit 48 octets par instruction */
stmia r0!,{r1-r12} /* r0 sert de pointeur pour l'adresse de destination */
stmia r0!,{r1-r12} /* et est incrémenté automatiquement avec le ! */
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}

stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}
stmia r0!,{r1-r12}

subs r14,r14,#1 /* décrémente la variable de boucle et test */
bne loop_efface /* répete la boucle si variable pas encore à 0 */

ldmfd sp!,{pc} /* retour */

Adr_1_REG_DISPCNT: .word REG_DISPCNT /* constantes utilisées pour la routine */
Adr_1_MEMOIRE_VIDEO: .word MEMOIRE_VIDEO

kinski
16/06/2006, 10h50
Hé Mike, il y a un article sur alten8 ce mois ci dans EDGE, mais les salauds ont pas mentionné votre projet :(

Alekmaul
16/06/2006, 11h15
Merci MikeGba , c'est sympa !

Brunni
16/06/2006, 11h25
Super merci, 'stmia' c'est donc ça le secret :ph34r:
Sinon je me demandais si tu n'avais pas aussi pareil mais pour copier des données? :whst:
Je verrais peut-être un ldmia suivi d'un stmia en boucle mais ça m'a l'air moyen quand même puisqu'on perd 2 fois plus de temps :(

MIKEGBA
16/06/2006, 11h54
Super merci, 'stmia' c'est donc ça le secret :ph34r:
Sinon je me demandais si tu n'avais pas aussi pareil mais pour copier des données stp? :whst:
Je verrais peut-être un ldmia suivi d'un stmia en boucle mais ça m'a l'air moyen quand même puisqu'on perd 2 fois plus de temps :(

copie de donnée à partir d'une adresse source, pareil avec effectivement un ldmia


r0 : adresse source
r1 : adresse destination
r14 : variable de boucle

ldmia r0!,{r2-r12}
stmia r1!,{r2-r12}

~~ débouclage

ldmia r0!,{r2-r12}
stmia r1!,{r2-r12}

subs r14,r14,#1
bne boucle...


1 instruction pour charger ldmia, 1 instruction pour stoquer stmia, de toute façon c'est impossible de faire autrement, le passage par les registres du cpu est obligatoire, il n'ya pas d'instruction pour copier d'une adresse A à une adresse B directement. ( à part le dma.... )

faut voire quand meme que l'avantage aussi c'est que les adresses source et destinations sont automatiquement incrémentées.

sinon, le débouclage , ça gagne pas mal de temps sur de grosses copies, tests en moins,branchement en moins. Les branchements, le cpu il aime pas beaucoup ça...

Brunni
16/06/2006, 12h15
Merci bien, j'espère pouvoir utiliser ça un jour :)
sinon, le débouclage , ça gagne pas mal de temps sur de grosses copies, tests en moins,branchement en moins. Les branchements, le cpu il aime pas beaucoup ça...
Ca va loin qd même, et le pire c'est que si tu passes sur GP2X par exemple, c'est exactement l'inverse: ta routine EFFACE_ECRAN serait en général plus lente qu'une boucle for (à cause du cache) ;)