NES Programming Tutorial : Multiple Sprites

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 : Multiple Sprites

Post by FARID »

Code: Select all

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

spt1_Y         = $0200
spt1_tile      = $0201
spt1_att       = $0202
spt1_X         = $0203

spt2_Y         = $0204
spt2_tile      = $0205
spt2_att       = $0206
spt2_X         = $0207

spt3_Y         = $0208
spt3_tile      = $0209
spt3_att       = $020A
spt3_X         = $020B

spt4_Y         = $020C
spt4_tile      = $020D
spt4_att       = $020E
spt4_X         = $020F

spt5_Y         = $0210
spt5_tile      = $0211
spt5_att       = $0212
spt5_X         = $0213

spt6_Y         = $0214
spt6_tile      = $0215
spt6_att       = $0216
spt6_X         = $0217

spt7_Y         = $0218
spt7_tile      = $0219
spt7_att       = $021A
spt7_X         = $021B

spt8_Y         = $021C
spt8_tile      = $021D
spt8_att       = $021E
spt8_X         = $021F

spt9_Y         = $0220
spt9_tile      = $0221
spt9_att       = $0222
spt9_X         = $0223

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;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 #$00
	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 sprites
   INC spt6_Y
   INC spt7_Y
   INC spt8_Y
   INC spt9_Y
   
;Sprites data to OAM
   JSR vblank_wait
   LDA #$00
   STA $2003
   LDA #$02
   STA $4014

   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:
  .incbin "mario_spt.oam"
;---------------------------;  
  .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 :

* Transferring 4-byte info of one sprite with $2003 and $2004 is ok, but it is slow for multiple sprites

* There is a faster way to transfer multiple sprites data to OAM : Using $2003 and $4014

* The data of sprites are stored in the RAM from $0200 to $02FF (256 Bytes)

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

* Attach it to the source code

Code: Select all

sprites:
  .incbin "mario_spt.oam"
* We load the data of sprites into $0200 to $02FF

Code: Select all

;Sprites data to ram
LoadSprites:
	LDX #$00
LoadSpritesLoop:
	LDA sprites, X
	STA $0200, X
	INX
	CPX #$00
	BNE LoadSpritesLoop
* We set OAM memory address to $00 with $2003

Code: Select all

	LDA #$00
	STA $2003
* We write $02 to $2014

Code: Select all

	LDA #$02
	STA $4014
* We only write the High byte of the RAM address to $2014, the Low byte of the RAM is automatically adjusted to $00 and there is no need to declare it.

* With this method a total of 256 bytes (info of 64 sprites) are transferred from RAM ($0200 ~ $02FF) to OAM memory

* This method is called DMA. Need more info about it? Then read this : PPU OAM

* Inside the game engine loop we can change the info of sprites which are saved on the ram

Code: Select all

;Give effect to sprites
   INC spt6_Y
   INC spt7_Y
   INC spt8_Y
   INC spt9_Y
* In this code we increase the Y coordinate of mario sprite, so it seems mario is going down constantly

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

Exercise :

Open mario_spt.oam with HxD and edit mario's data to become upside down.

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

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_spt.oam
mario_bg.chr
mario_spt.chr

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

Former Level : NES Programming Tutorial : Sprite
Next Level : NES Programming Tutorial : Using Joypad
Post Reply