NES Programming Tutorial : Sprite

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

NES Programming Tutorial : Sprite

Post by FARID »

Code: Select all

;NES Programming Tutorial
;Level 7 : Sprite
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Variables
L_byte         = $0000
H_byte         = $0001
bg_X_pos       = $0002
bg_Y_pos       = $0003
NMI_index      = $0004

sprite_Y       = $0200
sprite_tile    = $0201
sprite_att     = $0202
sprite_X       = $0203

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;iNES header data (16bytes)
;32KB PRG + 8KB CHR + NROM-256 + Vertical Mirroring
  .db $4E,$45,$53,$1A,$02,$01,$01,$00
  .db $00,$00,$00,$00,$00,$00,$00,$00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;PRG codes $8000 ~ $FFFF (32KB)
  .base $8000

RESET:
   SEI
   CLD

;Turn off NMI and rendering
   LDA #%00000000
   STA $2000
   LDA #%00000000
   STA $2001

;PPU warm up
   LDA $2002
vBlank_wait1:
   BIT $2002
   BPL vBlank_wait1
vBlank_wait2:
   BIT $2002
   BPL vBlank_wait2

;Clear RAM
   LDA #$00
   LDX #$00
clear_loop:
   STA $0000, X
   STA $0100, X
   STA $0200, X
   STA $0300, X
   STA $0400, X
   STA $0500, X
   STA $0600, X
   STA $0700, X
   INX
   CPX #$00
   BNE clear_loop

;Name table + Attribute
   LDA $2002
   LDA #$20
   STA $2006
   LDA #$00
   STA $2006
   LDA #<nam_att
   STA L_byte
   LDA #>nam_att
   STA H_byte
   LDX #$00
   LDY #$00
nam_loop:
   LDA ($00), Y
   STA $2007
   INY
   CPY #$00
   BNE nam_loop
   INC H_byte
   INX
   CPX #$04
   BNE nam_loop

;Name table + Attribute 2
   LDA $2002
   LDA #$24
   STA $2006
   LDA #$00
   STA $2006
   LDA #<nam_att_2
   STA L_byte
   LDA #>nam_att_2
   STA H_byte
   LDX #$00
   LDY #$00
nam_loop_2:
   LDA ($00), Y
   STA $2007
   INY
   CPY #$00
   BNE nam_loop_2
   INC H_byte
   INX
   CPX #$04
   BNE nam_loop_2

;Background color setup
   LDA $2002
   LDA #$3F
   STA $2006
   LDA #$00
   STA $2006
   LDX #$00
bg_pal_loop:
   LDA bg_pal, X
   STA $2007
   INX
   CPX #$10
   BNE bg_pal_loop

;Sprites color setup
   LDA $2002
   LDA #$3F
   STA $2006
   LDA #$10
   STA $2006
   LDX #$00
spt_pal_loop:
   LDA spt_pal, X
   STA $2007
   INX
   CPX #$10
   BNE spt_pal_loop
  
;Sprites data to ram
LoadSprites:
	LDX #$00
LoadSpritesLoop:
	LDA sprites, X
	STA $0200, X
	INX
	CPX #$04
	BNE LoadSpritesLoop
  
;Reset Scroll
   LDA #$00
   STA $2005
   LDA #$00
   STA $2005
   
;Turn on NMI and rendering
   LDA #%10001000
   STA $2000
   LDA #%00011010
   STA $2001

;Infinite loop
Forever:

;Move background
   JSR vblank_wait
   INC bg_X_pos
   LDA bg_X_pos
   STA $2005
   LDA #$00
   STA $2005

;Give effect to sprite
   INC sprite_Y
   
;Sprites data to OAM
   JSR vblank_wait
   LDA #$00
   STA $2003
   LDA sprite_Y
   STA $2004
   LDA sprite_tile
   STA $2004
   LDA sprite_att
   STA $2004
   LDA sprite_X
   STA $2004

   JMP Forever
;---------------------------;
vblank_wait:
	LDA NMI_index
not_yet:
	CMP NMI_index
	BEQ not_yet
	RTS   
;---------------------------;
NMI:
   INC NMI_index
   RTI
;---------------------------; 
IRQ:
   RTI
;---------------------------;
nam_att:
  .incbin "mario_bg.nam"

nam_att_2:
  .incbin "mario_bg_2.nam"

bg_pal:
  .incbin "mario_bg.pal"
 
spt_pal:
  .incbin "mario_spt.pal"

sprites:
  .db $80,$65,%00000000,$80
;---------------------------;  
  .pad $FFFA,$FF  
;Vectors
  .org $FFFA
  .dw NMI
  .dw RESET
  .dw IRQ
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHR data $0000 ~ $1FFF (8KB)
  .base $0000
  .incbin "mario_bg.chr"
  .incbin "mario_spt.chr"
  .pad $2000,$FF
Output :

Image


Explanation :

* Enable NMI, use left pattern table for background, use right pattern table for sprites

Code: Select all

   LDA #%10001000
   STA $2000
* Show background, show sprites

Code: Select all

   LDA #%00011010
   STA $2001
* The data of sprites tiles is stored in the PPU memory from $0000 to $0FFF (4KB)

* The data of sprites color is stored in the PPU memory from $3F10 to $3F1F (16Bytes)

* Extract those data from "Super Mario Bros. (W) [!].nes" and save them as : mario_spt.chr, mario_spt.pal

* Attach them to the source code

Code: Select all

spt_pal:
  .incbin "mario_spt.pal"

Code: Select all

  .incbin "mario_spt.chr"
* The codes of ;Sprites color setup actually transfers a total of 16 bytes (= 10 bytes in hex) data of sprites color to PPU memory ($3F10 ~ $3F1F)

* Each tile of sprite need 4 byte-info to be able to appear on the screen

* Y coordinate of the sprite on the screen

* One byte for tile number from sprites pattern table

* One byte for the attribute of the sprite, this byte is bit wise

* X coordinate of the sprite on the screen

Code: Select all

sprites:
  .db $80,$65,%00000000,$80
* With this code we take those 4 bytes and save them into ram

Code: Select all

;Sprites data to ram
LoadSprites:
   LDX #$00
LoadSpritesLoop:
   LDA sprites, X
   STA $0200, X
   INX
   CPX #$04
   BNE LoadSpritesLoop
* OAM is a special memory for holding sprites info, it has its own memory space starting from $00 to $FF (256bytes)

* To show a sprite on the screen you have to write its 4byte-info to OAM memory

* Every sprite needs 4 bytes of info, right? So OAM can hold up to 64 sprites at the same time

* We can't write directly to OAM memory, we have to use ports : $2003 and $2004

* With $2003 we declare what address of OAM want to write, then we use $2004 to write the desired value to that address

* Each time we write a value to $2004, the OAM address is automatically adjusted to the next address, so we don't need to declare the OAM address again

Code: Select all

;Give effect to sprite
   INC sprite_Y
   
;Sprites data to OAM
   JSR vblank_wait
   LDA #$00
   STA $2003
   LDA sprite_Y
   STA $2004
   LDA sprite_tile
   STA $2004
   LDA sprite_att
   STA $2004
   LDA sprite_X
   STA $2004
* In the game engine we increase the Y coordinate of the sprite and it seems that sprite is falling

* Need more info about sprites and OAM memory? then read this : PPU OAM

/////////////////////////////////////////////////////////////////////////////////////////////////

Exercise :

Make another sprite on the screen.

/////////////////////////////////////////////////////////////////////////////////////////////////

Files :
asm6.exe
Assembler.bat
Game.asm
name.exe
Bg_Editor.bat
alleg42.dll
mario_bg.nam
mario_bg_2.nam
mario_bg.pal
mario_spt.pal
mario_bg.chr
mario_spt.chr

/////////////////////////////////////////////////////////////////////////////////////////////////

Former Level : NES Programming Tutorial : Move Background
Next Level : NES Programming Tutorial : Multiple Sprites
Post Reply