Skip to main content
GameDev.net gamedev.net
🔒 Locked

Tile based scrolling background

Started by Brass_Munkee Jan 27, 2004 at 3:00 AM 12 replies 1.2k views
Original Post
Brass_Munkee
Brass_Munkee
Ive read many threads on this site pertaining to this topic but i think if i could have my own situation responded to it would help me alot more, so here it is. Im making a 2D RPG. Think SNES style like FF3, EarthBound, secret of something, something of mana (you get the idea). So ok. I know i am going to have to have large maps in this game. These maps must be created out of tiles. And there will be a certain viewable area and only the tiles within the current viewing area will be drawn. I have 2 books for reference, but neither show me as much as i need to get this started. first off i knwo i need the graphics to begin with, so say i have 1 tile, a grass tile. I want an entire 640x480 screen(viewing area) to be filled up with this grass tile (the tile is 32x32) so that means the viewing area will have 20x15 grass tiles within it. Am i supposed to manually create a matrix specifically saying which tile needs to be placed at every coordinate? for example: matrix[0][0] = grass tile, matrix [0][1] = grass tile, ... This is obviously tedious and want to know how i could do this easier. Second the books i was using mention something about clipping un-used tiles. But so far i find this unecessary. I am already going to be using memory because i have to initialize every bitmap i am going to be using in that map. And if i draw all 20x15 tiles on the screen and move to the right one tile length, I am still drawing 20x15 tiles except the 15 tiles on the right are new tiles. Why would i need to worry about what is left over on the left outisde the viewing area? its not like im re-drawing them even though i cant see them. i only draw whats within the viewing area. I dont even know if that is what they were getting at about the clipping. Any ideas on that? i was also thinking would it be a good idea to ONLY initialize bitmaps being used in a specific map rather than initializing all the bitmaps at game start? say if im in a desert in the game, when a player goes to the desert map, i initialize all the tile pointers and bitmap pointers used in the desert map then when i leave i delete them all? Thanks for taking your time to help me, im sure this topic is turning into a broken record by now. But any help or any light shed on this topic for me will be greatly appreciated.
m_wherrett
m_wherrett
I'm afraid a large array of values is going to be what you want buddy. A 2 dimensional array such as mapArray[20][15] could contain simple integer values where 1 = grass, 2 = mud, 3 = water etc etc. Loading a map can be a simple matter of reading in values from a text file and applying them to that array accordingly.


When it comes to drawing the tiles you could simply loop through all the elements in that array and call a specific draw function which draws the appropriate bitmap in the appropriate place. However, what would you do if you had a larger map that you can scroll around (mapArray[100][100])? You may not see the tiles drawn off the screen but calling the draw function for every single tile in your array would waste cycles. That is why you need to determine which tiles are in the camera's view and then only call the draw function for those tiles in particular.


As for loading specific tilemaps, this is something that is dependant on your engine. If your tile bitmaps are sectioned out carefully you could just ensure only specific tiles are used manually. Obviously that would require you to have the map file specify exactly which set you are using. Alternatively, you could have a list of the tiles to load/use before the array data in the aforementioned map file. Essentially, the map file could contain information detailing a list of bitmaps required and an array to signify which bitmaps go where. As your game progresses it could begin to include things like entity locations, map properties and such like.

As with many tasks like this, there is no wrong way to do it. Choose what you feel happy with and worry about making it more efficient/competent afterwards.


EDIT: and check out the articles in this section...


http://www.gamedev.net/reference/list.asp?categoryid=44


[edited by - m_wherrett on January 27, 2004 7:37:31 AM]
SelethD
SelethD
From your post it sounds like your not too familiar with the practices that you are asking about.

So dont bite off more than you can chew. Start small and experiment a LOT!

First try getting a map the size of the screen displaying with your tiles, then try one that is say, 4 screen sizes, and work on your scrolling techniques.
Then once you have a map that you can scroll around it, then experiment with loading seperate bitmaps with alternative tiles for other areas of your game.

Just go slow and get really comfortable with what your doing before you move onto another section.

If your using DirectDraw and need any help with this, you can e-mail me, just mention the post, or I trash the e-mail.
SelethD@hotmail.com
M3d10n
M3d10n
The objective of tiles is to make it easier to have huge maps that reuse graphics. You have a source image that stores the tile graphics, and a map, that is a large array that specifies which blocks from the source image you''ll draw in the screen. You seem to know that already.

The map is a huge 2D array, and you need to build it somehow. While it can be done directly in the code, it''s an obnoxious work, and you''d better off making a tile editor that lets you specify, visually, which tiles goes were.

As for scrolling, you don''t quite need any sort of culling. As you mentioned, you have 20x15 viewable tiles. When you scroll the map, you move it''s zero point. By dividing the offset between the map origin and the screen origin by the tile size, you''ll get the first visible tile (integer part) and a pixel offset (the decimal part). So, you use the screen tiles as "slots", where the first visible tile goes into the first slot.

Then you use the pixel displacement to move the screen tiles from their initial positions a bit. This will give you smooth scrolling.
Brass_Munkee
Brass_Munkee
thanks for your replies all advice im thankful for.

Ill check out those article m_wherret. thanks.

and seleth if i was too familiar with the topics i am posting about i probably wouldnt need to post about them to begin with : ) but yes that is exactly what i planned on doing, i am trying to get every piece of the puzzle working properly before i turn this into any huge production. And no im not using DirectDraw although i was reading up on it and might consider it. right now im just using strict windows GDI code.

but m3d10n i think you just hit the jack pot on your explanation of the pixel offset, interger being the tile, decimal being the amount of pixels currently viewbale in the tile. I think i am going to work towards that, i hadnt really looked at it in that perspective.

thanks agains guys, but while writign this reply i thought i just might ask abotu one more thing. If youve ever played any typical SNES RPG you''d notice that in small maps such as a small room, if you walked as close to the wall as you could you would see black region outside of it that was not accesable. Is this just the programmers making the map larger than the actual room and adding black tiles to the outside?





SelethD
SelethD
Sorry if I sounded kinda rude or anything, not my intention.

Well you can still email me if you need any help. I have been doing tile based games for the last 15 years.

Good luck
Brass_Munkee
Brass_Munkee
nah i didnt take it as you being rude, its all good.

Ive been sitting here for an hour or so drawing out possible situations trying to see if i can design this on my own but its becoming quite time consuming lol. I think i have it worked out of the most part but i think im getting stuck on the math of it all.

Ive got it figured out exactly how to find the first visible tile in the top left corner. But i can''t seem to visualize how to work the top right corner. Im not gonna go into detail here, i think i''ll just email you. 15 years of experience is quite a hefty background : )
Wavarian
Wavarian
Or you could do what many other tile-based rpgs do, and keep an array of map "chunks" that you can refer to using an id value. In your tile editor, allow say, an 8x8 tile chunk to be defined and stored. Then, you can simply specify which 8x8 tile chunk gets used where.

Lessens the hassel of working with each tile individually, allows you to re-use certain chunks without the player even noticing, and lessens the amount of overall memory used to store each tile. (Cuts costs of access time too).

You could make the chunks bigger or smaller of course, however, making them bigger will decrease their re-useability, and making them smaller will increase the memory used to store them, and the time it takes for you to build your "world". Keep this in mind.

Good luck.
M3d10n
M3d10n
Back to the screen tiles... you can easily make the "black areas" with it.

If any of the screen tiles happen to fall outside the map tile range, render a pre-definied tile into them (first one, maybe).

Example:
if your map (a room) is [10][10]. You use 32x32-sized tiles, so your 640x480 screen stores [20][15] tiles, so your map will only fill part of the screen. If you center the map, screen_tile[0][0] (lef to right, top to bottom) will point to somethingn like map_tile[-5][-2]. Since that''s outside the map, put a dummy tile in there.
yaroslavd
yaroslavd
Brass_Munkey, what''s your e-mail? Or do you have AIM/MSN/ICQ? Because I''m working on a very similar project, and could help you.

My screen name for AIM is yaroslavd. My e-mail (and MSN screen name) is yaroslavd@hotmail.com. Just IM me or e-mail me, and I should be able to help you out.
Ecliptici
Ecliptici
I'm working (somewhat) along the same lines with a tile based game. So far, this method is working on levels with about 1MB of tiles (1 tile = 1 byte).

The idea is based on the fact that no matter where you look, you're always going to be looking at 16x16 tiles (I'm going for a super metroid-esque look, so yes, this is accurate) so it would just be best to compute an array of vertices in a grid format and assign a glVertexPointer to it.

Each tile in memory equates to two (float) texture coordinates in OpenGL, so a brute force method here simply wouldn't work for maps of the size I'm working with now. Rather than precomputing all of the texture coordinates for each tile (essentially turning that 1MB I have loaded into 10-11MB) I created a class to serve as a "memory pool", or manager that only loads (at absolute maximum) 16 leaves worth of the quadtree. This is preallocated memory, and is never deleted or realloc'ed. Every few milliseconds (NOT every render), the viewing rectangle of the camera for the scene is passed through the quadtree, and the leaves that need to be drawn are loaded into the manager class, and given an ID they can use to identify themselves to the manager. Every render, unused leaves are forgotten by the manager (and their manager ID's revoked), so there is always (in theory) an empty spot if another leave needs to be loaded.

When rendering, I progress down the tree, rendering each node's objects, until I reach the leaves, when I pass the ID of the current leaf into the manager class, which determines what to render based on simple pointer arithmetic like so:


glColor4f(1.0f,1,1,1);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D,mTextures[mCurrentTexture]);
glTexCoordPointer (2, GL_FLOAT,0,(void*)&mRenderData[pos<<11]);
glVertexPointer (2, GL_FLOAT,0,(void*)gVertexGrid);
glDrawArrays(GL_QUADS,0,SIZE_SIDE*SIZE_SIDE * 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);


Where SIZE_SIDE is the number of tiles on a side of a quadleaf (in this case, 16).

I've gotten pretty good results so far, although I need to learn how to compress the filesize down so that the levels aren't quite so gigantic on disk. Other things that could be changed / added is the ability of the manager class to stream from disk, which I discarded because I considered it a bit too ambitious for the present moment.

A side note, the only thing I have to do to load a new tileset is just change the texture I'm loading, as long as it is 256x256 it can be used as a 16x16 tile map.

In summary:

render portion:
Scenegraph asks Environment to render quadleaves based on their ID's
Environment forgets unused leaves through pointers to the leaf in question
update portion:
Scenegraph does a quick prerender using a camera's view rect to change tile data to texture coord data.

Also, as above, what's your AIM/Email/etc?
I'm working on kind of similar lines, and maybe you could help me out / I could help you out / we could just reminisce about the glory days of the SNES.

my aim: Lunare Acerbus
my email: ecliptici at cox dot net

[edited by - Ecliptici on January 28, 2004 12:27:00 AM]
Glyce
Glyce
Sorry if I'm late to get on the bandwagon for this one, but if you are still looking for tutorials, I found Joseph Farrell's "Game Programming Genesis" to be right along your requirements.

http://www.gamedev.net/reference/programming/features/gpgenesis1

[edited by - Glyce on January 29, 2004 11:12:08 AM]
Rick Scott
Rick Scott
Much easier to do (IMO) then what some of the people above are suggesting is this:

Create a simple text file that looks like this:

1 2 5 2 2 2 2 1 1
1 2 5 2 2 2 2 3 3
1 2 5 2 2 2 2 3 3
1 2 5 2 2 2 2 3 3
1 2 5 2 2 2 2 3 3
1 1 1 1 1 1 1 1 1

etc. Parse it to fill in your "matrix". To scroll, keep the map-offset in a pair of ints and always draw one line of tiles outside the view of the world (yes, that sometimes means negative offsets). If you are using DirectDraw, the clipping will be done for you automatically so no need to worry about "how much of a tile is on the screen." Just draw an extra line of tiles in all 4 directions and you needn''t worry about it.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.