Tile Engine Considerations

BlitzMax Forums/BlitzMax Programming/Tile Engine Considerations

Hi Daniel,

What (I think) I'm doing is using one image per tile, but then that single image is getting drawn wherever the tile is on screen. So, for instance, I have "Water Tile 42" or whatever, and if there are 50 of them on screen, they are all referring to that single image.

Regarding storing alpha data and animation data etc...well, I'm not storing it in the tile, per se. See, I've got my base TTile class. ALL this class does is store it's associated image.

Then I have a TTileSet class. This class, when it is first instantiated, loads a tileset into a pixmap, and then creates individual TTile objects for each tile in the pixmap and stores the image in the TTile. The TTile is then stored in an TileArray:TTile. The position in the array that it is stored at is dependent on it's position in the Tileset. I do a normal 'column scan' through the pixmap, and the first tile created is stored at TileArray[1], second tile at [2], and so on. Also, the location in the array is ALSO the tiles "ID" number, which I will explain in a bit. Basically I use the ID as a lookup into the array.

Next I have a TTileMap 'container' class. This particular class holds info about a tile (but does not hold the actual image). It holds a TileID (which is used to get the image from the tile array mentioned above), a layer value (depth value), and flags regarding if it's an obstacle, a stairway (which causes the Y value handling to be different), etc.

As mentioned, I don't actually store a TTile object in this container class though, instead the class uses the TileID to refer to a tile in a Tilearray. This container class also contains a Draw method, which in this particular class calls draw image on the Tile object that it looks up.

I've then extended my TTileMap container class into other classes, such as a TAnimatedTileMap. This class holds extra info about the animation info, alpha info, etc, and overrides the Draw method to utilize the alpha info and such.

As far as I know this approach involves only using one copy of any particular tile in the tileset regardless of how many times that tile appears on screen. The actual tiles are owned by a tileset object...stored in a 1D array. Their TileID represents their location in that array - and that TileID is the what the TMapTile object holds. So in regards to the master map file - each X,Y location holds a series of "MapTiles" which hold TileID's which are utilized as a reference to the actual Tile image. Sorry for basically repeating that a couple of times, but I'm not sure if I'm making it clear what I'm doing.

The only reason I decided to break up my tile map pixmap objects into individual tile sized images is because I didn't see any way to draw only a partial rectangle of an image. It's of course easy to do with pixmaps, but ridiculously slow when we're talking a potential 1200 tiles or more per screen.

Is there an easy way to draw a partial rectangle of a large image within Bmax, or perhaps with direct calls to OpenGL? And if not, is there any difference in the amount of video ram that will be taken up if I have say, 100 32x32 images verses one 320x320 tileset? I was inclined to believe there wasn't, (minus perhaps a negligible amount of overhead) - and since I didn't see any easy way to draw partial images, I decided to break the tileset pixmap into images when I first load the tileset. (afterwards the pixmap is discarded and the individual images, the tiles, are stashed in an array (this allows direct access when the maptiles are referencing them with the TileID)).

The only reason I'm not drawing individual tile rows or columns as they appear on screen is because when it so happens that one of the newly uncovered tiles contains a tile in a tileset not currently loaded, the process of loading that tileset and then drawing the tiles causes a slight hiccup. Also, eventually I plan to give the player a means of rapid transportation, and then the above problem would simply be exacerbated. I could of course 'pre-screen' a rectangular area of the map larger than the screen area and check to see if any tilesets need to be loaded and then do so before the character gets there. But that's not much different than the region approach I have now - and that has the benefit of having the map pre-loaded as well.

The other thing that has me worried is that I will no doubt have certain tile locations that have 6-10 layers, and if the game suddenly had to load and draw say, 35 tile spaces (20 wide and 15 tall in 640x480 when using 32x32 tiles...this might happen if the player was moving diagonally, for instance) each with say 6 tiles...well, again I imagine the game would hiccup a bit.

I really appreciate your feedback and insight though, it's given me a lot to think about. I guess what makes it really difficult is that the framework I'm building is really quite large, and it's the kind of framework that it'll be hard to test 'realworld results' until I have most of it implemented. I'm trying to plan for it to be as optimized as possible while still being as flexible as possible. I want the engine to offer as few constraints as possible, as I plan on using this thing for many other 2D projects down the road.

Thanks again - let me know if any of this made sense and if I'm right or (probably) way off with some of the assumptions I've made.