+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  How do I shift a PPU tile in a game that uses CHR-RAM?
Pages: [1]
Author Topic: How do I shift a PPU tile in a game that uses CHR-RAM?  (Read 1 times)
Rockman
Guest
« on: June 13, 2010, 04:22:22 pm »

Let's say I have a tile in the left PPU table.  Tile $48.  It is a single rain tile.  I want to shift that rain tile downwards, to simulate rain.  How do I do that?

I don't necessarily have to do any copying right, since I'm just shifting the tile downwards?

Otherwise, all I know how to do is this:

; Copy all of tile $48
LDA $04
STA $2006
LDA $80
STA $2006
LDY $10
Again:
LDA ___ ; $FF or $00?  Which one is it?
STA $2007
DEY
BNE Again

Is it $FF or $00?

CHR-RAM is so damn confusing.  Any help would be appreciated.  Thanks.
Dwedit
Guest
« Reply #1 on: June 13, 2010, 04:52:54 pm »

Code that updates tiles needs to run as quickly as possible, otherwise you'll run out of draw time.

So you would store two copies of the rain tile, and redraw it from a different Y origin each frame.  You need two copies because otherwise you'd be reading from out-of-bounds places as you index further into your tile.

Here is some example code for how to update a tile.  For this, I'm using GAMEBOY FORMAT tiles instead of NES format, because it makes handling the second bit plane much easier.  ("Gameboy format" means that you store the second byte of a row immediately after the first byte of a row)

Code:
CopyTile:
\t;X register = scroll position (times 2)
\t;set the PPU address before you call this
\tlda MyTile+0,X
\tsta $2007
\tlda MyTile+2,X
\tsta $2007
\tlda MyTile+4,X
\tsta $2007
\tlda MyTile+8,X
\tsta $2007
\tlda MyTile+10,X
\tsta $2007
\tlda MyTile+12,X
\tsta $2007
\tlda MyTile+14,X
\tsta $2007
\tlda MyTile+1,X
\tsta $2007
\tlda MyTile+3,X
\tsta $2007
\tlda MyTile+5,X
\tsta $2007
\tlda MyTile+7X
\tsta $2007
\tlda MyTile+9,X
\tsta $2007
\tlda MyTile+11,X
\tsta $2007
\tlda MyTile+13,X
\tsta $2007
\tlda MyTile+15,X
\trts

If you don't need a second plane, you can get by with updating only 8 bytes instead of 16, then you won't need to bother with the second bitplane stuff.

That code you posted was an example of how to replace a tile with a blank FF or 00 tile, and wouldn't do anything else.
KingMike
Guest
« Reply #2 on: June 13, 2010, 08:47:52 pm »

Quote from: Rockman on June 13, 2010, 04:22:22 pm
; Copy all of tile $48
LDA $04
STA $2006
LDA $80
STA $2006
LDY $10
Again:
LDA ___ ; $FF or $00?  Which one is it?
STA $2007
DEY
BNE Again

Is it $FF or $00?

CHR-RAM is so damn confusing.  Any help would be appreciated.  Thanks.

Either way, your code would completely overwrite tile $48 with a blank tile (I'm assuming you mean #$04, etc. which means a literal value and not a RAM address). Using #$00 would make it a blank tile of color 0 (the background color), using #$FF would make it a blank tile that is color 3.
Rockman
Guest
« Reply #3 on: June 14, 2010, 03:43:34 pm »

Would my code look something like this?

Code:
; Code to copy and shift a single PPU tile.  In this case, PPU tile $48.

; Turn  screen off
\tLDA $16
\tSTA $2001
\t
; Select PPU tile $48
\tLDA $04
\tSTA $2006
\tLDA $80
\tSTA $2006

; Write to $2007 sixteen times to copy all of tile $48
\tLDY $10
Read:
\tSTA $2007
\tDEY
\tBNE Read

; Increase tile Y position and write pixels
\tLDY $0F
\tLDA $04
\tSTA $2006
\tLDX $81
\tSTX $2006
Write:
\tLDA $04
\tSTA $2006
\tSTX $2006
\tSTA $2007
\tINX
\tDEY
\tBNE Write

; Restore scanlines
\tLDA $20
\tSTA $2006
\tLDA $00
\tSTA $2006

; Turn screen back on
\tLDA $1E
\tSTA $2001

; Return from sub-routine
\tRTS
« Last Edit: June 14, 2010, 03:55:42 pm by Rockman »
tummai
Guest
« Reply #4 on: June 14, 2010, 11:33:22 pm »

Code:
; Code to copy and shift a single PPU tile.  In this case, PPU tile $48.

; Turn  screen off
\tLDA $16
\tSTA $2001
\t
; Select PPU tile $48
\tLDA $04
\tSTA $2006
\tLDA $80
\tSTA $2006

First, you want to put a # before immediate values.  LDA $16 doesn't put the value "$16" into A, it puts the value at the address $0016 into A.  What you want instead is LDA #$16 (same with the 04 and 80). 

Also, a #$16 in $2001 will turn the background off, but sprites will still be drawn.

Code:
; Write to $2007 sixteen times to copy all of tile $48
\tLDY $10
Read:
\tSTA $2007
\tDEY
\tBNE Read

This code doesn't read anything.  You are writing to the pattern table 16 times, overwriting the tile at $46.  Assuming you fix the # issue above, you'd be writing the value #$80 sixteen times, which would give you a tile with a vertical line on the left.

Code:
; Increase tile Y position and write pixels
\tLDY $0F
\tLDA $04
\tSTA $2006
\tLDX $81
\tSTX $2006
Write:
\tLDA $04
\tSTA $2006
\tSTX $2006
\tSTA $2007
\tINX
\tDEY
\tBNE Write

Same issue here with the # for immediate values.   In the write loop, again you are writing a single value over and over into the tile space (in this case 04, assuming you fix the # issue).  Also, the target PPU address increments automatically, so you don't need to set the address via $2006 each iteration of the loop.
Rockman
Guest
« Reply #5 on: June 14, 2010, 11:36:50 pm »

I'm sorry if I confused you about the "#" thing.  I already know about that.  It's just that I wasn't sure if it displayed the "#" in the FCEUXD Debugger, that's why I didn't put it.  But I should have clarified it better.

Here is a re-write of the code above, with the correct syntax:

Code:
; Code to copy and shift a single PPU tile.  In this case, PPU tile $48.

; Turn  screen off
\tLDA #$16
\tSTA $2001
\t
; Select PPU tile $48
\tLDA #$04
\tSTA $2006
\tLDA #$80
\tSTA $2006

; Write to $2007 sixteen times to copy all of tile $48
\tLDY #$10
Read:
\tSTA $2007
\tDEY
\tBNE Read

; Increase tile Y position and write pixels
\tLDY #$0F
\tLDA #$04
\tSTA $2006
\tLDX #$81
\tSTX $2006
Write:
\tLDA #$04
\tSTA $2006
\tSTX $2006
\tSTA $2007
\tINX
\tDEY
\tBNE Write

; Restore scanlines
\tLDA #$20
\tSTA $2006
\tLDA #$00
\tSTA $2006

; Turn screen back on
\tLDA #$1E
\tSTA $2001

; Return from sub-routine
\tRTS
« Last Edit: June 14, 2010, 11:43:26 pm by Rockman »
tummai
Guest
« Reply #6 on: June 14, 2010, 11:57:13 pm »

Well, my other comments still apply here.  The read loop doesn't read anything, rather it overwrites the tile at $0480.  The write loop does write, but it's not writing a copy of the tile - it's just writing the value #$04 to over and over again.

What you want to do is have a copy of the new tile to draw in RAM somewhere, and then do a copy loop.

Code:
   lda #$04
   sta $2006
   lda #$80
   sta $2006
   ldx #$00
loop:
   lda tile, x      ;"tile" is some location in RAM containing the tile.
   sta $2007
   inx
   cpx #$10
   bne loop

You'll also need a separate subroutine that constructs the tile to draw and stores it in RAM.
Pages: [1]  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC