es/SpriteCreationWithDyzen: Difference between revisions
No edit summary |
No edit summary |
||
Line 73: | Line 73: | ||
== Maquinas de Estado == | == Maquinas de Estado == | ||
Una Maquina de estados esta conformada por 2 partes principales, los estados y las transiciones entre estados. En estas maquinas, se ejecuta solo un estado al mismo tiempo y este cambia según las condiciones lógicas implementadas a los estados que son alcanzables desde este. | |||
No se planea hacer un curso completo sobre maquinas de estados, ya que, esta materia puede tomar semestres de estudios para profundizar todas sus distintas dimensiones, sin embargo, utilizaremos este concepto para armar la lógica de nuestro sprite. | |||
En este esquema la idea es tener una rutina central que llamaremos <code>StateMachine</code> que sera utilizada para llamar a la rutina correcta según el estado que es ejecutado. Para esto necesitaremos una tabla de sprites que usaremos con este proposito, se recomienda sobretodo una tabla misc, ya que, asi no necesitamos buscar freerams que pueden terminar siendo utilizadas para otros recursos, para esto podemos dirigirnos al tope del codigo y en la zona demarcada con los comentarios: | |||
<pre> | |||
;###################################### | |||
;############## Defines ############### | |||
;###################################### | |||
</pre> | |||
Podemos agregar la variable: | |||
<pre> | |||
!State = !SpriteMiscTable8 | |||
</pre> | |||
Utilizando una de las tablas Misc. de sprites que pueden ser usadas para cualquier proposito que desees. | |||
Una vez hecho lo anterior necesitaremos poner esta variable con el valor 0, usaremos el estado 0 para nuestro estado inicial, ahora no siempre podemos iniciarlo en 0, podríamos por ejemplo, hacer que a través del extra byte o el extra property, darle el estado inicial al sprite, con el fin de generar distintas versiones del mismo sprite, pero lo más usual es usar el estado 0 como estado inicial. Para esto en el el '''SpriteInit''', agregaremos la linea: | |||
<pre> | |||
STZ !State,x ;!State,x = 0 | |||
</pre> | |||
Luego de esto crearemos una rutina llamada "StateMachine" que ejecutara una rutina distinta dependiendo de la variable <code>!State,x</code>. Esta rutina, sera la siguiente: | |||
<pre> | |||
StateMachine: | |||
LDA !State,x ;A Reg = !State,x | |||
ASL | |||
TAX ;Transform A Reg into a index value for table States and put that value in the X Reg | |||
JSR (States,x) ;Call Routine on the table States using X reg value. | |||
RTS | |||
States: | |||
dw State0 | |||
dw State1 | |||
dw State2 | |||
. | |||
. | |||
. | |||
</pre> | |||
Podemos notar que esta rutina utiliza una tabla llamada "States", en esta tabla pondremos todos los estados que tenga nuestro sprite como correr, estar detenido, voltear, morir, etc. No es necesario ponerle de nombre a los estados "State0", simplemente usa el nombre que veas más conveniente, ahora normalmente se recomienda enumerarlos, ya que, sirve para recordar que valor de la variable <code>!State,x</code> llama a cada estado. | |||
Para aquellos que conocen algun lenguaje de programación de alto nivel, esta rutina seria el equivalente a: | |||
<pre> | |||
switch(state) | |||
{ | |||
case 0: | |||
state0(); | |||
break; | |||
case 1: | |||
state1(); | |||
break; | |||
case 2: | |||
state2(); | |||
break; | |||
case 3: | |||
state3(); | |||
break; | |||
etc... | |||
} | |||
</pre> | |||
Esta rutina la pondremos en cualquier sector debajo de la rutina "SpriteCode", solo intenta ser ordenado, ya que, en ASM es muy fácil que el código quede hecho un desastre. Una vez creada esta rutina, la llamaremos en la zona de la rutina "SpriteCode" que sucede antes del <code>JSR AnimationRoutine</code>. Sin embargo, en este momento si probamos el sprite ahora mismo, no va a poder ser insertado, ya que, los labels de los estados no han sido creado asi que debemos crear cada uno de los estados. | |||
=== Estructura de un Estado === | === Estructura de un Estado === | ||
=== Condiciones y Transiciones === | === Condiciones y Transiciones === | ||
== Movimiento == | == Movimiento == | ||
=== Movimiento Básico === | === Movimiento Básico === |
Revision as of 01:35, 22 March 2021
English | Português | Español | 日本語 |
En el siguiente tutorial se explicara como crear Sprites utilizando Dyzen. Este tutorial cubre no solo el como utilizar el tool, sino que además, cubre diversos comportamientos recurrentes en la creación de sprites normales, clusters y extended.
Para este tutorial se presume que el desarrollador tiene conocimientos previos de ASM como el uso de comandos básicos, branching e indexación. Este tutorial esta basado más en como construir la lógica de un sprite.
También debe notarse que este tutorial también puede servir para sprites que no son creados con Dyzen aunque el foco este basado en este ultimo.
Creando un CFG/JSON con CFG Editor
Estructura de un sprite
Un sprite se estructura de la siguiente manera:
-
Sprite Init: Es la rutina que ocurre cuando el sprite es creado. En Pixi esta rutina inicia con la linea:
print "INIT ",pc
Y debe terminar con un RTL.
-
Sprite Main: Esta rutina es llamada en cada logic loop del juego y se utiliza para actualizar al sprite y su logica. En pixi esta rutina inicia con la linea:
print "MAIN ",pc
Y debe debe terminar con un RTL. Usualmente esta rutina sera de esta manera:
print "MAIN ",pc PHB PHK PLB JSR SpriteCode PLB RTL
Llamando a una rutina llamada SpriteCode que sera el contenido real de esta rutina. Se realiza esto con el fin de mantener un mejor orden en el codigo y además setear el Program Bank para que se puedan indexar las tablas con indexación corta ($XXXX,x o $XXXX,y), en ves de usar indexación larga y asi disminuir la cantidad de ciclos en el codigo.
- SpriteCode: Es basicamente el contenido de la rutina Main previamente descrita. Esta rutina llamara a otras que haran la logica del sprite, separaremos estas rutinas en DynamicRoutine, GraphicRoutine, InteractionWithPlayer, InteractionWithSprites, StateMachine, AnimationRoutine, entre otras, dependiendo de que requiera el sprite. Una estructura basica de esta rutina es:
SpriteCode: .AlwaysExecutedZone JSR GraphicRoutine ;Calls the graphic routine and updates sprite graphics ;Here you can put code that will be excecuted each frame even if the sprite is locked LDA !SpriteStatus,x CMP #$08 ;if sprite dead return BNE Return LDA !LockAnimationFlag BNE Return ;if locked animation return. .ExecutedIfNotLocked %SubOffScreen() JSR InteractMarioSprite ;After this routine, if the sprite interact with mario, Carry is Set. ;Here you can write your sprite code routine ;This will be excecuted once per frame excepts when ;the animation is locked or when sprite status is not #$08 JSR AnimationRoutine ;Calls animation routine and decides the next frame to draw RTS Return: RTS
Donde podemos notar 2 zonas principales:
- .AlwaysExecutedZone que comprende el sector desde el inicio de la rutina hasta el primer chequeo
LDA !SpriteStatus,x
. Esta zona ocurre siempre, incluso si el juego esta en pausa o las animaciones bloqueadas, normalmente no pondremos mucho codigo en esta zona salvo por la rutina gráfica. - .ExecutedIfNotLocked que comprende el sector despues del chequeo
LDA !LockAnimationFlag
, esta zona ocurre cuando las animaciones no estan bloqueadas, o sea cuando el juego no esta pausado o el player no esta en animación de muerte o similares, tambien. Tambien debe aclararse que este sector solo es ejecutado si el!SpriteStatus,x
tiene el valor 8, esto significa que el el sprite esta con el status "Rutina Normal", esta dirección de RAM corresponde con la tabla $14C8, cabe destacar que modificando el chequeo del!SpriteStatus,x
se puede hacer que el sprite ejecute el codigo en otros status, siendo uno de los más comunes el 2 que ocurre cuando el sprite esta muriendo. En este sector podemos notar que se llaman a otras rutinas que iremos detallando a lo largo del tutorial, lo importante que debemos saber aca es que debajo de la del llamadoJSR InteractMarioSprite
es donde ejecutaremos el codigo de la lógica del sprite.
- .AlwaysExecutedZone que comprende el sector desde el inicio de la rutina hasta el primer chequeo
Maquinas de Estado
Una Maquina de estados esta conformada por 2 partes principales, los estados y las transiciones entre estados. En estas maquinas, se ejecuta solo un estado al mismo tiempo y este cambia según las condiciones lógicas implementadas a los estados que son alcanzables desde este.
No se planea hacer un curso completo sobre maquinas de estados, ya que, esta materia puede tomar semestres de estudios para profundizar todas sus distintas dimensiones, sin embargo, utilizaremos este concepto para armar la lógica de nuestro sprite.
En este esquema la idea es tener una rutina central que llamaremos StateMachine
que sera utilizada para llamar a la rutina correcta según el estado que es ejecutado. Para esto necesitaremos una tabla de sprites que usaremos con este proposito, se recomienda sobretodo una tabla misc, ya que, asi no necesitamos buscar freerams que pueden terminar siendo utilizadas para otros recursos, para esto podemos dirigirnos al tope del codigo y en la zona demarcada con los comentarios:
;###################################### ;############## Defines ############### ;######################################
Podemos agregar la variable:
!State = !SpriteMiscTable8
Utilizando una de las tablas Misc. de sprites que pueden ser usadas para cualquier proposito que desees.
Una vez hecho lo anterior necesitaremos poner esta variable con el valor 0, usaremos el estado 0 para nuestro estado inicial, ahora no siempre podemos iniciarlo en 0, podríamos por ejemplo, hacer que a través del extra byte o el extra property, darle el estado inicial al sprite, con el fin de generar distintas versiones del mismo sprite, pero lo más usual es usar el estado 0 como estado inicial. Para esto en el el SpriteInit, agregaremos la linea:
STZ !State,x ;!State,x = 0
Luego de esto crearemos una rutina llamada "StateMachine" que ejecutara una rutina distinta dependiendo de la variable !State,x
. Esta rutina, sera la siguiente:
StateMachine: LDA !State,x ;A Reg = !State,x ASL TAX ;Transform A Reg into a index value for table States and put that value in the X Reg JSR (States,x) ;Call Routine on the table States using X reg value. RTS States: dw State0 dw State1 dw State2 . . .
Podemos notar que esta rutina utiliza una tabla llamada "States", en esta tabla pondremos todos los estados que tenga nuestro sprite como correr, estar detenido, voltear, morir, etc. No es necesario ponerle de nombre a los estados "State0", simplemente usa el nombre que veas más conveniente, ahora normalmente se recomienda enumerarlos, ya que, sirve para recordar que valor de la variable !State,x
llama a cada estado.
Para aquellos que conocen algun lenguaje de programación de alto nivel, esta rutina seria el equivalente a:
switch(state) { case 0: state0(); break; case 1: state1(); break; case 2: state2(); break; case 3: state3(); break; etc... }
Esta rutina la pondremos en cualquier sector debajo de la rutina "SpriteCode", solo intenta ser ordenado, ya que, en ASM es muy fácil que el código quede hecho un desastre. Una vez creada esta rutina, la llamaremos en la zona de la rutina "SpriteCode" que sucede antes del JSR AnimationRoutine
. Sin embargo, en este momento si probamos el sprite ahora mismo, no va a poder ser insertado, ya que, los labels de los estados no han sido creado asi que debemos crear cada uno de los estados.