Updating a 'random' nametable / pattern tile
Moderator: Moderators
Updating a 'random' nametable / pattern tile
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.
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:
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:
EDIT:
Yes. Though if you want to do attributes, the other 64 bytes of the name table would be used.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?
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.
I'm stumped. I'm trying to avoid any user interaction, so using the controller is out for a seed value.
Exactly. How would you get a random interval without user interaction?noattack wrote:Although then I suppose the interval would need to be random.
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.I'm trying to avoid any user interaction, so using the controller is out for a seed value.
-
Celius
- Posts: 2159
- Joined: Sun Jun 05, 2005 2:04 pm
- Location: Minneapolis, Minnesota, United States
- Contact:
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.
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.
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:
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
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
rts90 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
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.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.
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 :-
rtsOnce 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.
-
Celius
- Posts: 2159
- Joined: Sun Jun 05, 2005 2:04 pm
- Location: Minneapolis, Minnesota, United States
- Contact:
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.noattack wrote:blargg, what is OAM? I can't seem to find an answer in the wiki.