It is currently Mon Oct 23, 2017 6:45 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 2 posts ] 
Author Message
PostPosted: Sat Mar 11, 2017 11:23 am 
Offline
User avatar

Joined: Wed Apr 07, 2010 1:14 am
Posts: 484
Location: Iran
Code:
;NES Programming Tutorial
;Level 9 : Using Joypad
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;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:

;Prepare controllers to read
   LDA #$01
   STA $4016
   LDA #$00
   STA $4016

;Check A
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE A_not_pressed

A_not_pressed:

;Check B
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE B_not_pressed

B_not_pressed:

;Check Select
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Select_not_pressed

Select_not_pressed:

;Check Start
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Start_not_pressed

Start_not_pressed:

;Check Up
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Up_not_pressed
    DEC spt6_Y
    DEC spt7_Y
    DEC spt8_Y
    DEC spt9_Y
Up_not_pressed:

;Check Down
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Down_not_pressed
    INC spt6_Y
    INC spt7_Y
    INC spt8_Y
    INC spt9_Y
Down_not_pressed:

;Check Left
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Left_not_pressed
    DEC spt6_X
    DEC spt7_X
    DEC spt8_X
    DEC spt9_X
Left_not_pressed:

;Check Right
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Right_not_pressed
    INC spt6_X
    INC spt7_X
    INC spt8_X
    INC spt9_X
Right_not_pressed:
   
;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


Explanation :

* In this level we are going to use joypad to move mario around the screen

* I removed the background scrolling code from the game engine

* To use joypad we have to use this code to announce the hardware to become ready

Code:
;Prepare controllers to read
   LDA #$01
   STA $4016
   LDA #$00
   STA $4016


* $4016 is Joypad 1 port, we have to read this port to find out if a button is pressed or not

* We have to read $4016 eight times in sequence, with each read the status of only one button is given

* The sequence is like this : A B Select Start UP Down Left Right

* $4016 is bit wise, and the only bit that we need is bit0

* If bit0 is 1 then the button was pressed, if it is 0 then the button was not pressed

* bit1 ~ bit7 of $4016 can be any random data, so we have get rid of them

* We use AND opcode to clear those unwanted bits

* AND is a logical operation, here is it's logic :

Image

* ORA and XOR are also another useful opcodes

* After clearing other unwanted bits we can do a compare operation to find out if the button was pressed or not :

Code:
;Check Up
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BNE Up_not_pressed
    DEC spt6_Y
    DEC spt7_Y
    DEC spt8_Y
    DEC spt9_Y
Up_not_pressed:


* For example if up button was pressed then we have to alter the Mario's sprite data on ram

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

Exercise :

Use Joypad to scroll the background.

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

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 : Multiple Sprites
Next Level : Pong


Last edited by FARID on Sat Mar 18, 2017 3:15 am, edited 11 times in total.

Top
 Profile  
 
PostPosted: Sat Mar 11, 2017 12:48 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
You're doing something *really bad* here, which is running the game logic in the NMI before the graphical updates.

You see, each frame on the NES has 262 scanlines, out of which only 20 coincide with vblank. You can only update sprites, backgrounds palettes and such during vblank, so you shouldn't waste vblank time doing tasks that could be done some other time, such as reading the controllers and moving objects.

Your program works so far because you have little logic and few graphical updates, but once you scale this to a full game, there's no way you can fit logic and video updates in just 20 scanlines (about 2273 CPU cycles), unless it's Pong...

So if you want my sincere opinion, this is not a good structure to present to newbies, because it scales very poorly and results in visual glitches as soon as programs become more complex than a few sprites moving around. That's confusing for newbies because they'll think there's something wrong with the code they wrote before breaking things, but the problem may very well not be with the code itself, but with the fact that there's more code than can fit in vblank.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group