We've just updated MediaWiki and its underlying software. If anything doesn't look or work quite right, please mention it to us. --RanAS

SpriteCreationWithDyzen: Difference between revisions

From SnesLab
Jump to: navigation, search
Line 74: Line 74:
</ol>
</ol>
== State Machines ==
== State Machines ==
A state machine is made up of 2 main parts, the states and the transitions between states. In these machines, only one state executes at a time, and it changes according to logical conditions implemented within each state.
This isn't a complete course on state machines, because this material can take semesters of study for deepening all the distinct dimensions. Nevertheless, we will use this concept for putting together the logic of our sprite.
With this scheme, the idea is to take the central routine called StateMachine, which will be used for calling the correct routine according to the state that's executing. To do this, we will need a table of sprites which we'll use for this purpose. It's highly recommended to use a misc table, so we don't need to find freeram that can end up being used by other resources. For this we have to look at the top of the code, in the marked zone with the comments:
<pre>
;######################################
;############## Defines ###############
;######################################
</pre>
We can add the variable:
<pre>
!State = !SpriteMiscTable8
</pre>
Using one of the misc sprite tables that can be used for whatever purpose we want.
Once this is done, we will need to give this variable a value of 0. We will use the state 0 for our initial state. Now we mustn't always initialize it as 0. For example, we could use the extra byte or extra property to set the initial state of the sprite, to create different versions of the same sprite, but normally we use the state 0 as the initial state. To do this, we will add the line on '''SpriteInit''':
<pre>
STZ !State,x ;!State,x = 0
</pre>
Soon we'll create a routine named "StateMachine" that executes a different routine, depending on the variable <code>!State,x</code>. This routine will be the following:
<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>
We can note that this routine uses a table named "States". In this table, we will put all the states that our sprite can have as it's running, being stopped, turning, dying, etc. It isn't necessary to put the name of the states "State0". Simply use the name that you think is most conventient. Now normally, it's recommended to number them because it serves to remember the value of the variable <code>!State,x</code> that's used to call each state.
For those that know some high level programming, this routine would be the equivalent of:
<pre>
switch(state)
{
case 0:
state0();
break;
case 1:
state1();
break;
case 2:
state2();
break;
case 3:
state3();
break;
etc...
}
</pre>

Revision as of 01:07, 27 March 2021

English Português Español 日本語

The following tutorial will explain how to create sprites using Dyzen. This tutorial covers not just how to use the tool, but also general functions for the creation of regular, cluster, and extended sprites.

For this tutorial, it's assumed that the developer has previous knowledge of ASM like using basic commands, branching, and indexing. This tutorial is based more on how to construct the logic of a sprite.

Also, it should be noted that this tutorial can also serve for sprites which are not created with Dyzen, though the focus is ultimately based on those.

Sprite Structure

A sprite is structured in the following manner:

  1. Sprite Init: This is the routine which occurs when the sprite is spawned. In Pixi, this routine begins with the line:
    print "INIT ",pc
    

    And should end with an RTL.

  2. Sprite Main: This routine is called in each Game Loop (SNES Frame) and is used for updating the sprite and its logic. In PIXI, this routine begins with the line:
    print "MAIN ",pc
    

    And should end with an RTL. Usually this routine would be like so:

    print "MAIN ",pc
    	PHB
    	PHK
    	PLB
    	JSR SpriteCode
    	PLB
    RTL
    

    This calls a routine named SpriteCode which will have the real contents of this routine. This is performed to better organize the code. Also, the Program Bank is set so that the tables can be indexed with short absolute indexing ($XXXX,x o $XXXX,y), instead of using long indexing, optimizing the number of cycles the code uses.

  3. SpriteCode: It basically contains the Main routine, as described above. This routine is called by others which will carry out the logic of the sprite. We will separate these routines into DynamicRoutine, GraphicRoutine, InteractionWithPlayer, InteractionWithSprites, StateMachine, AnimationRoutine, etc., depending on whatever the sprite requires. The basic structure of this routine is:
    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
    

    Here we can take note of 2 main zones (blocks of code):

    • .AlwaysExecutedZone which encompasses the area from the beginning of the routine until the first check LDA !SpriteStatus,x. This zone always runs, even if the game is paused or the animations are stopped, normally we don't put a lot of code in this zone, except for graphics routines.
    • .ExecutedIfNotLocked encompasses the area after the check LDA !LockAnimationFlag. This zone runs when the animations aren't stopped, the game isn't paused, or the player is not in the death animation, etc. Also, it should be clarified that this sector is only executed if the !SpriteStatus,x has the value 8. This means that the sprite has the status "Normal Routine". This RAM address corresponds with the table $14C8. It should be noted that the check of !SpriteStatus,x can be modified so that the sprite executes the code in other statuses. One common state is 2, which means the sprite is dying. In this area, we can note that it calls other routines that we're going to detail further along in the tutorial. For now, it's important to know that below, we call JSR InteractMarioSprite. This is where we will execute the code for the sprite's logic.

State Machines

A state machine is made up of 2 main parts, the states and the transitions between states. In these machines, only one state executes at a time, and it changes according to logical conditions implemented within each state.

This isn't a complete course on state machines, because this material can take semesters of study for deepening all the distinct dimensions. Nevertheless, we will use this concept for putting together the logic of our sprite.

With this scheme, the idea is to take the central routine called StateMachine, which will be used for calling the correct routine according to the state that's executing. To do this, we will need a table of sprites which we'll use for this purpose. It's highly recommended to use a misc table, so we don't need to find freeram that can end up being used by other resources. For this we have to look at the top of the code, in the marked zone with the comments:

;######################################
;############## Defines ###############
;######################################

We can add the variable:

!State = !SpriteMiscTable8

Using one of the misc sprite tables that can be used for whatever purpose we want.

Once this is done, we will need to give this variable a value of 0. We will use the state 0 for our initial state. Now we mustn't always initialize it as 0. For example, we could use the extra byte or extra property to set the initial state of the sprite, to create different versions of the same sprite, but normally we use the state 0 as the initial state. To do this, we will add the line on SpriteInit:

	STZ !State,x ;!State,x = 0

Soon we'll create a routine named "StateMachine" that executes a different routine, depending on the variable !State,x. This routine will be the following:

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
	.
	.
	.

We can note that this routine uses a table named "States". In this table, we will put all the states that our sprite can have as it's running, being stopped, turning, dying, etc. It isn't necessary to put the name of the states "State0". Simply use the name that you think is most conventient. Now normally, it's recommended to number them because it serves to remember the value of the variable !State,x that's used to call each state.

For those that know some high level programming, this routine would be the equivalent of:

switch(state)
{
	case 0:
		state0();
		break;
	case 1:
		state1();
		break;
	case 2:
		state2();
		break;
	case 3:
		state3();
		break;
	etc...
}