I've been developing for SNES and I want to have levels that are two screens tall, except to save video RAM for tiles instead, I'm using 64x32 tilemaps, but I'm running into problems with some occasional wrong tiles on the top half of the level, corresponding to the right tiles for the bottom half in the same position. I think aside from that it works.
Since this is my first time doing diagonal scrolling it's hard to tell if my implementation is wrong, or if the logic I'm trying to implement in the first place is wrong (so any implementation of that logic would be flawed) so I figured getting more eyes on my code would help.
I have a ColumnUpdateBuffer that gets DMA'd to ColumnUpdateAddress vertically, a full 32 tiles tall. I also have a RowUpdateBuffer that similarly gets DMA'd to RowUpdateAddress horizontally and it's always 64 tiles wide for simplicity, and I only write to the portion of it that will be visible. My level buffer is in LevelBuf and it is 256 wide * 32 tall * 2 bytes per metatile, arranged in a series of columns from left to right.
When the scrolling has changed: (simplified)
If the X scroll value passes a tile boundary:
If the Y scroll value passes a tile boundary:
Or probably a lot more clearly, the code itself:
scrolling.s
renderlevel.s
Since this is my first time doing diagonal scrolling it's hard to tell if my implementation is wrong, or if the logic I'm trying to implement in the first place is wrong (so any implementation of that logic would be flawed) so I figured getting more eyes on my code would help.
I have a ColumnUpdateBuffer that gets DMA'd to ColumnUpdateAddress vertically, a full 32 tiles tall. I also have a RowUpdateBuffer that similarly gets DMA'd to RowUpdateAddress horizontally and it's always 64 tiles wide for simplicity, and I only write to the portion of it that will be visible. My level buffer is in LevelBuf and it is 256 wide * 32 tall * 2 bytes per metatile, arranged in a series of columns from left to right.
When the scrolling has changed: (simplified)
If the X scroll value passes a tile boundary:
- If scrolling left, select a column 2 tiles left from the new scroll position
- If scrolling right, select a column 34 tiles right from the new scroll position
- (Selected column number will be called SelectedColumn)
- Set ColumnUpdateAddress to tilemap base address + SelectedColumn AND 31, use second screen if needed
- Prepare a pointer to start reading from level data (Level column is SelectedColumn / 2)
- -----
- Y = Y scroll position counted in metatiles
- X = Y, restricted to fit ColumnUpdateBuffer
- ColumnUpdateBuffer[X++] = Tile numbers[Level pointer[Y++]]
- Repeat the previous step 15 more times, wrapping X around in the buffer.
If the Y scroll value passes a tile boundary:
- If scrolling up, select a row 1 tiles up from the new scroll position
- If scrolling down, select a row 29 tiles down from the new scroll position
- (Selected row number will be called SelectedRow)
- Set RowUpdateAddress to tilemap base address + SelectedRow * 32
- Prepare a pointer to start reading from level data (Level column is X scroll position in metatiles, minus 1)
- -----
- Y = SelectedRow / 2
- X = X scroll position in metatiles * 2, minus 1, constrained to the buffer size
- RowUpdateBuffer[X++] = Tile numbers[Level pointer[Y]]
- Move Level pointer ahead one column
- Repeat previous two steps 20 times (probably more than needed. I was trying to make it slightly wider than the screen, hence starting a bit to the left of it)
Or probably a lot more clearly, the code itself:
scrolling.s
renderlevel.s