Scrolling RPG maps

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

User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Scrolling RPG maps

Post by zanto »

I'm working on a RPG on the NES. My next step is to have the player walk on the map and have the camera follow him around (just like in the Dragon Warrior games). The game uses vertical mirroring, btw.

My first goal is to make a character to walk around on a 255x240 map, the scroll will loop around the map, but that's fine for now.
Below is my code, it's incomplete and doesn't fully work. It works well when you move around and scrollx doesn't go below 0 or higher than 255 and when scrolly goes below 0 or higher than 240.
I've been stuck on this for the entire day almost and I tried looking for help online, but I had trouble understanding what exactly I had to do. Can anyone help me with this?

Code: Select all

; update scrollx
lda scrollx
sta aux1
lda playerx
sec
sbc #SCROLLX_OFFSET
sta scrollx
	
	; TODO: change nametable if needed
	
	
; update scrolly
lda scrolly
sta aux1
lda playery
sec
sbc #SCROLLY_OFFSET
	
cmp #$F0	; if new scrolly < 240, we're okay. If new scroll >= 240, we have to loop back
bcc	:+
sec
sbc #$F0
:
sta scrolly
Working on map infrastructure (scrolling, loading big maps and their attr tables, compression etc) is one of the things I was afraid the most when I started this project, I hope I can make it :P
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Scrolling RPG maps

Post by calima »

Try visualizing it with paper.

Cut out two pieces, one square for your camera, and a 2x1 squares piece for your nametables A & B. Move the camera paper over the nametable paper in different positions, see how it goes over which parts.
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: Scrolling RPG maps

Post by zanto »

calima wrote: Sun Mar 28, 2021 11:26 pm Try visualizing it with paper.

Cut out two pieces, one square for your camera, and a 2x1 squares piece for your nametables A & B. Move the camera paper over the nametable paper in different positions, see how it goes over which parts.
I know how it works in theory, I've read tutorials and used the PPU viewer in Mesen to look at scrolling in Dragon Warrior 4. But I'm having trouble translating that into code...
My problem with scrolling in the X axis is making the transition between nametables at $2000 and $2400. Right now there's no transition, so scrolling is wrapping around $2000. I could think of a way but that would involve a bunch of conditions and auxiliary variables, which I want to avoid. There HAS to be a simpler way.
And my problem with scrolling in the Y axis is that once the character crosses a y value over 240, the camera gets misplaced. I'm guessing it's because the player y value isn't restricted to work between 0-240, like the camera is, but I'm not sure. And I haven't figured out how to deal with that.

I don't know if this is useful to help me, but here's the code that I use to calculate where the player sprite is supposed to be drawn on screen. This is executed before loading its sprite into OAM.

Code: Select all

lda playerx
sec
sbc scrollx
sta arg2    ; this is the sprite's x position on screen, to be used by the LOAD_16_16_SPRITE routine
lda playery
sec
sbc scrolly
sta arg3    ; this is the sprite's y position on screen, to be used by the LOAD_16_16_SPRITE routine
	
lda #<(SPR_PlayerSprite)	; storing sprite data for player entity
sta currentsprite
lda #>(SPR_PlayerSprite)
sta currentsprite+1
jsr LOAD_16_16_SPRITE
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scrolling RPG maps

Post by tokumaru »

zanto wrote: Sun Mar 28, 2021 11:51 pmThere HAS to be a simpler way.
The simpler way is to treat the scroll values as 9-bit numbers: the lower 8 bits go to $2005, while the 9th bit is used to select a name table via $2000. Extend your scroll/camera variables to 16 bits and things will get a lot easier. Since you're using scrolling, this means your worlds are bigger than 256 pixels in at least one axis, so you need more than 8 bits to keep track of the positions of things.
And my problem with scrolling in the Y axis is that once the character crosses a y value over 240, the camera gets misplaced. I'm guessing it's because the player y value isn't restricted to work between 0-240, like the camera is, but I'm not sure. And I haven't figured out how to deal with that.
The simplest solution is to have two sets of vertical coordinates, one in level map space (wraps around at 256) and one in name table space (wraps around at 240). Have a 16-bit variable act as the vertical coordinate of the camera in level space, and just let it wrap around at 256 without any special handling, but keep a secondary 9-bit "NTCameraY" variable (or whatever you wanna call it) that updates in sync with the main coordinate (whenever you change the main CameraY, change NTCameraY by the same amount), and wraps around at 240 - you have to manually test it after each update to see if the lower 8 bits have gone over 239 (in which case you add 16 to fix it and flip the 9th bit) or below 0 (in which case you subtract 16 to fix it). Use that secondary variable to get the vertical parts of the values you write to $2005 and $2000 when setting the scroll.
KayBur
Posts: 12
Joined: Mon Mar 29, 2021 6:47 am

Re: Scrolling RPG maps

Post by KayBur »

I'm not a big expert in programming, but in many popular games, in addition to the kernel written in C ++ or Python, a SQL-database is screwed in which all actions, conditions, etc. are written.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Scrolling RPG maps

Post by Quietust »

KayBur wrote: Mon Mar 29, 2021 7:22 am I'm not a big expert in programming, but in many popular games, in addition to the kernel written in C ++ or Python, a SQL-database is screwed in which all actions, conditions, etc. are written.
Maybe in a modern game written for a modern computer or gaming console, but I can't imagine that a SQL database would have any place in an NES game where you've only got a 1.79MHz 6502 CPU with 2 kilobytes of RAM (or, 10 kilobytes, if you're using a cartridge with extra RAM).

Similarly, no NES game is going to use C++ (even plain C has enough overhead), and the idea of using a Python interpreter is laughable at best.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: Scrolling RPG maps

Post by zanto »

KayBur wrote: Mon Mar 29, 2021 7:22 am I'm not a big expert in programming, but in many popular games, in addition to the kernel written in C ++ or Python, a SQL-database is screwed in which all actions, conditions, etc. are written.
Unfortunately, I'm working with ASM, so none of that is available. Also, the NES doesn't have a lot of infrastructure to help you when it comes to graphics, other than what the PPU offers, so everything needs to be done by the programmer.
tokumaru wrote: Mon Mar 29, 2021 3:03 am The simpler way is to treat the scroll values as 9-bit numbers: the lower 8 bits go to $2005, while the 9th bit is used to select a name table via $2000. Extend your scroll/camera variables to 16 bits and things will get a lot easier. Since you're using scrolling, this means your worlds are bigger than 256 pixels in at least one axis, so you need more than 8 bits to keep track of the positions of things.
Yeah, my maps will be bigger than 256 both in X and Y axis. When you say "select the table using the 9th bit via $2000, are you referring to what this part of the wiki on PPU scrolling?
Ordinarily, a program writes to two PPU registers to set the scroll position in its NMI handler:

Find the X and Y coordinates of the upper left corner of the visible area (the part seen by the "camera")
Write the X coordinate to PPUSCROLL ($2005)
Write the Y coordinate to PPUSCROLL
Write the starting page (high order bit of X and Y) to bits 0 and 1 of PPUCTRL ($2000)
I wasn't sure what that meant, so I experimented with it by doing something like

Code: Select all

bit PPUSTATUS
lda scrollx
sta PPUSCROLL
lda scrolly
sta PPUSCROLL
lda PPUCTRL
ora #%00000001
sta PPUCTRL
And my screen got all glitched up. I also tried to store #$01 to PPUCTRL, but I also got a glitched screen.
tokumaru wrote: Mon Mar 29, 2021 3:03 am
And my problem with scrolling in the Y axis is that once the character crosses a y value over 240, the camera gets misplaced. I'm guessing it's because the player y value isn't restricted to work between 0-240, like the camera is, but I'm not sure. And I haven't figured out how to deal with that.
The simplest solution is to have two sets of vertical coordinates, one in level map space (wraps around at 256) and one in name table space (wraps around at 240). Have a 16-bit variable act as the vertical coordinate of the camera in level space, and just let it wrap around at 256 without any special handling, but keep a secondary 9-bit "NTCameraY" variable (or whatever you wanna call it) that updates in sync with the main coordinate (whenever you change the main CameraY, change NTCameraY by the same amount), and wraps around at 240 - you have to manually test it after each update to see if the lower 8 bits have gone over 239 (in which case you add 16 to fix it and flip the 9th bit) or below 0 (in which case you subtract 16 to fix it). Use that secondary variable to get the vertical parts of the values you write to $2005 and $2000 when setting the scroll.
I think I understand some of this idea, but I still get a little confused about the whole "below 0" thing, because it just overflows to FF. I understand bit 7 tells if the number is negative or not, but I don't know exactly how to tell the processor that "in this case FF is a number below 0" or "in this case FF is a number above 0 (i.e. we got FF by incrementing it from 00, 01, 02.... FE, FF). Is there any code examples that can help me understand and process this efficiently?

Also to make sure I understand: are CameraX,CameraY used to get the tiles from memory that will be loaded into the nametable and NTCameraX,NTCameraY used for the scroll? And if so, isn't it basically what I'm doing with the scrolly variable (which would be analogue to the NTCameraY) in this case? It doesn't use 9 bits, but does it need to, considering that since I'm using vertical mirroring, I can't switch to the nametable below the one I'm using? I feel like I'm mixing up a bunch of concepts together in the wrong way... :cry:
Last edited by zanto on Mon Mar 29, 2021 12:01 pm, edited 1 time in total.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scrolling RPG maps

Post by tokumaru »

zanto wrote: Mon Mar 29, 2021 10:02 amYeah, my maps will be bigger than 256 both in X and Y axis.
This means that you can't represent positions in those maps with 8-bit coordinates, you need to expand them to 16-bit. Even the NES' virtual background area is too big for 8-bit coordinates (the 4 name tables create a 512x40-pixel background), so if you're doing any scrolling at all, you'll need at least 9 bits.
When you say "select the table using the 9th bit via $2000, are you referring to what this part of the wiki on PPU scrolling?
Ordinarily, a program writes to two PPU registers to set the scroll position in its NMI handler:

Find the X and Y coordinates of the upper left corner of the visible area (the part seen by the "camera")
Write the X coordinate to PPUSCROLL ($2005)
Write the Y coordinate to PPUSCROLL
Write the starting page (high order bit of X and Y) to bits 0 and 1 of PPUCTRL ($2000)
Yeah, PPUSCROLL ($2005) is what you use to set the lower 8 bits of each coordinate of the scroll position, but since the complete scroll area is 512x480, each coordinate has a 9th bit that can be set via PPUCTRL ($2000), and these bits combined effectively select one of the 4 name tables in that 512x480-pixel space.

Code: Select all

lda PPUCTRL
ora #%00000001
sta PPUCTRL
You can't read PPUCTRL, it's a write-only register. You have to keep track of the 9th scroll bit in a variable in RAM, like you do with the lower 8 bits (scrollx), and write that bit to PPUCTRL each frame. Something like this:

Code: Select all

lda scrollx+0
sta PPUSCROLL
lda scrolly+0
sta PPUSCROLL
lda scrollx+1
lsr ;shift 9th bit of scrollx into the carry flag
lda scrolly+1
rol ;put it alongside the 9th bit of scrolly
and #%00000011 ;clear irrelevant bits
ora ppuctrl_mirror ;combine with the other PPUCTRL settings
sta PPUCTRL
I think I understand some of this idea, but I still get a little confused about the whole "below 0" thing, because it just overflows to FF.
Yes, and when that happens as the consequence of an ADC or SBC, the carry will be clear, indicating the wrap around. Check the carry, and fix as needed:

Code: Select all

  sec
  lda scrolly+0
  sbc #$04 ;move the camera 4 pixels up
  bcs done ;carry is still set, no need to fix anything
  sbc #$0f ;subtract 16 more pixels (since the carry is clear, sbc #$0f actually subtracts 16)
  dec scrolly+1 ;update the upper bits
done:
  sta scrolly+0
I understand bit 7 tells if the number is negative or not
Not always... scroll values are never negative, so that won't help you here.
but I don't know exactly how to tell the processor that "in this case FF is a number below 0" or "in this case FF is a number above 0 (i.e. we got FF by incrementing it from 00, 01, 02.... FE, FF). Is there any code examples that can help me understand and process this efficiently?
Use the carry flag, like I mentioned abobe.
Also to make sure I understand: are CameraX,CameraY used to get the tiles from memory that will be loaded into the nametable and NTCameraX,NTCameraY used for the scroll?
Since NTCameraX would wrap around normally at 256, you don't really need a special version of that, you can just use CameraX for accessing the level map AND for the scroll an calculation of NT/AT addresses. But for the vertical part, yeah, you'd use one variable that wraps normally at 256 for dealing with everything that happens in level map space (like reading the tiles from the level map and even calculating the positions of sprites on the screen doing ObjectY - CameraY), and another variable that wraps around at 240 (don't forget to adjust the upper byte as well!) that you can use for setting the scroll and calculating the VRAM addresses of where to write tiles and attributes.
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: Scrolling RPG maps

Post by zanto »

tokumaru wrote: Mon Mar 29, 2021 11:57 am You have to keep track of the 9th scroll bit in a variable in RAM, like you do with the lower 8 bits (scrollx), and write that bit to PPUCTRL each frame. Something like this:

Code: Select all

lda scrollx+0
sta PPUSCROLL
lda scrolly+0
sta PPUSCROLL
lda scrollx+1
lsr ;shift 9th bit of scrollx into the carry flag
lda scrolly+1
rol ;put it alongside the 9th bit of scrolly
and #%00000011 ;clear irrelevant bits
ora ppuctrl_mirror ;combine with the other PPUCTRL settings
sta PPUCTRL
I think the reason I was confused about the whole carry flag thing on the scroll is because I'm not incrementing or decrementing the scroll variables like I do with the player position. I recalculate them based on the player's position.

Code: Select all

LDA scrollx
STA aux1
LDA playerx
SEC
SBC #SCROLLX_OFFSET
STA scrollx
		
LDA scrolly
STA aux1
LDA playery
SEC
SBC #SCROLLY_OFFSET
	
CMP #$F0	; if scrolly < 240, we're okay. If scroll >= 240, we have to loop back
BCC	:+
SEC
SBC #$F0
:
STA scrolly
I did this because I thought it'd make the code cleaner, but I guess I'll have to change this approach if I follow your suggestion. I'll do it and post here the results. Thanks!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scrolling RPG maps

Post by tokumaru »

zanto wrote: Mon Mar 29, 2021 12:34 pmI think the reason I was confused about the whole carry flag thing on the scroll is because I'm not incrementing or decrementing the scroll variables like I do with the player position. I recalculate them based on the player's position.
That's fine. Having a "smart" camera can feel more pleasant than having the player stuck at a the same screen position all the time, but regardless of whether the camera has its own movement or it simply snaps to the player's position, you can always detect how much something moved by comparing its new position against the old one.

Like I said, no special handling is needed for the X coordinate, but if you're setting CameraY based on the player's position, you can simply save the old value of CameraY and compare the new one against it to see how much it changed, and then apply the same difference to NTCameraY. Something like this:

Code: Select all

sec
lda CameraY+0
sbc OldCameraY+0
sta DisplacementY
As long as the camera didn't move more than 127 pixels down or 128 pixels up (a very reasonable assumption!), DisplacementY will contain a signed value indicating how much the camera moved. Since this is a small value, you don't even need to compare the high bytes, so you don't even need to save the high byte of OldCameraY for this. Anyway, now you can simply add this to NTCameraY and fix it if it lands in the "forbidden zone":

Code: Select all

  clc
  lda NTCameraY+0
  adc DisplacementY ;add the signed displacement
  cmp #$f0 ;is the result between 240 and 255?
  bcc Done ;if not, we're done
  bit DisplacementY ;test the sign of the displacement
  bpl MovedDown
MovedUp: ;displacement is negative, we must wrap from 0 to 239
  sbc #$10 ;subtract 16 extra units
  dec NTCameraY+1 ;update the high byte
  jmp Done ;now we're done
MovedDown: ;displacement is positive, we must wrap from 239 to 0
  adc #$0f ;add 16 extra units (carry is set, so adc #$0f will add 16)
  inc NTCameraY+1 ;update the high byte
Done:
  sta NTCameraY+0
This works for displacements of -16 to 16 pixels, because we're detecting overflows/underflows when NTCameraY falls into the 240-255 range instead of using the carry flag from adding the displacement. But this is fine, since not even the Sonic games on the Genesis scroll faster than 16 pixels per frame!

BTW, calculating the direction of the camera displacement is a useful thing to do on the X axis as well, because in order to calculate the positions of the rows/columns of tiles that need to be updated, you need to know the direction of the camera's movement.
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: Scrolling RPG maps

Post by zanto »

I think I got it to work now! I ended up just changing the camera in the same routine that moves the player, like you suggested previously. Thank you very much! :D

My next step is to actually load bigger maps into the game now (like the world maps in Dragon Warrior games), and load the tiles and attributes on screen as the player moves around. Is there a code in ASM that I can use as an example? I could try it on my own, but I'm afraid whatever I'll come up won't be very efficient, specially when it comes to calculating the attribute tables that have to be loaded on screen.

Here's what Dragon Warrior 4 does. For horizontal scrolling, when you enter a new map, it loads the tiles on the screen properly, but it also loads 2 column of tiles to the left and to the right of what's inside the screen. As the player moves, the game loads more tiles to the left or the right of the screen depending on which direction the player is moving. It also starts the scroll in the middle of the first 2 nametables. I didn't know you could write outside the screen like this. I thought you could only send 960 bytes to the PPUDATA variable to populate the background graphics on the PPU, which are all the tiles on screen.
img4.png
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Scrolling RPG maps

Post by tokumaru »

zanto wrote: Mon Mar 29, 2021 2:12 pmI'm afraid whatever I'll come up won't be very efficient, specially when it comes to calculating the attribute tables that have to be loaded on screen.
I wouldn't worry too much about efficiency at this point. You'll benefit much more in the long run from thinking about the problems and finding solutions on your own than from just implementing whatever other people tell you to.

That being said, attribute tables can indeed be a pain to work with, specially when vertical scrolling is involved. You can try to alleviate the problem by working with 32x32-pixel blocks in your level maps, so that the attribute bytes are all pre-calculated, but you'll still have to swap nybles every other vertical screen due to each screen being 7 1/2 blocks tall.
Here's what Dragon Warrior 4 does. For horizontal scrolling, when you enter a new map, it loads the tiles on the screen properly, but it also loads 2 column of tiles to the left and to the right of what's inside the screen. As the player moves, the game loads more tiles to the left or the right of the screen depending on which direction the player is moving. But these tiles loaded are always outside the screen.
That's the general idea behind scrolling on the NES. How much is drawn in advance varies from game to game, but the general idea is mostly the same.

You can watch specific bits in the camera/scroll coordinates in order to tell when the camera moved enough to require a new column/row of blocks to be drawn. For example, if you want to draw new tiles every 16 scrolled pixels, compare bit 4 of the coordinates before and after the movement - if that bit is different, this means that a 16-pixel boundary was crossed:

Code: Select all

lda OldCameraX+0
eor CameraX+0 ;EOR results in 1 only when the 2 input bits are different
and #%00010000 ;keep only the bit that matters
beq NoColumnUpdate
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Scrolling RPG maps

Post by Quietust »

zanto wrote: Mon Mar 29, 2021 2:12 pm I thought you could only send 960 bytes to the PPUDATA variable to populate the background graphics on the PPU, which are all the tiles on screen.
While it's true that a single nametable (which consists of 960 bytes of tile data and 64 bytes of attribute data) will fill the screen, the PPU has 2 nametables worth of RAM connected to it, and how you use it is totally up to you.

The upper address line of that RAM chip goes through the cartridge edge, so you can hook it up so that the first nametable appears at $2000 and $2800 while the second nametable shows up at $2400 and $2C00. Most emulators call this "vertical mirroring", but Nintendo called it "horizontal arrangement" because it's ideal for horizontal scrolling. In this setup, as you increase the horizontal scroll register you'll see less of the right side of nametable A and more of the left side of nametable B, so you can draw new tiles to the "offscreen" portions and then scroll them in without any glitches; if you do vertical scrolling in this setup, then any updates to the very bottom of the screen will also briefly appear at the very top of the screen (or vice-versa).

Alternatively, you could hook it up so the first nametable appears at $2000 and $2400 and the second nametable shows up at $2800 and $2C00, which most emulators call "horizontal mirroring" and Nintend called "vertical arrangement" because it's ideal for vertical scrolling.

If you're not using scrolling at all, then you could use one nametable to represent the "current" video output and the other nametable as a buffer, allowing you to slowly draw a new scene to the second nametable while still displaying the first one, and when you're done you can seamlessly flip between them.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
zanto
Posts: 57
Joined: Sun Mar 07, 2021 11:15 pm
Location: Rio de Janeiro, Brazil

Re: Scrolling RPG maps

Post by zanto »

First, a quick question: I noticed in some examples have instructions like "lda CameraY+0". Is that the same as "lda CameraY"? If not, what's the difference?

Ok, now to the main point of this post: I got to the point where I have to load big maps to the game, but I'm stumped. Up until now, I only had one 256x240 screen, so my approach was a simple loop that stored all 960 bytes into the PPU.
In my RPG, maps can have an arbitrary width and height (all I've stablished is that width must be multiple of 256 and height must be multiple of 240). So, the world map can be a very big map, while a town would be considerably smaller. The world map in Dragon Warrior 4, for example is 4096x3840 pixels. I don't know if mine will be as big, but it'll be pretty big too.
I'm feeling overwhelmed now, because I have no idea how to find the tiles I need to show on screen. It'd be so much easier if ASM could work with 2D arrays, but alas :P Not only that, but I know a next step will be to implement a RLE compression on map data, so I'm afraid if I to work on a solution that doesn't consider it, I'll have to scrap it and think of something else because of the compression.

I've even considered rethinking how I'm storing map tile bytes. So far, I have stored as shown below. each number represents a byte in a 256x240 area. So, all 1's are byte that for the top left area (the top left 256x240 area). The 2's represent the bytes to the right of the area 1. Also, just because they are all 1's, it doesn't mean the bytes are the same, just that the bytes are from one area. So, for a map that is 4 screens width and 2 tall (1024 x 480 tiles), we have the following:

Code: Select all

11111111222222223333333344444444
11111111222222223333333344444444
11111111222222223333333344444444
11111111222222223333333344444444
11111111222222223333333344444444
11111111222222223333333344444444
55555555666666667777777788888888
55555555666666667777777788888888
55555555666666667777777788888888
55555555666666667777777788888888
55555555666666667777777788888888
55555555666666667777777788888888
I've even considered bundling all the bytes from each area together, but I think that'll make things more complicated.

Code: Select all

111111111111111111111111111111111111111111111111
222222222222222222222222222222222222222222222222
333333333333333333333333333333333333333333333333
444444444444444444444444444444444444444444444444
555555555555555555555555555555555555555555555555
666666666666666666666666666666666666666666666666
777777777777777777777777777777777777777777777777
888888888888888888888888888888888888888888888888

So, suppose I work with the first option.
img5.png
img5.png (2.65 KiB) Viewed 6964 times
When the screen loads up (e.g. after the map is just loaded), this is how I can get the bytes I need to display
1) I have to figure out what's the address of the byte on the top left tile within the camera, something like

Code: Select all

first_byte = start + (cameray * map_width) + camerax
2) Then, I'd have to loop go get all bytes in that row, so 32 times.
3) After that, I'd have to find the first byte of the next row. I can do that by adding the width to the first byte

Code: Select all

first_byte_in_row = prev_first_byte + map_width
4) go back to (2). Rules 2, 3 and 4 will be executed 30 times

Then, after I scroll to the right, for example:

1) get the first byte inside the camera, like (1) above
2) add 256 to it, so we have the byte right on the top left part that is to the right of what's displayed on screen
3) get byte 1 and byte 2 so we have a 16x16 tile
4) go to the next row, by adding "map_width" to the address we found in 2
5) go back to (3). repeat 3,4,5 30 times.

I want to make sure this is the idea, because if so, it involves a bunch of things I still don't know how to do in ASM, like 16 bit operations and multiplication. I also want to make sure that it's feasible to do these things the way I thought without causing lag and stuff

Also, will this idea work if my map is RLE compressed?
KayBur
Posts: 12
Joined: Mon Mar 29, 2021 6:47 am

Re: Scrolling RPG maps

Post by KayBur »

Quietust wrote: Mon Mar 29, 2021 9:25 am
KayBur wrote: Mon Mar 29, 2021 7:22 am I'm not a big expert in programming, but in many popular games, in addition to the kernel written in C ++ or Python, a SQL-database is screwed in which all actions, conditions, etc. are written.
Maybe in a modern game written for a modern computer or gaming console, but I can't imagine that a SQL database would have any place in an NES game where you've only got a 1.79MHz 6502 CPU with 2 kilobytes of RAM (or, 10 kilobytes, if you're using a cartridge with extra RAM).

Similarly, no NES game is going to use C++ (even plain C has enough overhead), and the idea of using a Python interpreter is laughable at best.
As I say, I'm not an expert in programming, much less programming in legacy languages.
Post Reply