It is currently Mon Sep 16, 2019 1:02 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Tue Sep 03, 2019 11:32 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 287
Location: Poland
I wrote a simple code that generates items on the screen in the form of background elements. It works, but I would like to do better. I have a problem generating the HI address using a similar table that I used to generate the LO. Instead, it generates HI by comparing RNG values every 64 and then increasing HI by one.

Code:
;################################################################################

PlaceRandomItem:

   LDA PlaceRandomItem_Flags   ;bit 0 code control (ora bit0 = run code, and = lock)
   AND #%00000001
   BEQ PlaceRandomItem_no

   LDY RNG            ;generate PPU LO
   LDA TablePPU_LO,y
   STA PPU_LO_Temp

   JSR TablePPU_HI         ;jump generate PPU HI

   LDA PlaceRandomItem_Flags   ;bit 1 blocks writing to PPU when RNG is above 240 (ora bit1 = run code)
   AND #%00000010
   BEQ PlaceRandomItem_no

   LDA PPU_HI_Temp
   STA $2006
   LDA PPU_LO_Temp
   STA $2006

   LDA ItemTile1of4
   STA $2007
   LDA ItemTile2of4
   STA $2007

   LDA PPU_HI_Temp
   STA $2006
   LDA PPU_LO_Temp
   CLC
   ADC #32
   STA $2006

   LDA ItemTile3of4
   STA $2007
   LDA ItemTile4of4
   STA $2007

   LDA PlaceRandomItem_Flags   ;lock the code when done
   AND #%11111100
   STA PlaceRandomItem_Flags

PlaceRandomItem_no:
   RTS

;################################################################################

TablePPU_LO:

   .db $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12,$14,$16,$18,$1A,$1C,$1E
   .db $40,$42,$44,$46,$48,$4A,$4C,$4E,$50,$52,$54,$56,$58,$5A,$5C,$5E
   .db $80,$82,$84,$86,$88,$8A,$8C,$8E,$90,$92,$94,$96,$98,$9A,$9C,$9E
   .db $C0,$C2,$C4,$C6,$C8,$CA,$CC,$CE,$D0,$D2,$D4,$D6,$D8,$DA,$DC,$DE
   .db $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12,$14,$16,$18,$1A,$1C,$1E
   .db $40,$42,$44,$46,$48,$4A,$4C,$4E,$50,$52,$54,$56,$58,$5A,$5C,$5E
   .db $80,$82,$84,$86,$88,$8A,$8C,$8E,$90,$92,$94,$96,$98,$9A,$9C,$9E
   .db $C0,$C2,$C4,$C6,$C8,$CA,$CC,$CE,$D0,$D2,$D4,$D6,$D8,$DA,$DC,$DE
   .db $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12,$14,$16,$18,$1A,$1C,$1E
   .db $40,$42,$44,$46,$48,$4A,$4C,$4E,$50,$52,$54,$56,$58,$5A,$5C,$5E
   .db $80,$82,$84,$86,$88,$8A,$8C,$8E,$90,$92,$94,$96,$98,$9A,$9C,$9E
   .db $C0,$C2,$C4,$C6,$C8,$CA,$CC,$CE,$D0,$D2,$D4,$D6,$D8,$DA,$DC,$DE
   .db $00,$02,$04,$06,$08,$0A,$0C,$0E,$10,$12,$14,$16,$18,$1A,$1C,$1E
   .db $40,$42,$44,$46,$48,$4A,$4C,$4E,$50,$52,$54,$56,$58,$5A,$5C,$5E
   .db $80,$82,$84,$86,$88,$8A,$8C,$8E,$90,$92,$94,$96,$98,$9A,$9C,$9E
   .db $C0,$C2,$C4,$C6,$C8,$CA,$CC,$CE,$D0,$D2,$D4,$D6,$D8,$DA,$DC,$DE

;################################################################################

TablePPU_HI:                               ;not used

   .db $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20
   .db $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20
   .db $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20
   .db $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20
   .db $21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21
   .db $21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21
   .db $21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21
   .db $21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21,$21
   .db $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22
   .db $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22
   .db $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22
   .db $22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22,$22
   .db $23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23
   .db $23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23
   .db $23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23
   .db $23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23,$23   ;attr table, don't generate

;################################################################################

TablePPU_HI:              ;used

   LDA RNG
   CMP #00
   BCC TablePPU_HI_Skip0

   LDA #$20
   STA PPU_HI_Temp

TablePPU_HI_Skip0:

   LDA RNG
   CMP #64
   BCC TablePPU_HI_Skip1

   LDA #$21
   STA PPU_HI_Temp

TablePPU_HI_Skip1:

   LDA RNG
   CMP #128
   BCC TablePPU_HI_Skip2

   LDA #$22
   STA PPU_HI_Temp

TablePPU_HI_Skip2:

   LDA RNG
   CMP #192
   BCC TablePPU_HI_Skip3

   LDA #$23
   STA PPU_HI_Temp

TablePPU_HI_Skip3:

   LDA RNG
   CMP #240
   BCC TablePPU_HI_Skip4

   LDA #$00
   STA PPU_HI_Temp
   STA PPU_LO_Temp

   LDA PlaceRandomItem_Flags   ;blocks writing to PPU when RNG is above 240
   AND #%11111101
   STA PlaceRandomItem_Flags

TablePPU_HI_Skip4:
   RTS


Attachments:
File comment: A/B button generate item on screen
demoRNGitem.nes [128.02 KiB]
Downloaded 5 times
Top
 Profile  
 
PostPosted: Tue Sep 03, 2019 12:15 pm 
Offline
User avatar

Joined: Tue Feb 27, 2018 10:41 am
Posts: 57
Location: Brazil
I think you don't need those tables:
Code:
   jsr rng ; rng is a proc that generates a random number from 0 to 255 in A
   and #3   ; A have a value from 0 to 3
   clc
   adc #$20   ; now A have $20 to $23
   sta PPUADDR   ; set HI byte PPU address
   
   jsr rng      ; generate another random byte
   cmp #240
   bcc set_hi
   sbc #240   ; A have 0 to 239
set_hi:
   sta PPUADDR   ; set LO byte PPU address

EDIT: fixed the low byte calculation

_________________
itch.io | github


Top
 Profile  
 
PostPosted: Wed Sep 04, 2019 12:41 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 287
Location: Poland
Thanks, in fact, incomparably smaller code. The only problem is that all addresses of 8x8 BGR tiles are randomly drawn, while 16x16 blocks should be. In addition, the values enter the attribute tables. After all, I would also like to see how to change the original code and use the "TablePPU_HI" table, which I had a problem with - curiosity, for learning to analyze the code.

Code:
;################################################################################

PlaceRandomItem2:

   LDA PlaceRandomItem2_Flags
   AND #%00000001
   BEQ PlaceRandomItem2_no

   LDA RNG        ; rng is a proc that generates a random number from 0 to 255 in A
   AND #3      ; A have a value from 0 to 3
   CLC
   ADC #$20   ; now A have $20 to $23
   STA PPU_HI_Temp   ; set HI byte PPU address
   
   LDA RNG      ; generate another random byte
   CMP #240
   BCC set_hi
   SBC #240   ; A have 0 to 239
set_hi:
   STA PPU_LO_Temp   ; set LO byte PPU address

;-------

   LDA PPU_HI_Temp
   STA $2006
   LDA PPU_LO_Temp
   STA $2006

   LDA ItemTile1of4
   STA $2007
   LDA ItemTile2of4
   STA $2007

   LDA PPU_HI_Temp
   STA $2006
   LDA PPU_LO_Temp
   CLC
   ADC #32
   STA $2006

   LDA ItemTile3of4
   STA $2007
   LDA ItemTile4of4
   STA $2007

   LDA PlaceRandomItem2_Flags
   AND #%11111110
   STA PlaceRandomItem2_Flags

PlaceRandomItem2_no:
   RTS


Attachments:
File comment: A/B - old code, STA/SEL - NOOPr code
demoRNGitem_2.nes [128.02 KiB]
Downloaded 5 times
Top
 Profile  
 
PostPosted: Wed Sep 04, 2019 5:49 am 
Offline
User avatar

Joined: Tue Feb 27, 2018 10:41 am
Posts: 57
Location: Brazil
sdm wrote:
The only problem is that all addresses of 8x8 BGR tiles are randomly drawn, while 16x16 blocks should be

Sorry, I missed that.
Just replace
Code:
   jsr rng      ; generate another random byte
   cmp #240

by
Code:
   jsr rng      ; generate another random byte
   asl a        ; an even low byte
   cmp #240

_________________
itch.io | github


Top
 Profile  
 
PostPosted: Wed Sep 04, 2019 8:34 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
Since there are only 16x15=240 16x16-pixel blocks in one screen, a single pseudo-random number provides enough bits to select one of them. You just need to convert this: YYYYXXXX (random byte) into this: 001000YY YY0XXXX0 (NT address). Here's one way to do it:

Code:
   ;get random coordinates and make sure they're in range
   jsr rng
   cmp #$f0
   bcc savecoords
   sbc #$f0
savecoords:
   sta xcoord ;save %YYYYXXXX
   and #%11110000 ;keep only %YYYY0000
   sta ycoord

   ;calculate the high byte of the address
   lda #%00001000 ;$20 >> 2, ready to be shifted left 2x
   asl ycoord
   rol
   asl ycoord
   rol ;A = %001000YY, ycoord = YY000000
   sta nthigh

   ;calculate the low byte of the address
   lda xcoord
   and #00001111 ;keep only %0000XXXX
   asl ;A = %000XXXX0
   ora ycoord ;A = %YY0XXXX0
   sta ntlow


If by any chance you need the attribute address as well (i.e. you need to change the block's colors), the original random number is still available in the xcoord variable, so you can use it to convert this: YYYYXXXX (random byte) into this: 00100011 11YYYXXX (AT address) + 000000YX (index of mask to clear and set attribute quadrants). Here's an idea:

Code:
   ;set the high byte of the address
   lda #%00100011
   sta athigh
   
   ;put all the bits in place
   lda xcoord
   lsr ;A = %0YYYYXXX, C = lowest X bit
   sta xcoord
   and #%01111000 ;keep only %0YYYY000
   adc #%00000011 ;A = %0YYYYX** (lowest X bit in bit 2)
   lsr ;A = %00YYYYX*
   sta ycoord
   lsr ;A = %000YYYYX
   and #%00000011 ;keep only %000000YX
   sta quadrant ;index of the attribute quadrant
   
   ;form the low byte of the address
   lda xcoord
   and #%00000111 ;keep only %00000XXX
   sta xcoord
   lda ycoord
   and #%00111000 ;keep only %00YYY000
   ora xcoord ;A = %00YYYXXX
   ora #%11000000 ;A = %11YYYXXX
   sta atlow


In order to update the attribute byte, you have to read it from the attribute table, clear the space for the new bits, set the new bits, and finally write the byte back. Something like this:

Code:
   ;prapare the new attribute bits
   ldx quadrant
   lda attribute
   and quadrantkeep, x
   sta attribute

   ;get the attribute byte from VRAM
   lda athigh
   sta $2006
   lda atlow
   sta $2006
   lda $2007
   lda $2007

   ;put the new bits in
   and quadrantclear, x
   ora attribute

   ;write the byte back to VRAM
   ldx athigh
   stx $2006
   ldx atlow
   stx $2006
   sta $2007


The tables to keep and clear attribute bits for each quadrant are these:

Code:
quadrantkeep:
   .db %00000011
   .db %00001100
   .db %00110000
   .db %11000000

quadrantclear:
   .db %11111100
   .db %11110011
   .db %11001111
   .db %00111111


It's worth noting that since you're using random coordinates, you don't necessarily have to respect the bit layouts I've used here (for random positions, it shouldn't matter which bits go where as long as all target spaces are filled), but I think it's a good idea to code it that way because then you can reuse the exact same logic in case you want to update blocks in known positions as well.

BTW, I haven't tested any of this code, so I may have made mistakes.


Top
 Profile  
 
PostPosted: Wed Sep 04, 2019 11:30 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 287
Location: Poland
Thanks Tokumaru for the extended code, I will check.

NOOPr wrote:
sdm wrote:
The only problem is that all addresses of 8x8 BGR tiles are randomly drawn, while 16x16 blocks should be

Sorry, I missed that.
Just replace
Code:
   jsr rng      ; generate another random byte
   cmp #240

by
Code:
   jsr rng      ; generate another random byte
   asl a        ; an even low byte
   cmp #240


Unfortunately, it doesn't work. :/ (run demo3.nes and press STA/SEL to run code [ A/B old code])


Attachments:
demo3.nes [128.02 KiB]
Downloaded 3 times
Top
 Profile  
 
PostPosted: Wed Sep 04, 2019 12:13 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
Using even addresses wouldn't align them to the 16x16-pixel grid anyway, because that'd only affect the horizontal alignment. You should probably use an and #%11011110 instead of that asl a, so that both the X and Y coordinates are made even.


Top
 Profile  
 
PostPosted: Thu Sep 05, 2019 12:15 pm 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 287
Location: Poland
I used your code. I just don't know if I understood correctly.

A / B button run code, D-PAD changes the palette. More precisely UP - lda 00000000 sta attribute, DOWN - lda 00000001 sta attribute, LEFT - lda 00000010 sta attribute, RIGHT - lda 00000011 sta attribute (demo4.nes)

Works, but the colors don't always change.

Code:
;################################################################################

PlaceRandomItem3_no:
   RTS
PlaceRandomItem3:      ;in NMI

   LDA PlaceRandomItem3_Flags
   AND #%00000001
   BEQ PlaceRandomItem3_no

   LDA RNG_Byte
   CMP #$F0
   BCC savecoords
   SBC #$F0

savecoords:

   STA xcoord      ;save %YYYYXXXX
   AND #%11110000      ;keep only %YYYY0000
   STA ycoord

            ;calculate the high byte of the address

   LDA #%00001000      ;$20 >> 2, ready to be shifted left 2x
   ASL ycoord
   ROL A
   ASL ycoord
   ROL A         ;A = %001000YY, ycoord = YY000000
   STA nthigh

            ;calculate the low byte of the address
   LDA xcoord
   AND #%00001111      ;keep only %0000XXXX
   ASL A         ;A = %000XXXX0
   ORA ycoord      ;A = %YY0XXXX0
   STA ntlow

;-------

   LDA nthigh
   STA $2006
   LDA ntlow
   STA $2006

   LDA tile1
   STA $2007
   LDA tile2
   STA $2007

   LDA nthigh
   STA $2006
   LDA ntlow
   CLC
   ADC #32
   STA $2006

   LDA tile3
   STA $2007
   LDA tile4
   STA $2007

;-------

   lda #%00100011
   sta athigh
            ;put all the bits in place
   lda xcoord
   lsr A         ;A = %0YYYYXXX, C = lowest X bit
   sta xcoord
   and #%01111000      ;keep only %0YYYY000
   adc #%00000011      ;A = %0YYYYX** (lowest X bit in bit 2)
   lsr A         ;A = %00YYYYX*
   sta ycoord
   lsr A         ;A = %000YYYYX
   and #%00000011      ;keep only %000000YX
   sta quadrant      ;index of the attribute quadrant

            ;form the low byte of the address
   lda xcoord
   and #%00000111      ;keep only %00000XXX
   sta xcoord
   lda ycoord
   and #%00111000      ;keep only %00YYY000
   ora xcoord      ;A = %00YYYXXX
   ora #%11000000      ;A = %11YYYXXX
   sta atlow

   ldx quadrant
   lda attribute
   and quadrantkeep,x
   sta attribute
            ;get the attribute byte from VRAM
   lda athigh
   sta $2006
   lda atlow
   sta $2006
   lda $2007
   lda $2007
            ;put the new bits in
   and quadrantclear,x
   ora attribute
            ;write the byte back to VRAM
   ldx athigh
   stx $2006
   ldx atlow
   stx $2006
   sta $2007

   LDA PlaceRandomItem3_Flags      ;lock code
   AND #%11111100
   STA PlaceRandomItem3_Flags

   RTS


EDIT:
I chang D-PAD (UDLR) writing to "attribute" , I changed to:
UP - lda 00000000 sta attribute
DOWN lda 01010101, LEFT - 10101010, RIGHT 11111111.
(demo4b.nes).

Now as we hold down one of the directions (+A/B button) the palette are changing.


Attachments:
demo4b.nes [128.02 KiB]
Downloaded 3 times
demo4.nes [128.02 KiB]
Downloaded 3 times
Top
 Profile  
 
PostPosted: Thu Sep 05, 2019 1:01 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11412
Location: Rio de Janeiro - Brazil
sdm wrote:
EDIT:
I chang D-PAD (UDLR) writing to "attribute" , I changed to:
UP - lda 00000000 sta attribute
DOWN lda 01010101, LEFT - 10101010, RIGHT 11111111.

Yup, the 2 attribute bits are supposed to be repeated 4 times in the source byte, so that any of the pairs can be selected by masking out the others. You can do it differently and shift a single pair of bits depending on the quadrant, but I prefer this way.

One important thing to keep in mind is that normally you'd calculate all the data and addresses beforehand, during render time, and then during vblank you'd only write the data to VRAM, since vblank time is a scarce resource. Unless you don't need that much VRAM bandwidth. Just pay attention to how much of your vblank time is being used so you don't go over the edge.


Top
 Profile  
 
PostPosted: Fri Sep 06, 2019 12:14 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 287
Location: Poland
Thanks. Yes, I know that. Of course, the code itself will be outside VBLANK, and only the transfer of value to $ 2007 through $ 2006 in NMI time.
In this case, everything was in NMI because of the test code.


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

All times are UTC - 7 hours


Who is online

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