Updating a 'random' nametable / pattern tile

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
noattack
Posts: 147
Joined: Tue Feb 13, 2007 9:02 pm
Location: Richmond, VA

Updating a 'random' nametable / pattern tile

Post by noattack »

I'm working on a graphics demo and I want to have a 'random' pattern tile update a 'random' section of my nametable. So, am I correct that the pattern data will choose from one of 256 possibilities and the nametable data will choose from one of 960?

I understand how to update the nametable and redraw the screen, but I don't know how to choose the random values. Will I need a pseudo-random number generator routine or is there a simpler way to do this?

Also, it's only necessary to do a tile at a time.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

There is no way to get a truly random value on the NES without writing your own random number generator. This will be pretty difficult because unlike in a computer, there isn't a value that's constantly changing (like a clock or something) to use as a seed. You would probably need to tell the user to press "A" and use the amount of frames (or even CPU cycles if you want REAL precision) as a seed to generate a random number.

EDIT:
noattack wrote:So, am I correct that the pattern data will choose from one of 256 possibilities and the nametable data will choose from one of 960?
Yes. Though if you want to do attributes, the other 64 bytes of the name table would be used.
User avatar
noattack
Posts: 147
Joined: Tue Feb 13, 2007 9:02 pm
Location: Richmond, VA

Post by noattack »

How about a continually incrementing counter variable that would be 'polled' at various intervals, whose value would then be used as a tile selection? Although then I suppose the interval would need to be random.

I'm stumped. I'm trying to avoid any user interaction, so using the controller is out for a seed value.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

noattack wrote:Although then I suppose the interval would need to be random.
Exactly. How would you get a random interval without user interaction?
I'm trying to avoid any user interaction, so using the controller is out for a seed value.
User input is the only source of randomness I can think of... Other aspects of the NES that might be random (such as register and memory contents) are probably not random enough for seeding a pseudo-random number generator.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Random number generation without user input or an external "seed" is nearly impossible. In a computer, I'm pretty sure they use the time as a seed, because every time it's different. Like Tokumaru said, the only thing that would give you a "random" value would be a register on power up. However, the bad thing about this is usually these registers hold "weird" values; not necessarily random ones. They may hold the same obscure value each time. If in the very beginning of the demo or whatever you're doing, you say "Press A" you can have a loop like this:

loop:
;wait for user to press A, but make sure they're not holding A from the start.
;if didn't press A, increment a variable and loop
;if pressed A, exit loop

And use that incremented value as a seed. This loop would be executed so fast that it would be near humanly impossible to get the same value intentionally. Though I would use a 16-bit variable instead of an 8 bit one, because there are well, more possibilities that way.
User avatar
noattack
Posts: 147
Joined: Tue Feb 13, 2007 9:02 pm
Location: Richmond, VA

Post by noattack »

So, assuming I don't mind the visual output being the same every time the program is executed, I could set my own seed value and still have it run its course.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

When your program is run, show a title screen and ask the user to press A to start the demo. The following code will generate an 8-bit seed for your pseudo-random number generator:

Code: Select all

; Generates 8-bit random value by waiting for user to press A.
; While waiting for A, it increments X 200000 times per second,
; cycling through all 256 values almost 800 times per second.
; X <- random value
; Preserved: Y
get_rng_seed:
    lda #1
    sta $4016
    
wait_released:
    bit $4016
    bne wait_released
    
    tax
debounce:
    inx
    bne debounce
    
wait_pressed:
    inx
    bit $4016
    beq wait_pressed
        
    rts
By leaving the controller clock line set, it can repeatedly read the status of A in the tight loop. Here's a sample of 100 random values it generated, with me pressing A over and over (you wouldn't have the user press A more than once, but this just shows the quality):

90 17 40 03 1C 47 2B 6A A3 47 37 A2 B8 A0 E8 70 53 12 7F 36 18 F7 D1 38 D0 D4 C8 4D D0 B4 A3 75 0F 6C 55 67 76 C4 C6 D8 E5 96 65 4E 16 E6 33 50 AA EA A2 54 99 62 F4 E1 3B 4E 35 FE 63 4A D1 22 CB 1E C4 F7 12 AC 45 74 B0 29 41 D1 3A 89 53 DC E5 A8 09 22 FD 1C FD 92 4D C4 95 62 4C A3 9D DD 4F F9 21 74
User avatar
noattack
Posts: 147
Joined: Tue Feb 13, 2007 9:02 pm
Location: Richmond, VA

Post by noattack »

Awesome. Thank you!
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

noattack wrote:So, assuming I don't mind the visual output being the same every time the program is executed, I could set my own seed value and still have it run its course.
Yes. If you really don't want any user input, this is your only choice. You can have a pseudo-random number generator and seed it with the same value every time, and you'll get a seemingly random sequence of numbers. They just won't be random at all, because the same sequence will be generated every time the program is run. Some programs even used this to their advantage... If I'm not mistaken, Pitfall for the Atari 2600 used a random number generator to generate the levels, probably because there wasn't space in ROM to store level maps.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Hmmm, since OAM is dynamic RAM (unlike the rest of VRAM, CHR-RAM, and internal RAM), it seems to get more random values at power. Here's a simple routine to make a hash of the values in OAM at power (be sure to call this before you enable PPU rendering):

Code: Select all

; Generates random value from initial contents of OAM
; A <- Random value
; Preserved: Y
random_from_oam:
    ldx #0
:   stx $2003
    eor $2004
    rol a
    inx
    bne :-
    rts
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Once you have the seed, you could try something similar to what some of my games do: clock the seed variable as a linear feedback shift register and then read bits off that.
User avatar
noattack
Posts: 147
Joined: Tue Feb 13, 2007 9:02 pm
Location: Richmond, VA

Post by noattack »

blargg, what is OAM? I can't seem to find an answer in the wiki.
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

noattack wrote:blargg, what is OAM? I can't seem to find an answer in the wiki.
OAM is "Object Attribute Memory" (I think that's what it stands for). It holds all the sprite information for each of the 64 sprites: YCoord, Tile, Attribute, XCoord. To my understanding, this is an area inside the NES that you can access with writes/reads to $2003/$2004. I usually don't deal with those because in standard NES game making practice, you reserve a page of RAM with which you do a DMA transfer. That will take all 256 bytes of that page of RAM (I usually use $300-$3FF) and copy it to OAM.
Post Reply