NES Programming Tutorial : Move Background

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 : Move Background

Post by FARID »

Code: Select all

;NES Programming Tutorial
;Level 6 : Move Background
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Variables
L_byte         = $0000
H_byte         = $0001
bg_X_pos       = $0002
bg_Y_pos       = $0003
NMI_index      = $0004
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;iNES header data
;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
  .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 #<bg_nam
   STA L_byte
   LDA #>bg_nam
   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 #<bg_nam_2
   STA L_byte
   LDA #>bg_nam_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

;Reset Scroll
   LDA #$00
   STA $2005
   LDA #$00
   STA $2005
   
;Turn on NMI and rendering
   LDA #%10000000
   STA $2000
   LDA #%00001010
   STA $2001

;Infinite loop
Forever:

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

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

bg_nam_2:
  .incbin "mario_bg_2.nam"

bg_pal:
  .incbin "mario_bg.pal"
;---------------------------;  
  .pad $FFFA,$FF   
;Vectors
  .org $FFFA
  .dw NMI
  .dw RESET
  .dw IRQ
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHR data $0000 ~ $1FFF
  .base $0000
  .incbin "mario_bg.chr"
  .pad $2000,$FF
Explanation :

* We enable NMI by setting the 7th bit of $2000

Code: Select all

   LDA #%10000000
   STA $2000
* In this level we are going to use another background

* The data of second background (name table) is stored in the PPU memory from $2400 to $2800 (1KB)

* Extract its data from "Super Mario Bros. (W) [!].nes" and save it as mario_bg_2.nam

* Attach its data to the source code

Code: Select all

bg_nam_2:
  .incbin "mario_bg_2.nam"
* With ;Name table + Attribute 2 codes we transfer the second background data to PPU memory (from $2400 to $2800)

* At first this background is outside of screen and is not visible

* We have to scroll the screen to show the second background

* By scrolling the background actually we are updating the graphic on screen, right? So we have to do it in vBlank period

* So we have to detect when vblank happens

Code: Select all

NMI:
   INC NMI_index
   RTI
* We use a variable, each time vblank happens this variable increase

Code: Select all

vblank_wait:
   LDA NMI_index
not_yet:
   CMP NMI_index
   BEQ not_yet
   RTS  
* With this code we check the variable, we keep looping until it changes which shows a vblank period just has happened

* Need more info about this method? then read this : NMI

* By using JSR ... RTS we make a subroutine. JSR jumps to a label, runs a block of code until it finds RTS then it goes back to its original code

* This loops is infinite and we call it game engine. Here it is very simple.

Code: Select all

;Infinite loop
Forever:

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

   JMP Forever
* Each time it waits for a new vblank period to start.

* Then X coordinate increase by one, so first background moves one pixel to left and the second background appears from right side of screen

Image

* With Vertical Mirroring we can scroll the background horizontally

* With Horizontal Mirroring we can scroll the background vertically

* Need more info? then read this : PPU scrolling

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

Exercise :

Scroll the screen backward or from up to 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_bg.chr

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

Former Level : NES Programming Tutorial : Background
Next Level : NES Programming Tutorial : Sprite
Post Reply