# Visual Basic > Games and Graphics Programming > Game Demos >  NES 6502 Programming Tutorial - Part 4: Sprite Movement And Declaring Variables

## Jacob Roman

Hi and welcome back to my awesome NES 6502 programming tutorial. And today I am going to introduce you to two things. Sprite movement, because static sprites are boring as hell, and how to declare variables so we aren't putting up fixed constants. And as a unique twist, I am also going to show you how to load sprites from a database rather than hard-coding everything. Now before we get started, I just realized that drawing a sprite looked like a sloppy mess with this sub routine I wrote for you all:



```
DrawSprite:
  LDA #$08      ; Top of the screen
  STA $0200     ; Sprite 1 Y Position
  LDA #$08
  STA $0204     ; Sprite 2 Y Position
  LDA #$10
  STA $0208     ; Sprite 3 Y Position
  LDA #$10
  STA $020C     ; Sprite 4 Y Position
  LDA #$3A      ; Top Left section of Mario standing still
  STA $0201     ; Sprite 1 Tile Number
  LDA #$37      ; Top Right section of Mario standing still
  STA $0205     ; Sprite 2 Tile Number
  LDA #$4F      ; Bottom Left section of Mario standing still
  STA $0209     ; Sprite 3 Tile Number
  LDA #$4F      ; Bottom Right section of Mario standing still
  STA $020D     ; Sprite 4 Tile Number
  LDA #$00		; No attributes, using first sprite palette which is number 0
  STA $0202     ; Sprite 1 Attributes
  STA $0206     ; Sprite 2 Attributes
  STA $020A     ; Sprite 3 Attributes
  LDA #$40      ; Flip horizontal attribute
  STA $020E     ; Sprite 4 Attributes
  LDA #$08      ; Left of the screen.
  STA $0203     ; Sprite 1 X Position
  LDA #$10
  STA $0207     ; Sprite 2 X Position
  LDA #$08
  STA $020B     ; Sprite 3 X Position
  LDA #$10
  STA $020F     ; Sprite 4 X Position
```

And you won't believe that it would have looked a hell of a lot better if I just put in a little bit of organization:



```
DrawSprite:
;Y Positions
  LDA #$08      ; Top of the screen
  STA $0200     ; Sprite 1 Y Position
  LDA #$08
  STA $0204     ; Sprite 2 Y Position
  LDA #$10
  STA $0208     ; Sprite 3 Y Position
  LDA #$10
  STA $020C     ; Sprite 4 Y Position

;Tile Number From Attribute Table  
  LDA #$3A      ; Top Left section of Mario standing still
  STA $0201     ; Sprite 1 Tile Number
  LDA #$37      ; Top Right section of Mario standing still
  STA $0205     ; Sprite 2 Tile Number
  LDA #$4F      ; Bottom Left section of Mario standing still
  STA $0209     ; Sprite 3 Tile Number
  LDA #$4F      ; Bottom Right section of Mario standing still
  STA $020D     ; Sprite 4 Tile Number
  
;Sprite Attributes  
  LDA #%00000000		; No attributes, using first sprite palette which is number 0
  STA $0202     		; Sprite 1 Attributes
  STA $0206     		; Sprite 2 Attributes
  STA $020A     		; Sprite 3 Attributes
  LDA #%01000000      	; Flip horizontal attribute
  STA $020E     	  	; Sprite 4 Attributes
  
;X Positions  
  LDA #$08      ; Left of the screen.
  STA $0203     ; Sprite 1 X Position
  LDA #$10
  STA $0207     ; Sprite 2 X Position
  LDA #$08
  STA $020B     ; Sprite 3 X Position
  LDA #$10
  STA $020F     ; Sprite 4 X Position
```

Although that is much cleaner code (especially where we wrote $40 and changed it to something much cleaner such as #%01000000 to see the horizontal flip attribute bit), I think we should take it a step further and load it from a database. This actually saves wasted cpu cycles and does the same code, only we load from the beginning and draw later on. So we are going to load any of our database stuff over at where our other database stuff was loaded (such as palette data for sprites and the background) at the memory address E000.



```
  .bank 1
  .org $E000
background_palette:
  .db $22,$29,$1A,$0F	;background palette 1
  .db $22,$36,$17,$0F	;background palette 2
  .db $22,$30,$21,$0F	;background palette 3
  .db $22,$27,$17,$0F	;background palette 4
  
sprite_palette:
  .db $22,$16,$27,$18	;sprite palette 1
  .db $22,$1A,$30,$27	;sprite palette 2
  .db $22,$16,$30,$27	;sprite palette 3
  .db $22,$0F,$36,$17	;sprite palette 4
  
sprites:
     ;vert tile attr horiz
  .db $08, $3A, %00000000, $08   ;sprite 0
  .db $08, $37, %00000000, $10   ;sprite 1
  .db $10, $4f, %00000000, $08   ;sprite 2
  .db $10, $4f, %01000000, $10   ;sprite 3

```

Next, just before the RTI, delete the DrawSprite sub and all the code within it. After that, over where you are loading the palettes for the background and sprites, just right after, add this chunk of code to preload sprite data from the database:



```
LoadPalette:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006             ; write the high byte of $3F00 address
  LDA #$00
  STA $2006             ; write the low byte of $3F00 address
  LDX #$00              ; start out at 0
LoadBackgroundPaletteLoop:
  LDA background_palette, x        ; load data from address (palette + the value in x)
                          ; 1st time through loop it will load palette+0
                          ; 2nd time through loop it will load palette+1
                          ; 3rd time through loop it will load palette+2
                          ; etc
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadBackgroundPaletteLoop  ; Branch to LoadBackgroundPaletteLoop if compare was Not Equal to zero
  
  LDX #$00      
        
LoadSpritePaletteLoop:
  LDA sprite_palette, x     ;load palette byte
  STA $2007					;write to PPU
  INX                   	;set index to next byte
  CPX #$10            
  BNE LoadSpritePaletteLoop  ;if x = $10, all done

  LDX #$00              ; start at 0
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down 
```

By now your completed code should look like this:



```
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
  
;;;;;;;;;;;;;;;

  .bank 0
  .org $C000 
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40	
  STX $4017    ; disable APU frame IRQ
  LDX #$FF	
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs

vblankwait1:       ; First wait for vblank to make sure PPU is ready
  BIT $2002
  BPL vblankwait1

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
  BIT $2002
  BPL vblankwait2
  
LoadPalette:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006             ; write the high byte of $3F00 address
  LDA #$00
  STA $2006             ; write the low byte of $3F00 address
  LDX #$00              ; start out at 0
LoadBackgroundPaletteLoop:
  LDA background_palette, x        ; load data from address (palette + the value in x)
                          ; 1st time through loop it will load palette+0
                          ; 2nd time through loop it will load palette+1
                          ; 3rd time through loop it will load palette+2
                          ; etc
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadBackgroundPaletteLoop  ; Branch to LoadBackgroundPaletteLoop if compare was Not Equal to zero
  
  LDX #$00      
        
LoadSpritePaletteLoop:
  LDA sprite_palette, x     ;load palette byte
  STA $2007					;write to PPU
  INX                   	;set index to next byte
  CPX #$10            
  BNE LoadSpritePaletteLoop  ;if x = $10, all done

  LDX #$00              ; start at 0
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down 
  
  LDA #%10000000   ; enable NMI, sprites from Pattern Table 0
  STA $2000
  
  LDA #%00010000   ; enable sprites
  STA $2001

Foreverloop:
  JMP Foreverloop     ;jump back to Forever, infinite loop

NMI: 
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer
  
  RTI

;;;;;;;;;;;;;;  

  .bank 1
  .org $E000
background_palette:
  .db $22,$29,$1A,$0F	;background palette 1
  .db $22,$36,$17,$0F	;background palette 2
  .db $22,$30,$21,$0F	;background palette 3
  .db $22,$27,$17,$0F	;background palette 4
  
sprite_palette:
  .db $22,$16,$27,$18	;sprite palette 1
  .db $22,$1A,$30,$27	;sprite palette 2
  .db $22,$16,$30,$27	;sprite palette 3
  .db $22,$0F,$36,$17	;sprite palette 4
  
sprites:
     ;vert tile attr horiz
  .db $08, $3A, %00000000, $08   ;sprite 0
  .db $08, $37, %00000000, $10   ;sprite 1
  .db $10, $4f, %00000000, $08   ;sprite 2
  .db $10, $4f, %01000000, $10   ;sprite 3


;;;;;;;;;;;;;;  

  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
  
;;;;;;;;;;;;;;  

  .bank 2
  .org $0000
  .incbin "mario.chr"   ;includes 8KB graphics file from SMB1
```

Compile the code with your compile.bat file and run it in your emulator debugger. You should see that it did exactly the same thing, only in less code. And it loaded it from a database! But guess whaaaaaat!!! It's still a static sprite! BOOOORING!!!  :Sick:  I'd say let's move it!

So in order to move it, we will need to create a variable over at the address 0000. To do this, you will need to go to the top of your code right after your headers and put in the command .rsset $0000. This is where we can put any variables really. And we are going to create a variable called player_x and reserve 1 byte of space:



```
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
  
;;;;;;;;;;;;;;;
;DECLARE SOME VARIABLES HERE
  .rsset $0000  ;;start variables at ram location 0
  
player_x  .rs 1  ; .rs 1 means reserve one byte of space 
;;;;;;;;;;;;;;;
```

Next we are going to load info into player_x by storing whatever what was stored into the address $0203 to get the top left X position of the sprite:



```
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down 
  
  LDA #%10000000   ; enable NMI, sprites from Pattern Table 0
  STA $2000
  
  LDA #%00010000   ; enable sprites
  STA $2001
  
  LDA $0203
  STA player_x
```

Last but not least, in our main NMI loop, we are going to load data from player_x to get the X position, and store it ONLY in $0203 and $020B since they are the left furthest sprites. And since it's the main value to work with, we need to make a copy of this value to the X register by using the command TAX (Transfer A to X, but actually it's making a copy). Then we are going to add 8, and store into $0207 and $020F. All together, this stored the X positions of the sprite. Now to work with the X register by incrementing it with INX, and store the new value into player_x. When you loop it, it moves the entire sprite group across the screen over and over and over since in 6502 assembly, it loops byte values from $00 to $FF over and over. 



```
NMI: 
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer

  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  INX
  STX player_x
  
  RTI
```

Your completed code should now look like this:



```
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
  
  
;;;;;;;;;;;;;;;
;; DECLARE SOME VARIABLES HERE
  .rsset $0000  ;;start variables at ram location 0
  
player_x  .rs 1  ; .rs 1 means reserve one byte of space  
;;;;;;;;;;;;;;;

  .bank 0
  .org $C000 
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40	
  STX $4017    ; disable APU frame IRQ
  LDX #$FF	
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs

vblankwait1:       ; First wait for vblank to make sure PPU is ready
  BIT $2002
  BPL vblankwait1

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
  BIT $2002
  BPL vblankwait2
  
LoadPalette:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006             ; write the high byte of $3F00 address
  LDA #$00
  STA $2006             ; write the low byte of $3F00 address
  LDX #$00              ; start out at 0
LoadBackgroundPaletteLoop:
  LDA background_palette, x        ; load data from address (palette + the value in x)
                          ; 1st time through loop it will load palette+0
                          ; 2nd time through loop it will load palette+1
                          ; 3rd time through loop it will load palette+2
                          ; etc
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadBackgroundPaletteLoop  ; Branch to LoadBackgroundPaletteLoop if compare was Not Equal to zero
  
  LDX #$00      
        
LoadSpritePaletteLoop:
  LDA sprite_palette, x     ;load palette byte
  STA $2007					;write to PPU
  INX                   	;set index to next byte
  CPX #$10            
  BNE LoadSpritePaletteLoop  ;if x = $10, all done

  LDX #$00              ; start at 0
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down 
  
  LDA #%10000000   ; enable NMI, sprites from Pattern Table 0
  STA $2000
  
  LDA #%00010000   ; enable sprites
  STA $2001
  
  LDA $0203
  STA player_x

Foreverloop:
  JMP Foreverloop     ;jump back to Forever, infinite loop

NMI: 
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer
  
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  INX
  STX player_x
  
  RTI

;;;;;;;;;;;;;;  

  .bank 1
  .org $E000
background_palette:
  .db $22,$29,$1A,$0F	;background palette 1
  .db $22,$36,$17,$0F	;background palette 2
  .db $22,$30,$21,$0F	;background palette 3
  .db $22,$27,$17,$0F	;background palette 4
  
sprite_palette:
  .db $22,$16,$27,$18	;sprite palette 1
  .db $22,$1A,$30,$27	;sprite palette 2
  .db $22,$16,$30,$27	;sprite palette 3
  .db $22,$0F,$36,$17	;sprite palette 4
  
sprites:
     ;vert tile attr horiz
  .db $08, $3A, %00000000, $08   ;sprite 0
  .db $08, $37, %00000000, $10   ;sprite 1
  .db $10, $4f, %00000000, $08   ;sprite 2
  .db $10, $4f, %01000000, $10   ;sprite 3


;;;;;;;;;;;;;;  

  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
  
;;;;;;;;;;;;;;  

  .bank 2
  .org $0000
  .incbin "mario.chr"   ;includes 8KB graphics file from SMB1
```

Once again, compile the code with compile.bat, and run it into your favorite emulator debugger. SUCCESS!!! Mario now moves right over and over. Congratulations! With the next tutorial, we will add Controller commands so you don't need to watch it move on its own. Enjoy the code and have a wonderful day!  :big yellow:

----------

