gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Scrolling maps... Tips?

#169127 - elyk1212 - Sun Jun 21, 2009 2:03 am

Ok, I am betting there are many more creative, and probably better ways. Please let me know.

I am just scrolling a simple run and jump background and have a question of what to do when I reach the edge. I have a 64x64 tile map, and once I scroll this about a two screen lengths, I reach the end of the said map. I want the map to continue on with the next "screen height row" of the tile map (basically scroll the level platforms and junk and have it wrap over when reaching the end of the map to the next lower level, seamlessly.

First off, do I have the right idea here, do most of you do this for standard maps, scroll down to the next level etc, with preloaded tiles and map?

Second, if so: Before I reach the end, should I buffer the next level of the map to the last screen section that has already scrolled off to the left? In other words

Here is my view:

(where rows are divided by screen height)

row 0: Screen width1 | Screen width2 |
row 1: Screen width 3 | Screen width 4
row 2.....

So, when I am near the end of screen width2, should I start placing the map for screen width3 into the map space memory, overwriting where screen width1 used to be?

This way when I update the Horizontal offset register for the background, it appears to be a "seamless" transition to the new area of the map.

If I didn't do this I'd have to "distract" the player and just use the vertical offset register, but I don't think games do this for horizontal scrolling, right?

But this makes me wonder about long maps,... even Super Mario World seems to have much longer maps than what is provided by the 64X64 tile space on a max normal GBA map (maybe even more than 128x128 affine?). Do they start loading the tiles for next section of a map when mario reaches a certain "world space" position?

It would seem with all the flying around Mario did, they have the appearance of a pretty large map space.

What do they do in this situation? Maybe the Affine map space of 128x128t is large enough to accommodate them.

I think I am missing something.

#169129 - gauauu - Sun Jun 21, 2009 2:22 am

Most tile-based games (that don't use fancy scaling or rotation effects) use a relatively small (32x32?) background. Because all you really need is what fits on the screen plus another row or two.

As you scroll to the right, for example, you'd copy a column's-worth of map tiles onto the map column that is just about ready to scroll into view. If you always copy the one column (or row) at a time, the time required to copy the tiles is negligable.

Does that make sense at all? (I'm not quite as good at explaining it as others on here are). If you do some searches for scrolling tiled backgrounds, you'll probably find better explanations, as it's been covered a few times.

Good luck.

#169130 - sgeos - Sun Jun 21, 2009 2:47 am

Think mapping part of your in game area to the display viewport.
Think modular.

Tile [x,y] in your area map will end up being mapped to tile [x%w,y%h] in video memory, where w and h are the width and height of the hardware background.

So, given a 32*32 background, tile [123, 11] of your area will be place in [27, 11] in the display. As you scroll, update the edges of your display.

#169131 - Ruben - Sun Jun 21, 2009 3:30 am

Since there's more "technical" answers here, I'll try to give a simpler answer:

When you scroll to the right and the displacement can be divided by 8, then draw a new column right at the end of the current view.
It's hard to explain, but it's a lot easier when you think about it:

Code:
extern int Dx; //Scrolling offset somewhere

if(MovingLeft) {
    if((Dx&7) == 0) {
        //Draw a column at ((Dx/8)-1)&31
        //That is, at the left, "invisible" side
    }
}
if(MovingRight) {
    if((Dx&7) == 0) {
        //Draw a column at ((Dx/8)+30)&31
        //That is, on the right "invisible" side
        //+30 assuming GBA screen. NDS = 32,
        //so you'll have to have 64x32 or something
    }
}

Note, however, that this can only be done on backgrounds that are 256x256 or bigger, as 128x128 is too small to fit the entire screen.

#169133 - elyk1212 - Sun Jun 21, 2009 4:06 am

Thanks, Cool. That sounds good... so... consensus on updating just the last "nearly visible" column then. Interesting. And I assume for parallax backgrounds you just use some repeating backgrounds that are interesting (clouds etc and cool tiled, repeatable art).

Ruben: I meant 128x128 tiles, not pixels ;). Lucky for me, there is no register value for 128x128 pixel maps, (to my knowledge) or during my testing I would have somehow happened upon this invalid state.... Just probability messing with me :)

#169134 - sgeos - Sun Jun 21, 2009 4:17 am

IIRC, you can use 32*32 maps on the GBA, but you need to use a 64*32 map on the DS because the screen width is 256 pixels.

You can try loading different games into VBA to see how they handle their VRAM when scrolling maps. (There is an autoupdate checkbox.)

#169135 - Ruben - Sun Jun 21, 2009 4:32 am

elyk:
I know. :P
And yes, there is a 128x128 pixel mode, but that's for affine backgrounds, which is.. not very useful IMO, unless it's an uber-repeated checker pattern for example.
But yeah, as sgeos said, on GBA you can use 256x256 (that is, 32x32 tiles) but on DS you kinda have to use 512x256 (64x32 tiles) since 256 is the width of the screen, giving you no edge room to update.

#169150 - elyk1212 - Mon Jun 22, 2009 4:29 am

Ah, yes, I missed that affine size. I am looking at the map viewer now to see how SMW does things.

Ha I forgot the windows version has so much more debug capability built in and didn't even think about using that.

(And I wonder why this wasn't ported to Linux, so now I am running it in wine, oh well. I wish folks decided on a cross platform GUI toolkit when making "portable" applications... sigh... ).


Whoa, blocks and coins and stuff are done with bg tiles, I had no idea, I thought they'd be sprites! Well, scratch that the info blocks are still sprites.. How interesting.
_________________
"Turn from evil and do good; seek peace and pursue it." Psalm 34:14

Like art? Just some wallpapers I do in my free time:
http://www.razzlegames.com/wallpaper/

#169152 - Ruben - Mon Jun 22, 2009 4:53 am

Wow, that is interesting indeed... Maybe they're using up sprites doing something else? Idk. But that *is* interesting.

#169154 - sgeos - Mon Jun 22, 2009 5:28 am

Of course the coins are tiles. With the number of coins they line up in the NES games, they would run out of total sprites and line over. Also, all the sprites can be animated in sync by just updating one character.

Same thing for the blocks. I suspect that when you bump a block, the tile is deleted and replaced with a sprite for the duration of the bounce, and the the block is tile is re-added so long as it has not been destroyed.

#169169 - elyk1212 - Mon Jun 22, 2009 3:53 pm

Yeah, I guess I just thought, you know.... allocate the OAM number and point to the gfx memory when it was needed, e.g. when it comes near being in screen cords, then when it went out being reclaimed. All in all it seems the levels I've looked at only have a handful of sprites ever active. For the first level, most of the time it is just mario and maybe a few enemies (and yoshi)
_________________
"Turn from evil and do good; seek peace and pursue it." Psalm 34:14

Like art? Just some wallpapers I do in my free time:
http://www.razzlegames.com/wallpaper/

#169176 - sgeos - Mon Jun 22, 2009 6:47 pm

Sounds about right. Backgrounds are not static immutable layers; you can do a lot with them.

#169195 - elyk1212 - Tue Jun 23, 2009 4:19 am

The other thing I am finding interesting is they update the graphics tiles for animated background parts they are not even using (not being displayed). Maybe so animation stays consistent and so they don't have to track when they are in view, I suppose.... Cool.
_________________
"Turn from evil and do good; seek peace and pursue it." Psalm 34:14

Like art? Just some wallpapers I do in my free time:
http://www.razzlegames.com/wallpaper/

#169197 - sgeos - Tue Jun 23, 2009 6:47 am

I suspect they blindly blanket update all animations. This makes sure that everything will work in the worst case scenario, and it is the simplest way of doing things. Premature optimization is the root of all evil; don't be clever if you can just get the job done.

#169241 - elyk1212 - Thu Jun 25, 2009 3:20 am

Do you think they blindly update the 0x4000 bytes or so to cover tile all BG used tile space, or do you think they do it on a per tile basis for just the animated guys ?

(perhaps series of small DMA or normal memory writes)
_________________
"Turn from evil and do good; seek peace and pursue it." Psalm 34:14

Like art? Just some wallpapers I do in my free time:
http://www.razzlegames.com/wallpaper/

#169242 - Ruben - Thu Jun 25, 2009 3:43 am

My guess: Have a script that runs every V-Blank that is dependent of the map, and that script updates the required tiles, scroll the palettes, etc.
That's what I'd do ;)

#169243 - elyk1212 - Thu Jun 25, 2009 3:46 am

Yeah and it's possible, I am sure, just wondering if it matters (overhead of all the memory transfer per frame, or maybe it's every 2nd, 3rd or 4th hmmm...), or if the clocks spent on this is negligible.

But I guess you're saying you'd only update the animated tiles.
_________________
"Turn from evil and do good; seek peace and pursue it." Psalm 34:14

Like art? Just some wallpapers I do in my free time:
http://www.razzlegames.com/wallpaper/


Last edited by elyk1212 on Thu Jun 25, 2009 4:34 am; edited 1 time in total

#169245 - elyk1212 - Thu Jun 25, 2009 4:17 am

BTW, Despite their volume, I noticed DK Country uses sprites for all in game goodies and most animations. All bananas are sprites and appear to come into existence when they are near screen cords (as I initially guessed SMW had done, but did not).

Hmm.. Just personal preference or I wonder if there are some reasons behind these differences (was it some necessary optimization for DK country?). Eh.. I am asking for way too much speculation.
_________________
"Turn from evil and do good; seek peace and pursue it." Psalm 34:14

Like art? Just some wallpapers I do in my free time:
http://www.razzlegames.com/wallpaper/

#169248 - Ruben - Thu Jun 25, 2009 5:06 am

Well, for map tiles, I think they're usually updated every 4 or 8 frames, but even then it's not much overhead (just a few ldmia/stmia pairs (8 per 4bpp tile)).

And for the other point..

I think that SMW was based on the old spec which didn't allow much, so they just practically ported it, and made sure that it would work even in the worst case scenario.

For DK, I suppose that they could do that because the barrels/etc need to be moved by pixels when you grab them and stuff... but I'm not sure why the bananas would be sprites rather than-- Oh, I know: It's because the bananas have to move to the top of the screen to add to your banana count.

#169249 - sgeos - Thu Jun 25, 2009 5:50 am

For a simple system I would put animated tiles next to eachother, and DMA over all of them from shadow RAM. Then I would load the next frame for the tiles into shadow RAM. Repeat for each frame update.

There are many ways to do the same thing. Can your game work if your coins/bananas are locked to a grid? If not, use sprites. In theory you could use both. =P

#169253 - Dwedit - Thu Jun 25, 2009 12:17 pm

You can always turn a background tile into a sprite and back again. Super Mario Bros on the NES makes the bricks and other blocks sprites while they bump up, then turns them back to background tiles when the animation is completed.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#169254 - sverx - Thu Jun 25, 2009 1:32 pm

Dwedit wrote:
You can always turn a background tile into a sprite and back again.


The annoying part is that you have to copy it from the tile memory (in BG video ram bank) to the sprite memory (int the sprite ram bank)... :|

If I'm wrong I would be really happy to know :)

edit: are we talking about GBA or DS?

#169255 - sgeos - Thu Jun 25, 2009 1:43 pm

sverx wrote:
The annoying part is that you have to copy it from the tile memory (in BG video ram bank) to the sprite memory (int the sprite ram bank)... :|

Commercial games typically do not load all the graphics and run from there. They update multiple times a second. Once you have a robust system in place, this is not a big deal.

sverx wrote:
are we talking about GBA or DS?

Both.

#169273 - sverx - Fri Jun 26, 2009 11:18 am

sgeos wrote:
Commercial games typically do not load all the graphics and run from there. They update multiple times a second. Once you have a robust system in place, this is not a big deal.


That's very interesting... so you mean for instance they (or some of them at least...) do load in the video ram only the tiles they're going to use in the next frame and then start over for the next frame... or you mean they do load dinamically as if that was kind of a cache (thus starting to replace those tiles which were used last time more time before)?

I'm very interested in learning such techniques :)

#169274 - Ruben - Fri Jun 26, 2009 11:33 am

From what I've seen, commercial games don't give a *#&% where the player is: All they care about is that the correct tile data gets updated at the correct time (that is, during V-Blank, every few frames or so); "Map data? What map data?"

So in short, from the games I've seen, they simply copy the new tile into the old tile's location, in doing so not needing to update the map data (which could potentially be costly, cycle-wise).

#169275 - sverx - Fri Jun 26, 2009 1:26 pm

we're probably OT but I'm really curious about that... so eventually some moderator can split... ?

Ruben wrote:
From what I've seen, commercial games don't give a *#&% where the player is: All they care about is that the correct tile data gets updated at the correct time (that is, during V-Blank, every few frames or so); "Map data? What map data?"

So in short, from the games I've seen, they simply copy the new tile into the old tile's location, in doing so not needing to update the map data (which could potentially be costly, cycle-wise).


That sounds really bad. You mean they do not actually use most of the features that the hardware gives? Because copying new tile into old tile location is kind of bit blitting operation, something I thought I would -almost- never see in a maps&tiles system, something that sounds more connected with bitmap graphics (hopefully you understand what I'm trying to explain with my poor english...)

(btw: why updating the map could be 'potentially' costly?)

#169277 - Ruben - Fri Jun 26, 2009 3:09 pm

Sorry about the late reply: didn't check my e-mail.

Quote:
That sounds really bad. You mean they do not actually use most of the features that the hardware gives?

Actually, it's not as bad as you think:
For 16x16 tiles, it's just a matter of copying 4 tiles (which are 8*4 words) to the right tile: not costly at all if the compiler uses ldmia/stmia.

And I don't really see what you mean "what the hardware gives." It's really a lot "cheaper" to just copy the tile GFX over to VRAM from ROM (not all 0x4000 bytes, mind you: just the tiles that need to be updated).

Quote:
Because copying new tile into old tile location is kind of bit blitting operation

Nah, it's more of a data copying operation

Quote:
(hopefully you understand what I'm trying to explain with my poor english...)

Heh, your English is fine. And I'm trying as hard as I can to try and understand.. hopefully I'm right :P

Quote:
(btw: why updating the map could be 'potentially' costly?)

Because you'd have 2 options:

-Scan the tile map in VRAM for the each occurence of tile x. If the tile at x+1 is the one on the right for the 16x16 tile, then check the bottom left, bottom right, if all equal update: Messy and HORRIBLY slow

-Scan the map data (that is, the in ROM map data) for each occurence of tile x. If found, then check if it's in range of the screen. If it isn't, skip it. Otherwise, update the tilemap.

With direct blitting/copying, it's a lot simpler, cleaner and faster as it's just 8*4 words per 16x16 tile, which can be pretty fast with ldmia/stmia, unless you're copying 0x4000 bytes, heh :P

#169278 - sgeos - Fri Jun 26, 2009 3:37 pm

Read up on Model-View-Controller if you don't know about it already. Also, make sure you know about finite state machines.

Your game has a few components related to displaying maps:
The internal model of the world. (ie, this is a lava tile; you can pass through it, but you take damage) This may be updated every frame, or it may be loaded into memory and rare updated.
The internal representation of you viewport. (x: 123, y: 11, fog on) Probably updated every frame.
The software interface to the hardware. (registers and special locations in RAM) Updated during vblank.
Buffers and shadow RAM. These can be updated during vdraw, unlike the real hardware, so you can take a long time editing them, and then quickly copy them into the real hardware locations during vblank.

So, this is how your game logic will look:
Code:
while (1)
{
  initializeProgram();
  while (!finished())
  {
    updateController();  // read player input and update scripts
    updateModel();  // uses custom logic on updated controller
    updateView();  // uses custom logic on updated model
    updateShadowRAM();  // uses custom logic on updated view
    waitForVblank();
    updateHardware();  // DMAs shadow RAM and updates registers
  }
}


The exact techniques used are tailored to the game. Some games will load a tileset and "patch" it when it is time for the tiles to be animated. A lot of games will give each game entity its own sprite VRAM and update that location when it is time to animate the critter. Even if you have eight copies of the same type of critter, they may each have a spot in sprite VRAM. Important, because the might be on different frames of the animation, and you will not always have eight of the same critter.

Patching background maps multiple times a second is also not strange. You need to update your model and view anyway, so if you have the the cycles there is nothing wrong with updating the shadow background (which may actually be in VRAM depending on how things are done) and then setting it to the display. A 64 x 32 tile map is only so big.

From a cycle standpoint, sometimes a simple brute force approach (blindly update and overwrite everything) actually works better than trying to use logic to figure out what needs to be done. In the worst case scenario, the extra logic will mean that you can actually get less done. Note that a couple of if statements will not hurt you in practice unless they call some silly routine that overthinks the problem.

Yes, most games ignore most hardware features most of the time. You can only do so much at once and programmer time is expensive. A couple of good reasons to keep things simple.

#169295 - sverx - Mon Jun 29, 2009 11:23 am

Again very interesting answers, thanks both :)

Ruben: you're talking about having more tiles than what you can store in VRAM, right? Because, for example, if you've got less than 1024 different tiles and you want to draw on a background, I don't see the point of updating tiles at runtime. We've got maps, and we even got registers to scroll that map on the screen: that's one of the hardware features we have on the consolle and that we want to use. But I guess you was talking about having much more tiles than what it's possible to store... that's one interesting challenge actually I still didn't face, so I still didn't think about it.

sgeos: I understand, even if I never heard that "Model-View-Controller" it's what I do in my code :)

#169296 - Ruben - Mon Jun 29, 2009 12:33 pm

sverx:
Well, I was talking about animating tiles. :P

Again, I think it's a lot faster to simply update the tiles in VRAM (that is, the character block (thanks Cearn for making me doubt my own words :P)) rather than update the map, even if the amount of tiles is < 1024.
Then again, I suppose it depends on what sort of map you have... but I'd still stick to my method cos I'm stubborn xD

#169297 - sverx - Mon Jun 29, 2009 3:36 pm

Ruben wrote:
Well, I was talking about animating tiles. :P


Oh. I guess it's my fault I didn't read the topic from the beginning... :rolleyes:

#169300 - Kyoufu Kawa - Mon Jun 29, 2009 7:20 pm

Ruben wrote:
I think it's a lot faster to simply update the tiles in VRAM
That's how the Mario games do it, that's how Pok?mon does it, that's how I do it, why the hell shouldn't you? ;)