LDA $2002 ; read PPU status to reset the high/low latch to high
LDA #$3F
STA $2006 ; write the high byte of $3F10 address
LDA #$10
STA $2006 ; write the low byte of $3F10 address
LDA #$32 ;code for light blueishYou would continue to do writes to fill out the rest of the palette. Fortunately there is a smaller way to write all that code. First you can use the .db directive to store data bytes:
STA $2007 ;write to PPU $3F10
LDA #$14 ;code for pinkish
STA $2007 ;write to PPU $3F11
LDA #$2A ;code for greenish
STA $2007 ;write to PPU $3F12
LDA #$16 ;code for redish
STA $2007 ;write to PPU $3F13
PaletteData:Then a loop is used to copy those bytes to the palette in the PPU. The X register is used as an index into the palette, and used to count how many times the loop has repeated. You want to copy both palettes at once which is 32 bytes, so the loop starts at 0 and counts up to 32.
.db $0F,$31,$32,$33,$0F,$35,$36,$37,$0F,$39,$3A,$3B,$0F,$3D,$3E,$0F ;background palette data
.db $0F,$1C,$15,$14,$0F,$02,$38,$3C,$0F,$1C,$15,$14,$0F,$02,$38,$3C ;sprite palette data
LDX #$00 ; start out at 0
LoadPalettesLoop:
LDA PaletteData, x ; load data from address (PaletteData + the value in x)
; 1st time through loop it will load PaletteData+0
; 2nd time through loop it will load PaletteData+1
; 3rd time through loop it will load PaletteData+2
; etc
STA $2007 ; write to PPU
INX ; X = X + 1
CPX #$20 ; Compare X to hex $20, decimal 32
BNE LoadPalettesLoop ; Branch to LoadPalettesLoop if compare was Not Equal to zero
; if compare was equal to 32, keep going down
LDA #$00Once the second write is done the DMA transfer will start automatically. All data for the 64 sprites will be copied. Like all graphics updates, this needs to be done at the beginning of the VBlank period, so it will go in the NMI section of your code.
STA $2003 ; set the low byte (00) of the RAM address
LDA #$02
STA $4014 ; set the high byte (02) of the RAM address, start the transfer
765432104 - X Position - horizontal position on the screen. $00 is the left side, anything above $F9 is off screen.
||| ||
||| ++- Color Palette of sprite. Choose which set of 4 from the 16 colors to use
|||
||+------ Priority (0: in front of background; 1: behind background)
|+------- Flip sprite horizontally
+-------- Flip sprite vertically
PPUCTRL ($2000)And the new code to set up the sprite data:
76543210
| ||||||
| ||||++- Base nametable address
| |||| (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
| |||+--- VRAM address increment per CPU read/write of PPUDATA
| ||| (0: increment by 1, going across; 1: increment by 32, going down)
| ||+---- Sprite pattern table address for 8x8 sprites (0: $0000; 1: $1000)
| |+----- Background pattern table address (0: $0000; 1: $1000)
| +------ Sprite size (0: 8x8; 1: 8x16)
|
+-------- Generate an NMI at the start of the
vertical blanking interval vblank (0: off; 1: on)
LDA #$80
STA $0200 ;put sprite 0 in center ($80) of screen vertically
STA $0203 ;put sprite 0 in center ($80) of screen horizontally
LDA #$00
STA $0201 ;tile number = 0
STA $0202 ;color palette = 0, no flipping
LDA #%10000000 ; enable NMI, sprites from Pattern Table 0
STA $2000
LDA #%00010000 ; no intensify (black background), enable sprites
STA $2001
gauauu: look, we all paid $10K at some point in our lives for the privilege of hanging out with Kevin
LDA #$80
STA $0200 ; put sprite 0 in center ($80) of screen vert
STA $0203 ; put sprite 0 in center ($80) of screen horiz
LDA #$00
STA $0201 ; tile number = 0
STA $0202 ; color = 0, no flipping
LDA #$80
STA $0204
LDA #$88
STA $0207
LDA #$01
STA $0205
LDA #$00
STA $0206
LDA #$88
STA $0208
LDA #$80
STA $020B
LDA #$02
STA $0209
LDA #$00
STA $020A
LDA #$88
STA $020C
LDA #$88
STA $020F
LDA #$03
STA $020D
LDA #$00
STA $020E
LDA #$90
STA $0210
LDA #$80
STA $0213
LDA #$04
STA $0211
LDA #$00
STA $0212
LDA #$90
STA $0214
LDA #$88
STA $0217
LDA #$05
STA $0215
LDA #$00
STA $0216
LDA #$98
STA $0218
LDA #$80
STA $021B
LDA #$06
STA $0219
LDA #$00
STA $021A
LDA #$98
STA $021C
LDA #$88
STA $021F
LDA #$07
STA $021D
LDA #$00
STA $021E
LDA #%10000000 ; enable NMI, sprites from Pattern Table 0
STA $2000
LDA #%00010000 ; enable sprites
STA $2001
LDA #$80
STA $0200 ; put sprite 0 in center ($80) of screen vert
STA $0203 ; put sprite 0 in center ($80) of screen horiz
LDA #$00
STA $0201 ; tile number = 0
STA $0202 ; color = 0, no flipping
LDA #$80
STA $0204
LDA #$88
STA $0207
LDA #$01
STA $0205
LDA #$00
STA $0206
LDA #$88
STA $0208
LDA #$80
STA $020B
LDA #$02
STA $0209
LDA #$00
STA $020A
LDA #$88
STA $020C
LDA #$88
STA $020F
LDA #$03
STA $020D
LDA #$00
STA $020E
LDA #$90
STA $0210
LDA #$80
STA $0213
LDA #$04
STA $0211
LDA #$00
STA $0212
LDA #$90
STA $0214
LDA #$88
STA $0217
LDA #$05
STA $0215
LDA #$00
STA $0216
LDA #$98
STA $0218
LDA #$80
STA $021B
LDA #$06
STA $0219
LDA #$00
STA $021A
LDA #$98
STA $021C
LDA #$88
STA $021F
LDA #$07
STA $021D
LDA #$00
STA $021E
LDA #%10000000 ; enable NMI, sprites from Pattern Table 0
STA $2000
LDA #%00010000 ; enable sprites
STA $2001
That's a lot of hard coding right there. I'd do something like this:
data:
.db $80,$00,$00,$80,$80,$01,$00,$88, etc.
load_sprite_data:
LDX #$00
.loop:
LDA data,x
STA $0200,x
INX
CPX #$??
BNE .loop
RTS
Cleaner and easier to read.
gauauu: look, we all paid $10K at some point in our lives for the privilege of hanging out with Kevin
LDA #$00
STA $2003 ; set the low byte (00) of the RAM address
LDA #$02
STA $4014 ; set the high byte (02) of the RAM address, start the transfer
That piece of code tells the PPU's internal sprite RAM to point to the first sprite RAM spot (#$00) to start uploading sprites. $02 tells it to put the sprites from $200-$2FF inside the NES to that memory. (Called sprite DMA. Uploads faster then a LDA STA loop which is why we use the special pointer. Can also point to $300, $400, and so on. Uploading bytes $X00-$XFF to the sprite RAM, but $200 is used consistently for sprite data, so that's why it's used. Pretty much a "standard" spot.)
So locations $200-$2FF of the RAM inside the NES holds 64 sprites. 256/64=4, so every 4 bytes is a new sprite. The 4 bytes used for the sprite data are called the attributes.
Byte $200 (1st sprite, 1st attribute)
Y position on screen. Moves the sprite up/down. 0=top, Higher number, more down is goes.
Byte $201 (1st sprite, 2nd attribute)
Tile number. whatever bank is switched on, the tile number from that bank will be put on the screen. In most programs, the 2nd 4K "page" of CHR-ROM are the sprites.
Byte $202 (1st sprite, 3rd attribute)
Other misc. attributes. Each bit does this function in this byte:
76543210
||| ||
||| ++- Color Palette of sprite. Choose which set of 4 from the 16 colors to use
|||
||+------ Priority (0: in front of background; 1: behind background)
|+------- Flip sprite horizontally
+-------- Flip sprite verticallyByte $203 (1st sprite, 4th attribute)X position on the screen. Moves player character left/right. 0=far left. Higher the number, more right it goes.Bytes $204-$207, $208-$20B, $20C-$20F, $210-$213 of Sprite RAM are different sprites, but each follows the same attributes. For unused sprites, just write #$FF to the Y locaion and they will be put off the screen. If you write #$FF to the X, It may cause sprite overflow on some scanlines and cause sprites not to show up. (There can only be 8 sprites per scanline. Any sprite after the first 8 will be left out. The ones that come first in RAM will be shown on top/in priority to other sprites if there's overflow/overlap.)
Hope this helps you understand, I simplified it a lot for the sake of making it easier to understand, but if you get this, understanding the technicalities behind it isn't so hard. Any questions, just PM me.
gauauu: look, we all paid $10K at some point in our lives for the privilege of hanging out with Kevin