choosing which image to draw (tilemap)
BlitzMax Forums/BlitzMax Programming/choosing which image to draw (tilemap)
| ||
when you draw a tilemap you are choosing which tile to draw for each cell of the map. How do people store their images Map,Array? Ive noticed my game slows down a lot when the map is on the screen and im getting paranoid that cycling through a map or array to find the right image to draw for every cell of the map might be slowing it down. I was blaming it on the fillrate of the card but now im having doubts. |
| ||
Tile selection shouldn't be bottleneck... unless your code happens to be really inefficient. How many tiles are you drawing per frame? |
| ||
You definitely want to think about putting lots of tiles on a single `tilesheet` like a spritesheet, and then drawing rectangles from that image to draw your tiles. Otherwise all the texture swaps between images is a major slowdown. Depending on your complexity most people just define a 2D array to store tile references. |
| ||
its an iso game so first i draw the floor then the back walls, then objects then the front walls. yes i could do a spritesheet i spose. so in a busy scene im drawing about 50 tiles max each image is represented as a string (in the mapdata) which is searched for in a Tmap to actually draw to screen. I could create a temp variable for the last image selected and draw that unless the next image to draw is different i spose. |
| ||
each image is represented as a string (in the mapdata) which is searched for in a Tmap to actually draw to screen. That sounds like a lot of work to find an image... 50 is nothing at all. Look at Tachyon's Book II... that seems to be drawing a lot more tiles. |
| ||
HMMM I just did that thing where i dont search the map if the image was drawn last and my FPS went from 60 to 80 - oops! |
| ||
TMaps are not good for high-demand random access. Usually I have a TTemplate type, which has the image of a cell type and its properties (such as passable) as a field. Then I have a TTile (or TCell) type, which has a template:TTemplate field, and other things such as what objects are currently in that cell. Store your templates in an array where each has an ID number so you can find it quickly (grass=0, water=1, ..) (or you could even store in a TMap if you find that easier - it's only used once when the game loads, so won't slow it down during play) Store your game map as a 2D array TTile[x,y]. When you create each tile give it the ID number or name as string of the type of tile it is, eg code written from head and not tested Const map_x_size = 64, map_y_size = 64 Const grass_id = 0, water_id = 1, tree_id = 2 Const tile_type_num = 3 Global map:TTile[,] = New TTile[map_x_size, map_y_size] Load() 'see load function below to load templates 'make map of grass For Local x:Int = 0 Until map_x_size For Local y:Int = 0 Until map_y_size map[x, y] = TTile.Create(grass_id) Next Next Type TTile Field template:TTemplate '... Method Draw(x:Int, y:Int) 'look up my image from the template DrawImage template.image, x, y End Method Function Create:TTile(id:Int) Local tile:TTile = New TTile tile.template = TTileTemplate.Get(id) Return Tile End Function End Type Type TTileTemplate 'stores all possible templates, so each image is in one location Global all:TTileTemplate[] = New TTileTemplate[tile_type_num] 'the appearance of this type of cell Field image:TImage 'whether characters can enter this cell Field passable:Int Function Get:TTileTemplate(id:Int) 'returns the tile for this id number 'gives a debug error if tile not found Assert id > 0 and id < tile_type_num Assert all[id] <> Null Return all[id] End Function Function Create:TTileTemplate(id:Int, image:TImage, passable:Int) 'creates a new tile template for a given image 'and stores it in the all array automatically Assert image <> Null Local template:TTileTemplate = New TTileTemplate template.image = image template.passable = passable all[id] = template Return template End Function End Type Function Load() 'here it is hardcoded, or you could load data from text files TTileTemplate.Create(grass_id, LoadImage("grass.png"), True) TTileTemplate.Create(water_id, LoadImage("water.png"), False) TTileTemplate.Create(tree_id, LoadImage("tree.png"), False) End Function |
| ||
yeah im going to do that next, the map contains strings but i can create ints when the game starts. Then the images go into an array. |
| ||
usually i use a layers and 2d arrays to draw tiles. Drawing off screen tiles is moot and best to avoid that. |
| ||
I have something like this... The idea is that image lookup for each tile is based strictly on an integer index into an array that stores each images a single time. This is very fast. I have considered using an AnimImage to get all tiles in a single PNG file, but so far this have proved to not be needed. My rule is: Just get it done, optimize later. Separate files works fine. Note that this code isn't tested. I can post the real thing I'm using later if this proves to not be helpful. const tilew:int = 32 const tileh:int = 32 Type TScreen map:Int[24,18] Method Load() ' Usually this loads from a text file specifying image paths images[1] = LoadImage("data/tile1.png") images[2] = LoadImage("data/tile2.png") End Method Method Draw() Local x:int, y:int For x = 0 To 23 For y = 0 To 17 If images[screen.map[x,y]] <> Null Then DrawImage(images[screen.map[x,y]], x * tilew, y * tileh) Next Next End Method EndType Global images:TImage[255] Global screen:TScreen = new TScreen screen.Load() While Not KeyHit(KEY_ESC) Cls screen.Draw() Flip(1) Wend |
| ||
The way I did this in TileMax is that each tile layer references the tileset (which can be a single image, composit image etc), the X,Y coordinates of the upper left corner and width/height of the tile. I then use drawsubimagerect to draw the image or subimage to the screen at render time. |