It is currently Thu Nov 23, 2017 1:25 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 80 posts ]  Go to page 1, 2, 3, 4, 5, 6  Next
Author Message
PostPosted: Mon Jul 17, 2017 4:42 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Hello, I have a question about the pallet and the screen. Every 6 frames I update the pallete, the scroll value gets affected temporally. How can you fix this?

HERE'S THE CODE:
Code:
NMI:

  INC scroll
   ; add one to our scroll variable each frame


NTSwapCheck:
  LDA scroll ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckP2 
NTSwap:
  LDA nametable         ; load current nametable number (0 or 1)
  EOR #$01              ; exclusive OR of bit 0 will flip that bit
  STA nametable         ; so if nametable was 0, now 1
                        ;    if nametable was 1, now 0
NTSwapCheckP2:


NTSwapCheckP2:
  LDA scrolly            ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckP3

NTSwap2:
  LDA nametabley         ; load current nametable number (0 or 1)
  EOR #$01              ; exclusive OR of bit 0 will flip that bit
  STA nametabley         ; so if nametable was 0, now 1 

NTSwapCheckP3:
 
 
 
NewAttribCheck:
  LDA scroll
  AND #%00011111            ; check for multiple of 32
  BNE NewAttribCheckDone    ; if low 5 bits = 0, time to write new attribute bytes
  jsr DrawNewAttributes
NewAttribCheckDone:

   
   
NewColumnCheck:
  LDA scroll
  AND #%00000111            ; throw away higher bits to check for multiple of 8
  BNE NewColumnCheckDone    ; done if lower bits != 0
  JSR DrawNewColumn         ; if lower bits = 0, time for new column
 
  lda columnNumber
  CMP #$FE
  BCC DT9
 
  LDA #$00
  STA scroll+2
 
 
DT9:
 
  lda columnNumber
  clc
  adc #$01             ; go to next column
  and #%11111111       ; only 256 columns of data, throw away top bit to wrap
  sta columnNumber
 
  lda scroll+2
  clc
  adc #$01
  STA scroll+2
 
 
  JSR Scrollcheck
   
 
NewColumnCheckDone:

 
 
 
  LDA #$00
  STA $2003       
  LDA #$02
  STA $4014       ; sprite DMA from $0200
 
 
  JSR LoadPalettes2

 
 
  LDA #$00
  STA $2006        ; clean up PPU address registers
  STA $2006
 
 
 
  LDA scroll
  STA $2005        ; write the horizontal scroll count register

  LDA scrolly         ; no vertical scrolling
  STA $2005
 
 
   
 
 
 
  ;;This is the PPU clean up section, so rendering the next frame starts properly.
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  ORA nametable    ; select correct nametable for bit 0
  STA $2000
 
  LDA #%00011110   ; enable sprites, enable background, no clipping on left side
  STA $2001
 
 

 
  JSR Updating
  JSR Gravity
  JSR ReadController1
 
 
 
 
  LDA #$00
  STA T
 
 
 
  LDA #$00
  STA D
 
  LDA #$00
  STA D+1
 

 LDA buttons
  AND #%10000000 ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                 
 
 
  LDA JumpState
  CMP #$01
  BCS ReadADone
 
  LDA #$01
  STA JumpState
 
 
 
 
 

  ; save sprite X position
ReadADone: 
 
 LDA buttons
 AND #%00000001 ; only look at bit 0
  BEQ ReadRightDone   ; branch to ReadADone if button is NOT pressed (0)
                     
 
  LDA #$01
  STA D
 
  LDA player       
  CLC             
  ADC #$01       
  STA player
 
  LDA #$00
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadRightDone:

 LDA buttons
 AND #%00000010 ; only look at bit 0
  BEQ ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)
                 
  LDA player       
  SEC             
  SBC #$01       
  STA player
 
  LDA #$01
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadLeftDone:

 
 LDA buttons
 AND #%00100000 ; only look at bit 0
  BEQ ReadUpDone
 
 
 
 
  LDA buttons
  AND #%00010000
 
   
 
  LDA gamestate
  CLC
  ADC #$01
  STA gamestate
 
ReadUpDone:
; run normal game engine code here
 ; reading from controllers, etc
 
 
 
  RTI              ; return from interrupt
 
 
 
 

DrawNewColumn:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$20          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  JSR levelselect
 

DrawColumn:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E         ; copy 30 bytes
  LDY #$1E
DrawColumnLoop:
  LDA [sourceLow], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop

 


 
DrawNewColumn2:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow2    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$28          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28 changes what loads the name table in the bottem name table in
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber2  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow2
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh2
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

DrawColumn2:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E              ; copy 30 bytes
  LDY #$1E
DrawColumnLoop2:
  LDA [sourceLow2], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop2

 

 
  RTS
 
 

 
 
DrawNewAttributes:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(attribData)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(attribData)
  STA sourceHigh

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone
 
  LDA columnLow         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow
  JMP DrawNewAttributesLoop
DrawNewAttributesLoopDone:

  RTS

DrawNewAttributes2:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop2
  LDA columnHigh2
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow2], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone2
 
  LDA columnLow2         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow2
  JMP DrawNewAttributesLoop2
DrawNewAttributesLoopDone2:


 


  rts

; skip the update function
LoadPalettes2:


 
 
  LDA #$00
  STA Timer1+5
 
  LDA #$00
  STA Timer1+6
 
  LDX #$00
 
LP2:
 
  LDA #$3F
  STA $2006
  LDA Timer1+6
  STA $2006
 
  LDA paletteswap , x
  STA $2007
   
 
 
 
  INX
 
  INC Timer1+5
 
  INC Timer1+6
 
  LDA Timer1+5
  CMP #$20
  BEQ Fin
 
 
  JMP LP2
 
Fin:


 
 
  RTS
 
 

I have also read this:
https://wiki.nesdev.com/w/index.php/The_frame_and_NMIs
And I don't Understand what he mean to do for lda needppureg
Please first explain what the problem is before showing the code.
Thanks.


Top
 Profile  
 
PostPosted: Mon Jul 17, 2017 5:29 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1832
Location: DIGDUG
The PPU is weird. The PPU Address ($2006) shares bits with the scroll ($2005). Writing to one affects the other.

After writing to the PPU, you must set a nametable(write to $2000), and set a scroll position (2 writes to $2005)


Edit. I think you are doing what i said.

Probably a timing issue. Writing outside V-blank.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Mon Jul 17, 2017 5:42 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
Not sure if it's the culprit, but I see that you have "PPU cleanup" twice and one of them comes after your scroll updates.

I see some other bad things as well. You have logic at the beginning of your NMI handler, logic is better to have in the main loop, or after all graphic updates (OAM, VRAM and certain register updates) in the NMI, else it will steal vblank time. The NMI handler first needs to backup registers A, X and Y to stack (unless you are doing the all-in-NMI approach) then immediately do graphic updates. The order of the graphic updates is ideally something like this:
1) Check your render flag and skip all graphic updates if clear (read bellow)
2) Read $2002 to reset high/low latch
3) Sprite updates (OAM DMA)
4) Background updates
5) Palette updates
6) $2000 and $2001 updates
7) Scroll updates ($2005)
4, 5 and 6 can probably come in any order, but OAM DMA should be done early for PAL compatibility and Scroll should be updated last because PPU register writes affects the scroll register.

After all the graphic updates, you can have things that don't have to be in vblank, like sound updates or controller updates, though I heard controller updates are better to have in your main loop to avoid possible inconsistencies. Sound is best to be in NMI though since it ensures mostly constant tempo timing.

About the needppureg flag, he uses it whenever he has made changes to $2000 or $2001 in their buffers so that the NMI only updates them when the flag is set. I don't think it's really necessary to make them conditional separately. You should make the whole graphic update block conditional though. Have a render flag that is set at the end of each main loop and cleared at the end of each NMI. If the flag is not set, jump past all the graphic updates (but not sound and everything after that). That way there is no risk for drawing partly updated frames when the game lags.


Top
 Profile  
 
PostPosted: Tue Jul 18, 2017 7:53 am 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
What logic is at the main loop?


Top
 Profile  
 
PostPosted: Tue Jul 18, 2017 10:56 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
Everything in your NMI before the sprite DMA looks like logic to me (it does not write to VRAM, OAM or PPU registers, so it's not graphic updates). It should be in your main loop.

Is the main loop in your NMI? In that case it should come after the graphic updates, because the first part of the NMI always happens during the vblank interval, which is limited. The article you linked to explains this too.


Top
 Profile  
 
PostPosted: Tue Jul 18, 2017 8:59 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1832
Location: DIGDUG
Definitely writing to PPU outside V-blank. I dropped your code into a blank template, and put some breakpoints on when the final scroll setting is done. About every 8 frames, you are clear down to scanline 7, occasionally more, by the time you set the scroll for the screen. [I had to make some assumptions, since you didn't provide the entire source code, I might be off by a few lines]

Eliminating the line...
jsr LoadPalettes2 (you are updating the entire palette, every frame)
-I don't know why you said "Every 6 frames". It happens every frame.

...improves this quite a bit, but still hitting scanline 1 occasionally, which would shift the entire screen by 1 pixel. Jittery. If you tightened your code a bit (made loops slightly more efficient). You could probably avoid the scroll shift entirely.

A more ideal solution, would be to do most of the calculations before hand (outside of NMI). Load all updates into a buffer (also outside of NMI), and make a much more efficient system of writing to the PPU. Then you could put the palette updates back in.




EDIT: also...

[deleted some code advice, I didn't like my wording]

You need to be careful about which direction PPU writes are going. You specifically set it to +32 in the DrawColumn / DrawColumn2 subroutines, but that comes after the attribute table subroutine, and it's still set to +1 mode from the end of the NMI write to $2000 [I guess that won't cause a problem, now that I look at it]. Further, it is still in +32 mode (sometimes) when it gets to LoadPalettes2, which needs it to be in +1 mode.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Thu Jul 20, 2017 6:27 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Cool. :mrgreen:
1. Is updating the palette EVERY FRAME a bad thing and can it be done with buffering?
2 whuts buffering?
3 pla does What?
Also Would It help to give you the .nes file for reference?
Heres the new CODE:

Code:
LoadPalettes2:


  LDA #%00000000        ; set to increment +32 mode
  STA $2000
 
 
  LDA $2002             ; read PPU status to reset the high/low latch
 
 
  LDA #$00
  STA Timer1+5
  STA Timer1+6
 
  LDX #$00
 
LP2:
 
   
 
  LDA #$3F
  STA $2006
  LDA Timer1+6
  STA $2006
 
  LDA paletteswap , x
  STA $2007
   
 
 
 
  INX
 
  INC Timer1+5
 
  INC Timer1+6
 
  LDA Timer1+5
  CMP #$20
  BEQ Fin
 
 
  JMP LP2
 
Fin:


  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  RTS
 

NOW, to learn buffering.


Top
 Profile  
 
PostPosted: Fri Jul 21, 2017 2:47 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
1. Not a bad thing as long as it is updated in vblank, and yes buffering is the preferable way to do it. The palette isn't that big but if you are short on vblank time you could make a buffer system that only updates parts of the palette instead of the whole palette every time. You could also make a buffer system that updates nametable and palette together so that changing BG characters also changes their colours at the same time.

2. Buffering is keeping a copy of whatever you buffer (usually graphic updates) in a RAM area. You update this buffer in your game logic (main loop) and in the beginning of NMI (vblank) you just copy the contents of this buffer to VRAM/OAM etc. This way you can keep game logic and graphic updates separate. You are already buffering the OAM by using the RAM area $0200 to $02FF as an OAM buffer (or shadow OAM as they also call it). But DMA can only be used for OAM (sprite attributes), not for VRAM (nametable and palette), so you have to code a different buffer system for those. Updates to $2000 and $2001 should also be buffered in their own RAM registers so that they are also only changed in vblank.

3. PLA pulls the topmost value from the stack and puts it in the accumulator. If you have your main loop outside of NMI handler (in your RESET handler), you need to backup both the accumulator and the index registers X and Y on the stack at the start of your NMI handler and pull them out again in reverse order. PHA pushes the accumulator on to the stack but there are no instructions for pushing or pulling X or Y to or from stack, so you have to transfer X and Y into A first (using TXA/TYA when pushing and TAX/TAY after pulling):
Code:
NMI:
  pha
  txa
  pha
  tya
  pha                ;save A, X and Y to the stack

;(NMI code here)

  pla
  tay
  pla
  tax
  pla                ;restore A, X and Y from the stack
  rti

This is needed because the NMI is an interrupt that could happen at any time in your main loop, and since both main and NMI uses the registers it could mess up your code. You don't need to backup the status flags however, because they are backed up automatically whenever an interrupt occurs.

The NES file would help, but the whole source code would help more.


Top
 Profile  
 
PostPosted: Fri Jul 21, 2017 1:01 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Code:
  .inesprg 1  ; 1x 16KB PRG code
  .ineschr 4   ; 1x  8KB CHR data
  .inesmap 4   ; mapper 0 = NROM, no bank swapping
  .inesmir 2   ; background mirroring
 

;;;;;;;;;;;;;;;
    .rsset $0000  ;;start variables at ram location 0
 

paletteswap     .rs 32
scroll     .rs 3
D     .rs 2
scrolly     .rs 1
gravity    .rs 1
buttons    .rs 1
gamestate  .rs 4
progress   .rs 1
buttonslay .rs 1
player     .rs 2
feet       .rs 1
jheight    .rs 1
pdirection .rs 5
grounded .rs 1
Frame .rs 1
Fr .rs 1
Timer1 .rs 12
ANT .rs 4
T .rs 1
Srt .rs 6

Ant .rs 1
L .rs 1
BCount .rs 16
JumpState .rs 3
nametable  .rs 1
nametabley  .rs 1  ;  ; which nametable to use, 0 or 1
columnLow  .rs 1  ; low byte of new column address
columnHigh .rs 1  ; high byte of new column address
sourceLow  .rs 1  ; source for column data
sourceHigh .rs 1
columnNumber .rs 1
columnNumber2 .rs 1
sourceLow2  .rs 1  ; source for column data
sourceHigh2 .rs 1
columnLow2  .rs 1  ; low byte of new column address
columnHigh2 .rs 1  ; hi


  ; which column of level data to



GROUND     = $B1  ;



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


  .bank 0
  .org $C000
 
  vblankwait:
  BIT $2002
  BPL vblankwait
  RTS
 
 
  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
  lda #%00000001
  sta $4017 ;enable Square 1
 
    ;square 1
  lda #%00000000 ;Duty 10, Length Counter Disabled, Saw Envelopes disabled, Volume F
  sta $4000
   
  lda #$C9    ;0C9 is a C# in NTSC mode
  sta $4002   ;low 8 bits of period
  lda #$00
  sta $4003
 
   
  JSR vblankwait     

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
   JSR vblankwait   

 
LoadPalettes:
  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
LoadPalettesLoop:
  LDA palette, x        ;load palette byte
 
 
 
  STA $2007             ;write to PPU
  INX                   ;set index to next byte
  CPX #$20           
  BNE LoadPalettesLoop

  LoadPalettesLoop1:
  LDA palette, x        ;load palette byte
 
 
 
  STA paletteswap, x             ;write to PPU
  INX                   ;set index to next byte
  CPX #$20           
  BNE LoadPalettesLoop1   ;if x = $20, 32 bytes copied, all done
 
 
 
LoadPSprites:
 
 
  LDX #$00              ; start at 0
LoadSpritesLoopP:
  LDA Playersprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$08             ; Compare X to hex $20, decimal 32
  BNE LoadSpritesLoopP   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
 
LoadESprites:
 
 
  LDX #$00              ; start at 0
LoadSpritesLoopE:
  LDA Esprites, x        ; load data from address (sprites +  x)
  STA $0218, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX $FF            ; Compare X to hex $20, decimal 32
  BNE LoadSpritesLoopE   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
     
             
             

   
 
InitializeNametables:
  LDA #$01
  STA nametable
  LDA #$00
  STA scroll
  STA columnNumber
InitializeNametablesLoop:
  JSR DrawNewColumn
  ; draw bg column
  LDA scroll            ; go to next column
  CLC
  ADC #$08
  STA scroll
  INC columnNumber
  LDA columnNumber      ; repeat for first nametable
  CMP #$20
  BNE InitializeNametablesLoop
 
  LDA #$00
  STA nametable
  LDA #$00
  STA scroll
  JSR DrawNewColumn     ; draw first column of second nametable
  INC columnNumber
 
  LDA #$00              ; set back to increment +1 mode
  STA $2000
InitializeNametablesDone:


InitializeAttributes:
  LDA #$01
  STA nametable
  LDA #$00
  STA scroll
  STA columnNumber
InitializeAttributesLoop:
  JSR DrawNewAttributes     ; draw attribs
  LDA scroll                ; go to next column
  CLC
  ADC #$20
  STA scroll

  LDA columnNumber      ; repeat for first nametable
  CLC
  ADC #$04
  STA columnNumber
  CMP #$20
  BNE InitializeAttributesLoop
 
  LDA #$00
  STA nametable
  LDA #$00
  STA scroll
  JSR DrawNewAttributes     ; draw first column of second nametable
InitializeAttributesDone:

  LDA #$21
  STA columnNumber


 
 
  LDA #$10
  STA paletteswap
 
  LDA #$00
  STA JumpState
 
  LDA #$80
  STA player
 
  LDA #$FE
  STA scrolly
 
  LDA #$80
  STA player+1
 
  LDA #$08
  STA pdirection+1
 
  LDA #$06
  STA ANT
 
  LDA #$08
  STA ANT+1
 
  LDA #$0A
  STA ANT+2
 
  LDA #$06
  STA ANT+3
 
  LDA #$06
  STA Srt
 
  LDA #$01
  STA gamestate+1
 
 


 
 
 
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  STA $2000

  LDA #%00011000   ; enable sprites, enable background, no clipping on left side
  STA $2001

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


NMI:



 

  INC scroll
   ; add one to our scroll variable each frame


NTSwapCheck:
  LDA scroll ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckP2 
NTSwap:
  LDA nametable         ; load current nametable number (0 or 1)
  EOR #$01              ; exclusive OR of bit 0 will flip that bit
  STA nametable         ; so if nametable was 0, now 1
                        ;    if nametable was 1, now 0



        ; so if nametable was 0, now 1 

NTSwapCheckP2:
 
  LDA #$00
  STA $2003       
  LDA #$02
  STA $4014       ; sprite DMA from $0200
 
NewAttribCheck:
  LDA scroll
  AND #%00011111            ; check for multiple of 32
  BNE NewAttribCheckDone    ; if low 5 bits = 0, time to write new attribute bytes
  jsr DrawNewAttributes
 
NewAttribCheckDone:

   
   
NewColumnCheck:
  LDA scroll
  AND #%00000111            ; throw away higher bits to check for multiple of 8
  BNE NewColumnCheckDone    ; done if lower bits != 0
  JSR DrawNewColumn         ; if lower bits = 0, time for new column
 
  lda columnNumber
  CMP #$FE
  BCC DT9
 
  LDA #$00
  STA scroll+2
 
 
DT9:
 
 
  lda columnNumber
  clc
  adc #$01             ; go to next column
  and #%11111111       ; only 256 columns of data, throw away top bit to wrap
  sta columnNumber
 
  lda scroll+2
  clc
  adc #$01
  STA scroll+2
 
 
  JSR Scrollcheck
   
 
NewColumnCheckDone:

 

  JSR LoadPalettes2
 
 
  LDA #$00
  STA $2006       
  STA $2006
 
   ;;This is the PPU clean up section, so rendering the next frame starts properly.
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  ORA nametable    ; select correct nametable for bit 0
  STA $2000
 
  LDA #%0001100[0   ; enable sprites, enable background, no clipping on left side
  STA $2001
 
 
 
  LDA scroll
  STA $2005        ; write the horizontal scroll count register

  LDA scrolly         ; no vertical scrolling
  STA $2005
 
 
   
 
 
 
 
 
 

 
  JSR Updating
  JSR ReadController1
 
 
 
 
  LDA #$00
  STA T
 
 
 
  LDA #$00
  STA D
 
  LDA #$00
  STA D+1
 

 LDA buttons
  AND #%10000000 ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                 
 
 
  LDA JumpState
  CMP #$01
  BCS ReadADone
 
  LDA #$01
  STA JumpState
 
 
 
 
 

  ; save sprite X position
ReadADone: 
 
 LDA buttons
 AND #%00000001 ; only look at bit 0
  BEQ ReadRightDone   ; branch to ReadADone if button is NOT pressed (0)
                     
 
  LDA #$01
  STA D
 
  LDA player       
  CLC             
  ADC #$01       
  STA player
 
  LDA #$00
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadRightDone:

 LDA buttons
 AND #%00000010 ; only look at bit 0
  BEQ ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)
                 
  LDA player       
  SEC             
  SBC #$01       
  STA player
 
  LDA #$01
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadLeftDone:

 
 LDA buttons
 AND #%00100000 ; only look at bit 0
  BEQ ReadUpDone
 
 
 
 
  LDA buttons
  AND #%00010000
 
   
 
  LDA gamestate
  CLC
  ADC #$01
  STA gamestate
 
ReadUpDone:
; run normal game engine code here
 ; reading from controllers, etc
 
 
 
  RTI              ; return from interrupt
 
 
 
 

DrawNewColumn:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$20          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  JSR levelselect
 

DrawColumn:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E         ; copy 30 bytes
  LDY #$1E
DrawColumnLoop:
  LDA [sourceLow], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop

 


 
DrawNewColumn2:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow2    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$28          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28 changes what loads the name table in the bottem name table in
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber2  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow2
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh2
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

DrawColumn2:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E              ; copy 30 bytes
  LDY #$1E
DrawColumnLoop2:
  LDA [sourceLow2], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop2

 

 
  RTS
 
 

 
 
DrawNewAttributes:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(attribData)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(attribData)
  STA sourceHigh

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone
 
  LDA columnLow         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow
  JMP DrawNewAttributesLoop
DrawNewAttributesLoopDone:

  RTS

DrawNewAttributes2:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop2
  LDA columnHigh2
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow2], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone2
 
  LDA columnLow2         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow2
  JMP DrawNewAttributesLoop2
DrawNewAttributesLoopDone2:


 


  rts
 
levelselect:

  LDA gamestate+1
  CMP #$00
  BEQ l00
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(columnDatay)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(columnDatay)
  STA sourceHigh
 
  RTS
l00:

  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(columnData)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(columnData)
  STA sourceHigh
 
  RTS
 
Scrollcheck:
 
 
  LDA columnNumber
  CMP #$00
  BCC Neve
 
Sc:
 
  LDA scroll+2
  CMP #$20
  BEQ Endt
 
 
  RTS
 
Neve:

  LDA #$FF
  STA columnNumber
 
Endt:
  LDA columnNumber
  CLC
 
  ADC #$20
  STA columnNumber
 
  LDA #$00
  STA scroll+2 
 
 
  RTS
 
 
  RTS
 
;;;;;;;;;;;;;; 

  JMP BulletM




BulletM:
  CLC
  ADC #$02
  RTS

 


 
  Updating:

 
 


 
 
  LDA Frame
  CMP #$3C
  BCS AniFrame
 
  LDA #$00
  STA Frame
 
 
 
  LDA Timer1+3
  CMP #$00
  BEQ No
 
  LDA #$00
  STA Timer1+3
 
  JMP FS2
 
No:
 
  LDA #$01
  STA Timer1+3
 
FS2:

 
  LDA Timer1+11
  CMP #$03
  BEQ No2
 
  LDA #$01
  STA Timer1+10
 
  JMP FSl
 
No2:
 
  LDA #$01
  STA Timer1+3
 
 
 
  JMP FSl
 

 

 
FSl:
 
 
  LDA paletteswap+17
  CLC
  ADC #$01
  STA paletteswap+17
 
  LDA paletteswap
  CMP #$1D
  BCS Flu
 
  JMP Fly
 
 
Flu:
 
  LDA #$10
  STA paletteswap

Fly:
 

 
  LDA JumpState
  CMP #$02
  BCS AniFrame
 
AniFrame:

 
 
  LDA Srt
  STA $0211
  CLC
  ADC #$01
  STA $0215
 
  LDA Srt+1
  STA $0209
 
  LDA Srt+2
  STA $020D
 
  LDA JumpState
  STA $0219
 
  LDA JumpState+1
  STA $021B
 
  LDA Timer1+1
  STA $021A
 
 
 
Vertical:

 
 
 
  LDA player+1
  STA $0200
 
  LDA player+1
  STA $0204

  LDA player+1
  CLC
  ADC #$08  ; A = A - 1
  STA $0208

 LDA player+1
  CLC
  ADC #$08  ;     ; A = A - 1
  STA $020C

  LDA player+1
  CLC
  ADC #$0F  ; A = A - 1
  STA $0210

  LDA player+1
  CLC
  ADC #$0F  ;     ; A = A - 1
  STA $0214

Direction:
  LDA pdirection
  CMP #$01
  BCS Right
 
  LDA #$00
  STA pdirection+1
 
  LDA #$00
  STA pdirection+3
 
  LDA #$08
  STA pdirection+2
 
  BCC DDIR
 
Right:

  LDA #$08
  STA pdirection+1
 
  LDA #$40
  STA pdirection+3
 
  LDA #$00
  STA pdirection+2
 
DDIR:
 
  LDA pdirection+3
  STA $0202
  STA $0206
  STA $020A
  STA $020E
  STA $0212
  STA $0216
 
  LDA player
  CLC
  ADC #$04
  STA $0203
 
 

  LDA player
  CLC
  ADC pdirection+1 ; A = A - 1
  STA $020B

 LDA player
  CLC
  ADC pdirection+2  ;     ; A = A - 1
  STA $020F

  LDA player
  CLC
  ADC pdirection+1  ; A = A - 1
  STA $0213

  LDA player
  CLC
  ADC pdirection+2  ;     ; A = A - 1
  STA $0217
 
Gravity:

 

 
  LDA #GROUND
  CLC
  ADC #$01
  STA feet
 
  LDA player+1
  CLC
  ADC #$08
  STA grounded
   
 
 
 
   
 
  LDA grounded
  CMP #GROUND
  BEQ Fl
 
  JMP NP1
 
AnimationP3:
  JMP AnimationP1
 
Fl:
 
  LDA JumpState
  CMP #$01
  BCC AnimationP3
 
  LDA JumpState
  CMP #$01
  BEQ Jump
 
 
  LDA JumpState
  CMP #$01
  BEQ Jump
 
  LDA JumpState
  CMP #$02
  BEQ Delay
 
 
  LDA JumpState
  CMP #$03
  BEQ FP1
 
NP1:
 
  LDA JumpState+2
  CMP #$01
  BEQ Fl
 
  LDA #$03
  STA JumpState
 
  JMP Fl
 

Jump:

 


  LDA #$01
  STA JumpState+2
 
  LDA #$00
  STA gravity
 
 
  LDA #$01
  STA jheight
 
 
 
  LDA player+1
  CMP #$80
  BEQ Pa2
 
  JMP Can
 
Pa2:
 
  LDA scroll+1
  CMP #$FF
  BEQ Can
 
  LDA scroll+1
  CMP #$00
  BEQ Can
 
  LDA scrolly
  SEC
  SBC jheight
  STA scrolly
 
Can:
 
  LDA player+1
  SEC
  SBC jheight
  STA player+1
 
  LDA JumpState+1
  CLC
  ADC #$01
  STA JumpState+1
 
  LDA JumpState+1
  CMP #$18
  BCC AnimationP1
 
  LDA #$02
  STA JumpState
 
  LDA #$00
  STA JumpState+1
 
  LDA #$00
  STA JumpState+1
 
  JMP AnimationP1
 
FDP1:
  JMP FallDone

AnimationP1:
 
  JMP Animation

  FP1:
  JMP Fall
 


 
Delay:

 
  LDA #$00
  STA gravity
 
  LDA player+1
  SEC
  SBC jheight
  STA player+1
 
 
  LDA #$01
  STA jheight
 
 
  LDA JumpState+1
  CLC
  ADC #$01
  STA JumpState+1
 
 
  LDA JumpState+1
  CMP #$1E
  BCS P2
 
  LDA Timer1+3
  STA jheight
 
  JMP AnimationP1
 
P2:
 
  LDA JumpState+1
  CMP #$25
  BCS P3
 
  LDA #$00
  STA jheight
 
 
  JMP AnimationP1
 
AnimationP2:
  BCC AnimationP1
 
P3:
 
 
  LDA #$01
  STA gravity
 
  LDA #$01
  STA gravity
 
  LDA #$00
  STA jheight
 
  LDA JumpState+1
  CMP #$2A
  BCS P4
 
  LDA #$01
  STA gravity
 
  LDA #$01
  STA gravity
 
  JMP AnimationP1
 
P4:
 
 
  LDA #$00
  STA JumpState+1
 
  LDA #$03
  STA JumpState
 
 
  JMP AnimationP1
 

 
Fall:
 
  LDA grounded
  CMP feet
  BCS FDP1
 
  LDA #$00
  STA jheight
 
  LDA #$01
  STA gravity
 
  LDA player+1
  CLC
  ADC gravity
  STA player+1
 
  LDA JumpState+1
  CMP #$15
  BCS MV
 
  LDA JumpState+1
  CLC
  ADC #$01
  STA JumpState+1
 
  BCC AnimationP2
 
MV:
 
  LDA #$02
  STA gravity
 
  JMP AnimationP2
 
 

 

 

 
FallDone:

  LDA #$01
  STA JumpState+2
 
 
  LDA #$00
  STA gravity
 
  LDA #$00
  STA JumpState
 
  LDA #$00
  STA JumpState+1
 
  BCC AnimationP2
 
 
FireJump:
 
 
 
Animation:
 
  LDA JumpState
  CMP #$01
  BEQ JAniP
 
  LDA JumpState
  CMP #$02
  BEQ DAniP
 
  LDA JumpState
  CMP #$03
  BEQ FAniP
 
  LDA T
  CMP #$01
  BCC  Rss
 
  LDA Timer1
  CMP #$0F
  BCS  ResP2
 
  LDA Timer1
  CLC
  ADC #$01
  STA Timer1
 
  BCC SAni
 
 
ResP1:
 BCC Res
 
ResP2:
 BCS Res
 
 
Rss:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$06
  STA Srt
 
  LDA #$02
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
  BCC DoneP1
 
 
Res:
 
  LDA #$00
  STA Timer1
 
  LDA Ant
  CLC
  ADC #$01
  STA Ant
  BCC DoneP1
 
Rse:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  BCC DoneP1
 
JAniP:
 
  JMP JAni
  RTS
 
 
FAniP:
 
  JMP FAni
  RTS
 
DAniP:
 
  JMP DAni


  RTS

SAni:

 LDA JumpState
 CMP #$01
 BEQ JAni
 
 
 
 
FrameA1:
  LDA Ant
  CMP #$01
  BEQ FA2
  LDA #$0C
  STA Srt
 
  LDA #$04
  STA Srt+1
 
  LDA #$10
  STA Srt+2
 
  BCC DoneP1
 

 
FA2:
 
  LDA Ant
  CMP #$02
  BEQ FA3
  LDA #$0A
  STA Srt
 
  LDA #$02
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
  BCC DoneP1

FA3:
 
  LDA Ant
  CMP #$03
  BEQ FA4
  LDA #$0C
  STA Srt
 
  LDA #$0E
  STA Srt+1
 
  LDA #$0F
  STA Srt+2
 
 
  BCC DoneP1
 
RsP1:
  BCC Done
 
  DoneP1:
  BCC Done
 

 
  FA4:
 
  LDA Ant
  CMP #$04
  BEQ Rse
  LDA #$0A
  STA Srt
 
  LDA #$02
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
  BCC DoneP1
 
  LDA Ant
  CMP #$03
  BCS  RsP1
 




JAni:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$08
  STA Srt
 
  LDA #$04
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
 
 
  JMP Done
 
DAni:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$25
  STA Srt
 
  LDA #$23
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
 
 
  JMP Done
 
FAni:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$0C
  STA Srt
 
  LDA #$24
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
 
 
  JMP Done

Done:

 

ReadController1:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016
  LDX #$08
ReadController1Loop:
  LDA $4016
  LSR A            ; bit0 -> Carry
  ROL buttons     ; bit0 <- Carry
  DEX
  BNE ReadController1Loop
 
  RTS
 
ReadController2:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016
  LDX #$08
ReadController2Loop:
  LDA $4017
  LSR buttonslay            ; bit0 -> Carry
  ROL buttons     ; bit0 <- Carry
  DEX
  BNE ReadController2Loop
 
  RTS
 

 



 
  RTS

LoadPalettes2:


  LDA #%00000000        ; set to increment +32 mode
  STA $2000
 
 
  LDA $2002             ; read PPU status to reset the high/low latch
 
 
  LDA #$00
  STA Timer1+5
  STA Timer1+6
 
  LDX #$00
 
LP2:
 
   
 
  LDA #$3F
  STA $2006
  LDA Timer1+6
  STA $2006
 
  LDA paletteswap , x
  STA $2007
   
 
 
 
  INX
 
  INC Timer1+5
 
  INC Timer1+6
 
  LDA Timer1+5
  CMP #$20
  BEQ Fin
 
 
  JMP LP2
 
Fin:


  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  RTS
 
   

 
 
 
 
 
 


 
 
 
;;;;;;;;;;;;;; 
 
 
 
  .bank 1
  .org $E000
palette:
  .db $02,$11,$01,$0F,$02, $04,$36,$37,$02,$39,$3A,$3B,$02,$16,$05,$0f
  .db $02,$16,$20,$38,$01,$0F,$07,$37,$02,$1C,$15,$14,$02,$0F,$07,$37
 
palette3:
  .db $02,$11,$01,$0F,$02, $04,$36,$37,$02,$39,$3A,$3B,$02,$16,$05,$0f
  .db $02,$16,$20,$38,$01,$0F,$07,$37,$02,$1C,$15,$14,$02,$0F,$07,$37
 
Playersprites:
   ; Player
   ;vert tile attr horiz
  .db $80, $00, $1C, $80   ;sprite 0
  .db $88, $02, $1C, $80   ;sprite 2
  .db $88, $03, $00, $88   ;sprite 3
  .db $88, $03, $00, $88   ;sprite 3
  .db $88, $03, $00, $88   ;sprite 3
  .db $8F, $04, $00, $80   ;sprite 3
 
 
;Bullets
Bullets:
  .db $8F, $1F, $04, $88 
  .db $8F, $1F, $04, $88 
  .db $8F, $1F, $04, $88 
  .db $8F, $FF, $04, $88 
 

Esprites:
  .db $10, $2F, $04, $88 
  .db $FF, $2F, $04, $FF 
  .db $8F, $1F, $04, $88 
  .db $8F, $FF, $04, $88 
 
  ;sprite 3
 
columnData:
 
 
 
 
  .incbin "KitsuneTaleslevel.bin"
 
 
 
columnDatay:
  .incbin "KitsuneTaleslevel2.bin"

attribData:
  .incbin "KitsuneTalesattrib.bin"
 
attribDatay:
  .incbin "KitsuneTalesattrib2.bin"
 
 

 
 
 
  .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 "KitsuneTalesShiroAkai.chr"
  ;;;;;;;;;;;;;;;;;;;;
  .bank 3
  .org $A000
  .incbin "Kitsunetales.chr"
 
 ;;;;;;;;;;;;;;;;;;;
 
  .bank 4
  .org $E000
 

What this is doing so far is that you ave a character running around with 5 8x8 sprites attached to it.
You can jump, the pallete stack $3F11 should change constantly, The nametables $20 and $28 should be both filled with a screen worth of info if a full level is loaded ala SMB3, Finally, paletteswap is the palette swapping variable.
GAME : Kitsune Tales


Top
 Profile  
 
PostPosted: Fri Jul 21, 2017 2:42 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
I see you moved out some of the logic from the beginning of the NMI, not everything though, the INC Scroll and the NTSwapCheck stuff are also logic and should be moved down after graphic updates. But now you have much more vblank time, do you still have the same problem?

I saw some other weird things. You clear RAM (at "clrmem") except page 3 that you fill with $FE:
Code:
  ;...
  LDA #$FE
  STA $0300, x
  ;...

You probably meant to fill page 2 with $FE to avoid stray sprites at boot since you are using that page as your OAM buffer for OAM-DMA.

And you only read bit 0 of $4016/$4017 in your controller reading routine so expansion port controllers doesn't work. You should read bit 1 as well unless it's a 4-player game.

Also I see you are doing the All-in-NMI approach. That's fine (Super Mario Bros is doing it that way) but it has its limits, and having logic in the main loop (the loop at "Forever" in your code) makes things more clear I think.


Top
 Profile  
 
PostPosted: Fri Jul 21, 2017 3:22 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
1. Yes, But listening to you des make a difference and that's nice. Wait I moved more logic around and It made a difference.
2. I Don't want the All nmi approach. I want some of the rendering to go Outside Like text, boss AI and other stuff. I heard that It boggles down speed if your not careful.
3. It's a one player game. However, If I get to demaking smash bros., I'll need that info
4. I found an article on stacks pha and pla. I just need to figure out where my buffer's going to go.
5. that was on the nerdy nights tutorial.
6. The scroll is only affected when it loads a section of the attibutes and the back ground.
7. I feel like I went too far off talking about stacks and what not. Should I continue?


Last edited by IMAGICA on Fri Jul 21, 2017 6:53 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Fri Jul 21, 2017 5:11 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1832
Location: DIGDUG
If you are still having glitches, you're doing too much at once. One quick fix, would be to do the attribute table writes a frame early. It would look something like this...

NewAttribCheck:
LDA scroll
CLC ;!
ADC #1. ;!
AND #%00011111 ; check for multiple of 32
BNE NewAttribCheckDone ; if low 5 bits = 0, time to write new attribute bytes
jsr DrawNewAttributes

It may need more than just this, to make sure you write to the correct Nametable.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Sat Jul 22, 2017 4:45 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
IMAGICA wrote:
2. I Don't want the All nmi approach. I want some of the rendering to go Outside Like text, boss AI and other stuff. I heard that It boggles down speed if your not careful.

Then just move out all your logic from the NMI and put it in your forever loop. Only keep the graphic updates (OAM, VRAM, $2000, $2001 and $2005 writes) in the NMI.

IMAGICA wrote:
3. It's a one player game. However, If I get to demaking smash bros., I'll need that info

You misunderstand me. If it's a one player game, you need to read both bit 0 and bit 1 of $4016 to your controller 1 data so that people can use both standard controllers and Famicom expansion port controllers. Nerdy Nights doesn't teach this but it's good practice to do it. Else people might not be able to use their arcade sticks and other controllers with your game.

IMAGICA wrote:
4. I found an article on stacks pha and pla. I just need to figure out where my buffer's going to go.

Your buffers goes into RAM wherever there is space. You are already buffering OAM and scroll in RAM. I like to keep my OAM buffer on RAM page 2 ($0200~$02FF), BG and palette buffers in page 3, and scroll and $2000/$2001 buffers in the zero page. The BG buffer can't be too big (there's not enough vblank time to draw the whole nametable), so you could also keep BG and palette buffers at the beginning of page 1. The stack starts in the other end of page 1 so unless you use a lot of stack there's no risk they will collide.


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 8:30 am 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
dougeff : Sorry, writing that slows dow the game. I need to learn buffering first
Pokun: What's bit one and how do you get it?


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 9:34 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19252
Location: NE Indiana, USA (NTSC)
Bits in a binary number are traditionally numbered by their place value from right to left.

  • %00000001: Ones place, 1 = 2^0, bit 0
  • %00000010: Twos place, 2 = 2^1, bit 1
  • %00000100: Fours place, 4 = 2^2, bit 2
  • %00001000: Eights place, 8 = 2^3, bit 3
  • %00010000: Sixteens place, 16 = 2^4, bit 4
  • %00100000: Thirty-twos place, 32 = 2^5, bit 5
  • %01000000: Sixty-fours place, 64 = 2^6, bit 6
  • %10000000: One-hundred-twenty-eights place, 128 = 2^7, bit 7


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 80 posts ]  Go to page 1, 2, 3, 4, 5, 6  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 11 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