Page 1 of 1

[FR][Axe][TUTO] Faire votre propre personnage

Unread postPosted: 29 Sep 2014, 20:58
by Hayleia
(En travaux, vous pouvez commencer mais rien ne dit que vous n'aurez pas à revenir sur ce que vous avez écrit. Par contre, vous pouvez spriter sans problèmes)
(Si vous êtes vraiment pressé, je vous rappelle que vous pouvez lire les codes sources de Fox et Falco dans le zip, ils devraient être assez lisibles)


Remarques Diverses

En utilisant la "méthode Axe" pour créer vos personnages, vous compilez en programme avant de convertir en appvar. C'est pourquoi j'utiliserai les termes "programme" et "appvar" indifféremment dans ce tutoriel.

Les noms des états, des touches, des labels, etc ayant été définis en anglais dans le smashh.inc (mentionné plus bas) ainsi que dans les codes de Fox et Falco (les personnages utilisés comme exemples de code ici), j'utiliserai dans ce tutoriel des noms anglais pour mes états, touches, labels, etc.

Il se peut aussi que les différents logiciels utilisés pour détokeniser le code ne soit pas toujours les mêmes d'un bout de code à l'autre. Vous verrez donc par exemple apparaître "^^r" et "^r" mais il faudra comprendre que c'est la même chose et que cela fait référence au r du menu Angle.

Si vous savez développer en Asm, je vous conseille de suivre le tutoriel Asm plutôt que celui-ci.


Remarques qui vous faciliteront la vie

Vous pouvez inclure SMASHH dans votre programme. Il ne contient que des définitions, ni code ni data, vous pouvez donc l'inclure où vous voulez dans votre programme.
Non seulement il rendra votre code plus lisible (vous écrirez °AirNull au lieu de pi00000011) mais il me permettra aussi de changer quelques spécifications (même si j'espère que ça n'arrivera jamais) sans que vous n'ayez à tout réécrire, il vous suffira de changer le SMASHH et de recompiler.

Je vous conseille aussi d'utiliser vos propres macros comme "38→°Gravity" afin de pouvoir facilement changer cette valeur partout où vous l'utilisez.


Comment les personnages fonctionnent, sans détails (les détails viendront...)

En deux mots, ils fonctionnent par états. Quand votre personnage se tient debout sans rien faire, il est dans un état qu'on pourrait appeler "Standing State". Votre personnage quittera cet état lors de l'appui sur Jump par exemple, pour aller dans le "Jumping State". Un autre exemple est le "Dashing State" (lorsque vous courez), qui se répète (pas exactement) jusqu'à ce que vous appuyez sur A ou Jump, etc.


Le Header

Cette étape est nécessaire pour que le jeu reconnaisse votre personnage et le liste dans le menu de sélection.

Le header commence par un octet, pour l'instant égal à 1. Cet octet est en réalité inutilisé mais dans le cas d'un changement de spécification (qui j'espère n'arrivera jamais), il sera incrémenté, afin que le programme sache quelle spécification votre personnage suit.

Vous avez ensuite besoin de la chaine de caractères "SSBOCHAR"[00]. C'est ce que le programme utilise pour reconnaître votre appvar en tant que personnage SSBO.

Les deux octets suivants représentent la taille du programme.

Vous utiliserez les 28 octets suivants pour décrire une icône 16x24 pour le menu de sélection de personnages.

Et vous terminez le header avec le nom de votre personnage (évidemment suivi d'un zéro).

Voici ce que cela peut donner par exemple si vous faites Fox :
Code: Select all
.FOXP
prgmSMASHH

[]→°FoxBEGIN
[01]
"SSBOCHAR"[00]
Data(°FoxEND-°FoxBEGIN^r)
[00000000000000000000000000000000000000000000000000000000]
"Fox"[00]
[]→°FoxEND


Informations Générales

Après le header, votre personnage devra comporter quelques informations auxquelles le jeu aura besoin d'accéder vite et/ou souvent. Dans cet ordre :
1 octet: gravité (inutilisé finalement, peut être recyclé)
1 octet: vitesse aérienne
1 octet: traction
1 octet: nombre maximal de sauts (2 en général, 5 pour Rondoudou)
2 octets: vitesse horizontale maximale (pas encore utilisée)

Vous devrez ensuite donner au programme les adresses des états auxquels il devra accéder rapidement. Un contre-exemple de ce type d'états est la deuxième frame du Down Aerial. Vous n'y accéderez qu'après la première frame. Cette première frame en revanche a besoin d'être vite trouvée lorsque le joueur demande un Down Aerial.
Toutes ces adresses prennent deux octets.
Puisque pour l'instant vous n'avez écrit aucun état et n'avez l'adresse d'aucun d'eux, mettez simplement l'adresse du Standing State partout et vous modifierez ceci au fur et à mesure que vous avancez.

Dans cet ordre :
Standing, Airing, Dashing, GroundJump, AirJump, Landing
AirNeutralSpecial, AirSideSpecial, AirDownSpecial, AirUpSpecial
GroundNeutralSpecial, GroundSideSpecial, GroundDownSpecial, GroundUpSpecial
DashAttack
SideSmash, DownSmash, UpSmash
NeutralAir, ForwardAir, BackAir, DownAir, UpAir
LedgeGrabbed

Une petite précision s'impose. L'Axe Parser compile les programmes "dans" la zone mémoire où ils seront exécutés. Pour les développeurs assembleur, je suis en train de dire qu'il n'y a aucun moyen de dire .org 0. Pourtant, les adresses dont je parle doivent être des adresses relatives au début de la data, pas des adresses absolues qui supposent de plus que le programme se trouvera dans une certaine place dans la mémoire.
Heureusement pour vous, vous vous trouvez sur le tutoriel Asm, nous allons nous faciliter la vie en utilisant .org 0. Remarquez cependant que bous avons déjà utilisé un .org 0 pour calculer la taille du programme. Si nous en ajoutons un, nous devons aussi ajouter un nouveau label de fin que nous ajouterons au précédent.

Voici donc ce l'on a pour l'instant.
Code: Select all
.FOXP
prgmSMASHH
38→°FoxGravity

[]→°FoxBEGIN
[01]
"SSBOCHAR"[00]
Data(°FoxEND-°FoxBEGIN^r)
[00000000000000000000000000000000000000000000000000000000]
"Fox"[00]

[]→°DB
Data(°FoxGravity)
Data(5)
Data(20)
Data(2)
Data(255^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r)

[]→°FoxStand
##that state is not done yet but since you wrote its adress above, you need that adress to exist

[]→°FoxEND
## dont forget that the °FoxEND must be the last line of your program, it's not because you wrote it at a previous step that what you add at the next step must be written after it


On a donc des accès rapides vers le Standing State... qu'on n'a pas implémenté. C'est donc ce que nous allons faire maintenant.


Les États

À MOITIÉ TRADUIT

Les états possèdent les champs suivants (explications en dessous) :
2x2 octets: pointeur vers sprite tournée vers la droite, pointeur vers sprite tournée vers la gauche
2x1 octets: teleportation (X,Y)
1x1 octet: flags
2x2 octets: vitesse
1x1 octet: influence des touches directionnelles
1x2 octets: adresse vers l'état suivant par défaut
<variable>: commandes
1x1 octet: 0, fin des commandes.

- Inutile d'expliquer l'utilité des sprites, seulement leur format sera détaillé. 1 octet pour la largeur en octets (largeur en pixels divisée par 8 ), 1 octet pour la hauteur en pixels, puis 1 bit par pixel dans l'ordre de lecture occidental.
- Le champ Téléportation est simple à comprendre aussi. Si vous voulez que le personnage voie sa position modifée à l'entrée de cet état, spécifiez ici la position relative à la position actuelle. Puisqu'il s'agit d'octets simples, il n'est pas possible d'aller plus loin que -128 ou +127. Et ceci n'est pas encore implémenté.
- Flags change the behaviour of your state.
--- °Inv when set will grant your character invincibility during that state (not implemented)
--- °Piv when set allows you to pivot (change the direction you're facing)
--- °AbsX when set will set your X speed to the specified X speed in the speed field, and when not set will add the X speed in that field to your current X speed
--- °AbsY is obviously the same for the Y speed
--- °SetKnockBack is unused
--- °GroundNull states that when in that state you are on the ground and can't use attacks
--- °GroundOK states that when in that state you are on the ground and can use attacks
--- °GroundDash states that when in that state you are on the ground and can use dash attacks
--- °AirNull states that when in that state you are in the air and can't use attacks
--- °AirOK states that when in that state you are in the air and can use attacks
--- °Aerial states that this state is an aerial attack (don't follow the example of the Fox I made, he doesn't use that flag when he should)
--- °Ledge states that you are currently holding a ledge
- Speed is the X speed and Y speed we mentionned when talking about °AbsX and °AbsY
- The arrow key influence is a number that, when non-zero, will allow your character to be moved horizontally during that state. It is for example used in the Air (falling) state but it may be set to zero in most attacks. The higher it is, the more the character can be moved of course.
- The adress to the next state by default is pretty straightforward too
- Commands (will) have their section below in that tutorial but are not used in the standing state so first read and understand the following example

The Standing state is a very simple example (plus, it's the state you gave the adress everywhere so it would rather be defined soon).
I am throwing it without more explanation because I don't know what to say, it you have questions, feel free to ask.

Code: Select all
.FOXP
prgmSMASHH
38→°FoxGravity

[]→°FoxBEGIN
[01]
"SSBOCHAR"[00]
Data(°FoxEND-°FoxBEGIN^r)
[00000000000000000000000000000000000000000000000000000000]
"Fox"[00]

[]→°DB
Data(°FoxGravity)
Data(5)
Data(20)
Data(2)
Data(255^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r,°FoxStand-°DB^r)
Data(°FoxStand-°DB^r)

[]->°FoxStand .état debout normal
Data(°FoxStandSprR-°DB^^r,°FoxStandSpr-°DB^^r) .sprite
Data(0,0) .téléportation
Data(°Piv+°GroundOK)
Data(0^^r,0^^r) .V
Data(0) .arrowkeys influence
Data(°FoxStand-°DB^^r) .état suivant par défaut
Data(0)

[021B]->°FoxStandSpr
[004000A001300208052407142834660EF1946FF821F4DCE2A4C794CF95C84E3863F037F80FFC0F3C0B1C079603DE01CE03DE039E010C]
[021B]->°FoxStandSprR
[020005000C80104024A028E02C147066298F1FF62F84473BE325F32913A91C720FC61FEC3FF03CF038D069E07BC073807BC079C03080]

[]→°FoxEND


Notice that flags can be added in the flags field. Writing "or" instead of "+" is advised however, in case you add twice the same flag (since or_ing it twice gives the same result as or_ing it once) but "+" is more compact so I use it.