Question on tiles and SDL surfaces
I''ve come up with what SOUNDS, in theory, like a good tile engine for a side-view tile-based game I''m working on. The gist of it is this...
First, tiles (ie, "grass tile", "door tile"; not "tile at 57,18". That is, the tile palette instead of the actual map tiles) are defined in a file: various properties that may be relevant to my game as well as the graphic (which will be stored in a series of bitmaps; all''s I''d need is the bitmap ID and the X/Y position, pretty much...). There''s the obvious "solid" property (ie, can stand on), say... a "climbable" property, etc. On the subject of graphics, tiles will most likely be in more than one actual bitmap file since the complete tile palette for the game will probably be rather big.
Once this tile information file is built, it is loaded in the game. A tile object will hold the following data: the tile''s properties, the tile''s ID (actually, I''d have an array of tile objects and the index would be the ID, so this isn''t quite a property in the class itself), and... this is where the main part of my question comes in, an SDL surface which holds the tile graphic. Basically, for instance, a 16x16 colorkeyed surface.
Then when I wish to render the level, I''d loop through every element of the map array (which are onscreen, of course; why render stuff that won''t be displayed?) and simply do something like... Tileset[MyMap[CurrentPos]].Render(). Poof, tile''s blitted from the SDL surface it contains to the screen.
The alternative would be to simply hold the file and the X and Y position in the file where the image is stored, however this has a few problems. Mainly the fact I might have to load multiple bitmaps at once, sometimes just to gain access to a single tile (if, for instance, the ground graphic is in SomeBitmap_1.bmp and the rest of the tiles are in SomeBitmap_2.bmp). Furthermore, my idea allows me to do a lot of stuff. For instance, if I want to animate a tile, I can just change the tile''s graphic. When I''d render the map, since every element on the map that uses that tile would all use the same instance of my tile class, they would all be updated in one fell swoop.
Is this a good idea? Can it be improved? Would it be a waste? I can''t say I''ve tried it yet (I''ve yet to come to a decision on the actual format I''ll be using for my maps) but I don''t want to end up writing two different map engines, frankly. I feel this is a pretty safe bet but I''m also uncertain exactly how bad having, say, 500 16x16x8 SDL surfaces loaded in memory would be. That''s my main concern.
I''d say the system''s alright, but here''s a suggestion. Tiles are bound to be repeated, right? You should create a class (or module) that keeps track of SDL surfaces such that a surface is never loaded into memory twice. Then, in your "tile" class, have a pointer to that surface - as opposed to having a copy.
Another idea - you''re not going to be rendering every single tile. Likely you''ll have some sort of scrolling background, and say, 40% of the screen have tiles (I''m just guessing - as a comparison to Mario). Use a list of tiles on the map - if they''re viewable on screen, render them. This is far more efficient than having a tile for every possible position on the screen, and looping through them all.
Hope that''s helpful.
- Ben
[benlog.org] [Project 0 A.D.]
Another idea - you''re not going to be rendering every single tile. Likely you''ll have some sort of scrolling background, and say, 40% of the screen have tiles (I''m just guessing - as a comparison to Mario). Use a list of tiles on the map - if they''re viewable on screen, render them. This is far more efficient than having a tile for every possible position on the screen, and looping through them all.
Hope that''s helpful.
- Ben
[benlog.org] [Project 0 A.D.]
quote:Original post by carb
Another idea - you''re not going to be rendering every single tile. Likely you''ll have some sort of scrolling background, and say, 40% of the screen have tiles (I''m just guessing - as a comparison to Mario). Use a list of tiles on the map - if they''re viewable on screen, render them.
Hmmm how would you optimize that? Quad-tree?
Well, what I had in mind was merely to loop from say... PlayerX - 10 to PlayerX + 10 (not exactly, but you get the idea). I don''t see how this could be (or why, for that matter) optimized, really
Wait, I read that wrong. Heh. Yeah, though I figure the overhead for a simple if(currentTile) wouldn''t be anything to worry about in a, say, 32x20 screen. 640 ifs doesn''t sound like TOO much, though I could be wrong.
Does SDL have something like DirectDraw where, eh... I forgot the name but it''s some kind of reverse color key where you can only draw on a certain color when blitting. This allows for quite a bit less overdrawing: you just render stuff backwards. Foreground, sprites, tiles, background. By the time you get to the background, you only have to fill in a few holes here and there (say... 60-40% of the screen). Seems like it would help with a lot of things. Can that be done with SDL or is there a library that implants it?
I''m not sure what you mean about having a pointer to an SDL surface where the tile is stored. Do you mean keeping the entire tileset collection in memory and having a pointer to the right surface instead of a copy of just the tile? Sounds wasteful to me... let''s suppose we have Bitmap1 and Bitmap2. Bitmap1 contains say... grass-type tiles. But for a given stage, I also need the chair tile from Bitmap2. Are you sure loading all of Bitmap2 in memory just to get a single tile from it would be better than creating an SDL surface and blitting just the tile to that surface (during the load phase at start), then discarding the bitmap surface? Or did I misunderstand your suggestion?
Thanks
Wait, I read that wrong. Heh. Yeah, though I figure the overhead for a simple if(currentTile) wouldn''t be anything to worry about in a, say, 32x20 screen. 640 ifs doesn''t sound like TOO much, though I could be wrong.
Does SDL have something like DirectDraw where, eh... I forgot the name but it''s some kind of reverse color key where you can only draw on a certain color when blitting. This allows for quite a bit less overdrawing: you just render stuff backwards. Foreground, sprites, tiles, background. By the time you get to the background, you only have to fill in a few holes here and there (say... 60-40% of the screen). Seems like it would help with a lot of things. Can that be done with SDL or is there a library that implants it?
I''m not sure what you mean about having a pointer to an SDL surface where the tile is stored. Do you mean keeping the entire tileset collection in memory and having a pointer to the right surface instead of a copy of just the tile? Sounds wasteful to me... let''s suppose we have Bitmap1 and Bitmap2. Bitmap1 contains say... grass-type tiles. But for a given stage, I also need the chair tile from Bitmap2. Are you sure loading all of Bitmap2 in memory just to get a single tile from it would be better than creating an SDL surface and blitting just the tile to that surface (during the load phase at start), then discarding the bitmap surface? Or did I misunderstand your suggestion?
Thanks
You should also realize that you probably don''t need much in the way of optimization, given this is 2D, but to each his own.
As to your question, it''s far less wasteful. You have only one copy of a graphics file (e.g. bitmap) in an SDL surface. Everything that could potentially render that surface has a POINTER to that shared surface. Not that this would improve performance in terms of blitting, but it''s just a "common sense" programming practice Surfaces can take up a significant amount of memory - having 100 copies of the same surface in different tiles is particularly wasteful. This way, you only ever have one copy.
- Ben
[benlog.org] [Project 0 A.D.]
As to your question, it''s far less wasteful. You have only one copy of a graphics file (e.g. bitmap) in an SDL surface. Everything that could potentially render that surface has a POINTER to that shared surface. Not that this would improve performance in terms of blitting, but it''s just a "common sense" programming practice Surfaces can take up a significant amount of memory - having 100 copies of the same surface in different tiles is particularly wasteful. This way, you only ever have one copy.
- Ben
[benlog.org] [Project 0 A.D.]
Woaaah, I don't think you fully understood what I was trying to do.
I'm not going to store every tile in the map as individual SDL surface; that would, obviously, be quite a waste. (Edit: For instance, if I have a long stretch of "straight rocky ground" tiles, I won't store each "straight rocky ground" tile as a seperate surface.) I'm storing every individual tile from the tileset in surfaces.
I plan on storing every tile, neatly seperated in these images, as a seperate "tile" object. As I've said in my OP, this is what has me worried: would I be wasting considerable resources doing this, or negligeable resources? Anyhow, so we store these spiffy tiles and give them a simple Render() method which just blits the surface to the display. Nice and easy. You're probably wondering why not just store a pointer to the location of the tile in the bitmap?
Let's say I'm working on a desert level and use the tiles from the first bitmap. But lo and behold, for whatever reason it may be I want to use the ice stalagmite from picture 2. This would mean loading bitmap 2 in memory just to use a single tile. Again, I'm using these two as examples: I'm expecting to use quite a lot of tiles for my project (this isn't a simple one-layer 2D sidescroller with choppy 2-3 frame animations and a static background; I have pretty big tilesets). Loading a, say, 512x512x8 image just to have access to a 16x16 region in it seems like a lot of waste to me. And what if I have to do this with 3-4 images? Hrm.
The other happy little bonus I see here is, suppose I want to make fire stalagmites (ooooh o.o) or something like that, I can just alter the palette of the coresponding tile object. Or if I want to animate, I can just swap the contents of the tile's surface with the next frame. Then when I render my map, I'd call the aforementionned Render() method and wouldn't have to worry about a thing because the replacement would be automatic: every tile that uses that particular tile would be redrawn with the new image.
As for optimization, I'm not sure how your statement holds true. For a simple 2D game, yes. On a higher end system, yes. With a graphic-intensive game on a < 1 ghz system? Eh, lazy coding and bad algorithms could end up harming the performance. Well, quite a bit more than if 3D methods were used to handle the graphics (ie, textured quads to render sprites and all). At least, prior experience makes it seem that way. I could be wrong. >"<
Edit: Ok, actually, I'm a dumbass. Either way, I'm still loading just as much image data. Instead of, say, 5 256x256 chunks, I'd be loading 1200 16x16 chunks. Ah... didn't quite think of that. In fact, it sounds even worse when I look at it like this.
Well, I still get the advantages I mentionned with my idea. But my argument against kinda went down the drain. So yeah. Is it still worth it, given the fact I can very easily animate tiles, or am I just wasting my time anyways?
Edit 2: Wait wait wait, got an idea. Why load EVERY tile? Why not just load every tile I plan on using in a given map? I'd cut down from a few thousand tiles to maybe a few hundred in memory at once. I can still avoid loading a whole bitmap just to use one tile in my map, though I still end up with a few hundred 16x16 SDL surfaces. It's a bit better than my previous observation, though my question still holds... Obviously the header for the surface would end up chewing quite a bit of unecessary memory, though would it really be that bad? I can still do some very easy manipulations of my tiles...
[edited by - RuneLancer on April 22, 2004 2:43:50 AM]
I'm not going to store every tile in the map as individual SDL surface; that would, obviously, be quite a waste. (Edit: For instance, if I have a long stretch of "straight rocky ground" tiles, I won't store each "straight rocky ground" tile as a seperate surface.) I'm storing every individual tile from the tileset in surfaces.
I plan on storing every tile, neatly seperated in these images, as a seperate "tile" object. As I've said in my OP, this is what has me worried: would I be wasting considerable resources doing this, or negligeable resources? Anyhow, so we store these spiffy tiles and give them a simple Render() method which just blits the surface to the display. Nice and easy. You're probably wondering why not just store a pointer to the location of the tile in the bitmap?
Let's say I'm working on a desert level and use the tiles from the first bitmap. But lo and behold, for whatever reason it may be I want to use the ice stalagmite from picture 2. This would mean loading bitmap 2 in memory just to use a single tile. Again, I'm using these two as examples: I'm expecting to use quite a lot of tiles for my project (this isn't a simple one-layer 2D sidescroller with choppy 2-3 frame animations and a static background; I have pretty big tilesets). Loading a, say, 512x512x8 image just to have access to a 16x16 region in it seems like a lot of waste to me. And what if I have to do this with 3-4 images? Hrm.
The other happy little bonus I see here is, suppose I want to make fire stalagmites (ooooh o.o) or something like that, I can just alter the palette of the coresponding tile object. Or if I want to animate, I can just swap the contents of the tile's surface with the next frame. Then when I render my map, I'd call the aforementionned Render() method and wouldn't have to worry about a thing because the replacement would be automatic: every tile that uses that particular tile would be redrawn with the new image.
As for optimization, I'm not sure how your statement holds true. For a simple 2D game, yes. On a higher end system, yes. With a graphic-intensive game on a < 1 ghz system? Eh, lazy coding and bad algorithms could end up harming the performance. Well, quite a bit more than if 3D methods were used to handle the graphics (ie, textured quads to render sprites and all). At least, prior experience makes it seem that way. I could be wrong. >"<
Edit: Ok, actually, I'm a dumbass. Either way, I'm still loading just as much image data. Instead of, say, 5 256x256 chunks, I'd be loading 1200 16x16 chunks. Ah... didn't quite think of that. In fact, it sounds even worse when I look at it like this.
Well, I still get the advantages I mentionned with my idea. But my argument against kinda went down the drain. So yeah. Is it still worth it, given the fact I can very easily animate tiles, or am I just wasting my time anyways?
Edit 2: Wait wait wait, got an idea. Why load EVERY tile? Why not just load every tile I plan on using in a given map? I'd cut down from a few thousand tiles to maybe a few hundred in memory at once. I can still avoid loading a whole bitmap just to use one tile in my map, though I still end up with a few hundred 16x16 SDL surfaces. It's a bit better than my previous observation, though my question still holds... Obviously the header for the surface would end up chewing quite a bit of unecessary memory, though would it really be that bad? I can still do some very easy manipulations of my tiles...
[edited by - RuneLancer on April 22, 2004 2:43:50 AM]
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement