It is currently Tue Sep 17, 2019 9:42 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Thu Aug 15, 2019 8:06 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 93
Location: Italy
Hello to everyone, I'm creating a new prototype for NES. I've an "action space matrix" where the player can move in 4 directions as you can see in the image.

Image

I need to change the background into the matrix at runtime with some wall sprites. The matrix PPU address start at 2103 and it end at 2376. I created a loop to change the background tile by tile, row by row:

;2103 -> 2116
;2120 -> 2136
;...
;2303 -> 2376


Code:
generate_random_walls:
  lda $2002             
  lda #$21
  sta $2006             
  lda #$03
  sta $2006             

  ldx #$00
  ldy #$00
.gen_random_walls_loop:
    lda #$C2
    sta $2007
    inx
    cpx #$14
    bne .gen_random_walls_loop

    .go_next_row:


when the loop goes to #$16 on the X register I need to "jump" from $2116 to $2120 and continue to write on PPU that auto increment by one every time. So, what's the best way to do that? I've to reset the address in this way at next row? Or there is a more efficent way?

Code:
lda $2002             
  lda #$21
  sta $2020             
  lda #$03
  sta $2006             


Thanks a lot! :)


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 8:30 am 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
You should keep the base address as a variable in RAM, as opposed to hardcoding it in the logic, so you can modify it as you move down the screen. For example:

Code:
  ;initialize the address for the first row
  lda #$03
  sta ScreenAddress+0
  lda #$21
  sta ScreenAddress+1


Then at the start of every row you can set the address from this variable:

Code:
  ;start the row
  lda ScreenAddress+1
  sta $2006
  lda ScreenAddress+0
  sta $2006


And at the end of every row, you increment the address by 32 (the number of times in a full row) to move one row down:

Code:
  ;move one row down
  clc
  lda ScreenAddress+0
  adc #$20
  sta ScreenAddress+0
  lda ScreenAddress+1
  adc #$00
  sta ScreenAddress+1


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 8:56 am 
Offline
User avatar

Joined: Tue Feb 27, 2018 10:41 am
Posts: 57
Location: Brazil
This should do the trick (untested code!!)

Code:
PPUSTATUS   = $2002
PPUADDR      = $2006
PPUDATA      = $2007
START_ADDR   = 2103
MATRIX_ROWS   = 10 ; arbritrary value
MATRIX_COLS   = $13
TILE      = $c2

generate_random_walls:
   lda PPUSTATUS             
   lda #>START_ADDR
   sta PPUADDR         
   lda #<START_ADDR
   sta PPUADDR           

   ldy #MATRIX_ROWS
   lda #TILE
gen_rows:
   ldx #MATRIX_COLS
gen_cols:
   sta PPUDATA
   dex
   bne gen_cols
   ldx #(32-MATRIX_COLS)
skip_col:
   bit PPUDATA
   dex
   bne skip_col
   dey
   bne gen_rows


EDIT: changed 1st line after skip_col label

_________________
itch.io | github


Last edited by NOOPr on Thu Aug 15, 2019 9:08 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 9:05 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 93
Location: Italy
Thanks a lot, I will try as soon as I can. :)


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 9:32 am 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
Cool! Skipping the remaining positions is definitely an elegant approach in this case!


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 9:55 am 
Offline
User avatar

Joined: Tue Feb 27, 2018 10:41 am
Posts: 57
Location: Brazil
tokumaru wrote:
Cool! Skipping the remaining positions is definitely an elegant approach in this case!

The first time I saw this bit $2007 to increment $2006 was in a reply from you on a topic about change palette mid frame

_________________
itch.io | github


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 10:20 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 93
Location: Italy
NOOPr wrote:
This should do the trick (untested code!!)

Code:
PPUSTATUS   = $2002
PPUADDR      = $2006
PPUDATA      = $2007
START_ADDR   = 2103
MATRIX_ROWS   = 10 ; arbritrary value
MATRIX_COLS   = $13
TILE      = $c2

generate_random_walls:
   lda PPUSTATUS             
   lda #>START_ADDR
   sta PPUADDR         
   lda #<START_ADDR
   sta PPUADDR           

   ldy #MATRIX_ROWS
   lda #TILE
gen_rows:
   ldx #MATRIX_COLS
gen_cols:
   sta PPUDATA
   dex
   bne gen_cols
   ldx #(32-MATRIX_COLS)
skip_col:
   bit PPUDATA
   dex
   bne skip_col
   dey
   bne gen_rows


EDIT: changed 1st line after skip_col label


This code works great! Thanks a lot!


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 10:45 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7582
Location: Canada
Reading $2007 to increment the address is useful, but usually only for a small number of increments in a row. Each BIT $2007 is 4 cycles, so that "small number" might be 4 or 5.

In that loop with DEX/BNE that's 9 cycles each, so it becomes slower after only 3 loops or so. It's probably a good solution for small code (or simple code), but if you find yourself needing to squeeze more into your vblank it's maybe not going to be the best option.


Alternatives:

If start is the starting address of your update, you can jump to an arbitrary offset from it in 22 cycles. Consider that you don't have to write this result back to start: you can do all the skips relative to the start, rather than the current position, which can probably save a few cycles.
Code:
lda start+0
clc ; can potentially omit this for another -2 cycles if careful
adc #<offset
tax
lda start+1
adc #>offset
sta $2006
stx $2006


Also, if you want to increment by 32 specifically you could write to $2000 to switch increment mode then switch back. This seems to cost 16 cycles already, so unless you're looking for 32 or 33 specifically it's probably better to just go through $2006.
Code:
lda #%10000100 ; +32 increment mode
sta $2000
bit $2007 ; skip 32
lda #%10000000 ; +1 increment mode
sta $2000


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 11:41 am 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
Since this code appears to be drawing the entire board, I assume it's not running during vblank, but during the initialization of the level. If this is the case, the time spent BIT'ing $2007 is irrelevant, making the simplicity and compactness of the code more desirable IMO.

During vblank though, where every cycle counts, it indeed only makes sense to use BIT if that's faster than the alternative.


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 12:13 pm 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 93
Location: Italy
This code will run only once at change of the room. So it's not so critical. But thanks, I will try to study your code anyway. :)


Top
 Profile  
 
PostPosted: Thu Aug 15, 2019 5:32 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
Just to make it clear: I'm saying that NOOPr's code looks pretty good for this particular situation, more elegant and compact than what I had suggested. IMO you should stick with it.


Top
 Profile  
 
PostPosted: Fri Aug 23, 2019 7:56 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 93
Location: Italy
Hello again, I'm using your tips to implement creation of the matrix, ( 16x16 tiles ), everything works great when I start the game and i generate it with this code:

Code:
gen_level_0_room_0:
  ldy #MATRIX_ROWS

  gen_rows:
    ldx #MATRIX_COLS
   
    gen_cols:
     
      ;jsr generate_random_tile 

      lda #$D0
      sta PPUDATA

      dex
      bne gen_cols
      ldx #( 32 - MATRIX_COLS ) ;32x30 tiles
     
      skip_col:
        bit PPUDATA
        dex
        bne skip_col
        dey
        bne gen_rows

  rts


For now I'm putting the tile "#$D0". The problems start when I want to re-generate the matrix to change the room, for some reason it start to glitch probably because i'm putting too many cycles into vblank? What's the best pratices to update the background matrix once when the player it the door? In my previous game I can change the entire background without glitch, but I try to update a portion of the screen, it glitch.

Any idea? Thanks a lot!


Top
 Profile  
 
PostPosted: Fri Aug 23, 2019 10:12 am 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
For large PPU updates you have to turn rendering off, so you have free access to VRAM, and turn it back on once you're done. There are a couple of things you should keep in mind though:

1- Wait for vblank (via the NMI handler, not the "buggy" $2002 vblank flag) before turning rendering off, to avoid turning it off mid-screen and causing a brief visual glitch;

2- Take precautions to prevent the NMI handler from interfering with your large PPU updates. You should either have a flag indicating whether the NMI handler is allowed to touch the PPU, or disable NMIs altogether at the same time you disable rendering, then enable NMIs again along with rendering when you're done updating. If you do disable NMIs, you won't be able to play sounds or music during these transitions.


Top
 Profile  
 
PostPosted: Fri Aug 23, 2019 12:12 pm 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 93
Location: Italy
Thanks. Another solution could be to create a "fade in" effect that draw one column at time every t interval. :D

But, my question is, how Zelda room transition works? It scroll the entire screen without problem.


Top
 Profile  
 
PostPosted: Fri Aug 23, 2019 2:06 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7582
Location: Canada
kikutano wrote:
It scroll the entire screen without problem.

You don't see a whole new screen in a single frame. You can spread out the changes across several vblanks.

If you want to see what Zelda does, open the nametable viewer in FCEUX or Mesen and go frame by frame as you pass to the next room. You can watch the whole process.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


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