Tilesets & RPG maps
BlitzMax Forums/BlitzMax Programming/Tilesets & RPG maps
| ||
ugh. sorry to flood the forum with questions, i hope it is not much of a bother. In blitz3D you have a surface, and i know how to render different shapes and textures from the same surface. How do i do this in BlitzMax? I have already asked related questions here: http://www.blitzbasic.com/Community/posts.php?topic=75531 and here: http://www.blitzbasic.com/Community/posts.php?topic=75549 then i thoughd to have found an awnser here: http://www.blitzbasic.com/Community/posts.php?topic=73041#816343 and here: http://www.blitzbasic.com/Community/posts.php?topic=73223#818518 but it seems to be overcomplicated for what i need it for. maybe ineed to study it a bit more, but can't it be as simple as the psuedo code: tileset=loadimage() map=newimage() for y=0 to 10 for x=0 to 10 map.pasteinto(tileset, srcx, srcy, srcwidth, srcheight, desx,desy) next next loop drawimage(map) flip loop (p.s. Also i noticed that BlitzMax is lacking buffers o_O?) |
| ||
i think your looking for a pixmap |
| ||
ok. so it is really a requirement to do this through pixmaps? yes.. that works. Maybe thats why i failed on doing it otherwise. k, just checking :) |
| ||
Why would you draw the tiles into a new image and then draw that, when you could draw the tiles directly to the screen in the first place? If you load the tiles as an anim image, you can then use the frame number to determine which tile to draw. |
| ||
Forget pixmaps. Research Anim Image. Will get you going quickly. Allows you place all your "same sized" tiles on one image and then easily render them similar to your post. ;) |
| ||
Why would you draw the tiles into a new image and then draw that, when you could draw the tiles directly to the screen in the first place? If you load the tiles as an anim image, you can then use the frame number to determine which tile to draw. That is Exactly what ive done, and working. But i was told i could optimize that, however, i dont know how. Having looked at the given example i didnt see how that would optimize it. Here, before we lose track, this is what i have: Type TTileset Field image:TImage Field width:Int Field height:Int Method Open(file:String) Local image:TImage = LoadImage(file) Self.width = ImageWidth(image) Self.height = ImageHeight(image) Self.image = LoadAnimImage(file, 32, 32, 0, (Self.width / 32) * (Self.height / 32)) End Method End Type Function DrawTile(tile:Int, x:Int, y:Int, z:Int, oX:Int, oY:Int) If z = 1 And tile = 0 DrawImage(ts.image, (x * 32) - oX, (y * 32) - oY, 31) 'If z<>5 And z<>8 And If tile > 0 DrawImage(ts.image, (x * 32) - oX, (y * 32) - oY, tile - 1) End Function ts:TTileset=new TTileset etc... ++START DRAW LOOP++ DrawTile(tile, x, y, 1, 0,0) ++END DRAW LOOP++ |
| ||
That's about as good as it gets. Are you having and render speed issues? |
| ||
MGE, i render realtime: 19*18*9 times, *FPS. I dont have speed issues, but it runs when using the GLMax2Ddriver at 70+ FPS. when not using the GLMax2Ddriver but the DX7 or default graphics i get arround 50FPS. And that is just the map. Meening, if i add the rest of the game im afraid i end up running at 35 FPS. And im on a 2GHZ celleron with 712 (or something) MB Ram. But even on my P4 2.8 HT it ran like that, well.. a bit faster i beleive... but still. One of the ideas i have is, because the RPG world is virtualy unlimited, to devide it up zones (which i actualy have done already) and pre-render each zone into a single image. Then i just display this single image with 1 draw command isntead of having 19*18*9 draw commands in realtime. So, to prerender the zones, is really a good idea. Now, the zones also have waterfalls, moving trees and quite some animation, but i could just draw that on top of it, and put a filter so it wont draw it on the base map. Doesnt that sound like a plan? :-P I hoped to save the buffer to a TImage, but BlitzMax doesnt have buffers... does it? So that is why i was looking for the most efficiant way to draw alphachanneled PNG tiles from the tileset, into an image. EDIT I just had an idea, wouldnt it work to render the map as i do above, the capture the window using Window:TPixmap( x,y,width,height ) or something? Then save that as TImage? In total i would then need 9 TImages for the center zone and surrounding zones. Then, when the player leaves a zone, it renders the 3 new zones, and loses the 3 old zones. |
| ||
Ok. I now found out its kinda required to prerender the maps as collicions work for images. Meening if i do not pre-render the zones i will need to setup collisions for each tile. -edit- I finaly found a solution: http://www.blitzbasic.com/Community/posts.php?topic=74153#828522 |
| ||
Ok, for those interested here is some testing results: Running 18*19*9 times IN REALTIME the DrawImage command with 32x32 tiles (TImage) is FASTER (+-50FPS faster!!) then to pre-Render a single 608x576 Timage, using a Pixmap. Drawing a TPixmap instead of an TImage is even worse, thats gonne cost ya arround 80FPS. I dont understand why, but the numbers don't lie. |
| ||
so prerender, make pixmaps for each collision layer and load them into timages. then drop them in order. onto teh backbuffer, flip |
| ||
and BMAX is double buffered, thats what flip is all about |
| ||
so prerender, make pixmaps for each collision layer and load them into timages. then drop them in order. onto teh backbuffer, flip Well, as i said: Running 18*19*9 times IN REALTIME the DrawImage command with 32x32 tiles (TImage) is FASTER (+-50FPS faster!!) So i dont see why to prerender the pixmaps and convert them to TImages. |
| ||
oh i misinterpreted your intent there. But do you plan on smoothly scrolling the map? Dropping tiles makes that difficult. a single timage can be panned around easily. But this is actually something im working on so i dont know of there is a better way. |
| ||
Seriously, don't get caught up in the rendering loop at this time. An RPG world is alot more complex than typical games. If you're in this for the long haul, you'll have more complex issues to deal with. If you're getting a frame rate of at least 30fps on decent (not the best) hardware, I say move on to the next phase. Keep it simple until you need to complicate it. ;) Forget Pixmaps. (I think I mentioned that.) What you're doing with the individual tiles is the standard. But ofcourse ONLY render the tiles needed on screen, do not render the entire map off screen. ;) |
| ||
MGE, we speak the same language here. That is exactly what i did, and now after serious testing and having tried different aprouces i strongly recommend anyone making an RPG, todo it this way. That is, render all individual tiles using DrawImage, however, dont draw more then you need. (no offscreen rendering) It is also the most memmory efficiant solution. @Schragnasher, i also have scrolling! Add to your drawtile function an X and Y offset. Using SetOrigin, or even a streight substraction on the DrawImage command, you can get pixelsmooth scrolling. Please do take in mind that you will need 1 extra row and column for this. as the old column scrolls out, it has a new one to scoll in. In my code above these parameters are known as oX and oY. |
| ||
I'd suggest trying to cut down how many iterations you go through to render. If you have 4 background layers 1 player layer and 4 foreground layers, then do 3 iterations instead of 9. You render the layers together block by block. for y = num1 to num2 for x = num3 to num4 Layer1(x,y).Render Layer2(x,y).Render Layer3(x,y).Render Layer4(x,y).Render next next for y = num1 to num2 for x = num3 to num4 Layer5(x,y).Render next next for y = num1 to num2 for x = num3 to num4 Layer6(x,y).Render Layer7(x,y).Render Layer8(x,y).Render Layer9(x,y).Render next next This method speeds things up quite a bit. You will need to modify it a bit when you throw enemy in. I'd recommend a matrix layered out detailing where they are then render them in paralell with the layers as such: for y = num1 to num2 for x = num3 to num4 Layer1(x,y).Render Enemy1(x,y).Render Layer2(x,y).Render Enemy2(x,y).Render Layer3(x,y).Render Enemy3(x,y).Render Layer4(x,y).Render Enemy4(x,y).Render next next |
| ||
computercoder: That would probably be a little faster if you weren't rendering anything. But the bottleneck is usually the rendering speed not the logic speed. At least with today's faster cpu speeds it is. I did similar coding optimizations with my engine, and it really wasn't worth it to code like that. It make's scaling the code a little more complex and probably is not worth the bang for the buck. ;) |
| ||
Here, this is how i have done it:'Draw map For Local layer:Int = 1 To 4 DrawLayer(World, WorldX, WorldY, WorldZ, layer, player.x, player.y) Next 'Draw player player.Render(Int(player.x * tween + player.tx * (1.0 - tween)), Int(player.y * tween + player.ty * (1.0 - tween))) For Local layer:Int = 6 To 7 DrawLayer(World, WorldX, WorldY, WorldZ, layer, player.x, player.y) Next 'code goes here if player happens to be standing on a bridge (2nd level) For Local layer:Int = 9 To 9 DrawLayer(World, WorldX, WorldY, WorldZ, layer, player.x, player.y) Next talking about it, i also want to add shadows. that would give me another bunch of layers :S ![]() the problem is tough, that the trees are part of the background, so i cant render shadows dynamicly. Anyway, i will also have movable trees, these are objects. |
| ||
The point is the number of iterations to process it. Every iteration does take time away from the next process you need done. I've done this design with my tilemap editor and its actually faring much faster than it was before. (visit http://www.computercoder.org - 2D World Designer, still a WIP) I understand the render to screen takes time as well, just shaving off as much as possible where I can. I can see where it doesn't scale well either. :) This method also works well when you are not using accellerated gfx APIs like DX or OGL. GDI for instance. Anywho... There's several ways to skin a cat right? ;) |
| ||
You're still rendering each layer; completely before moving to the next layer. Which in reality is still 9 iterations only now its within another layer of an iterator! What I was explaining was rendering each tile starting at bthe upper left (x=0, y=0) and render each layer for that cell. then move to the nest cell, and repeat. When you get done with layers 1 - 4, then do the player layer, render the player on top if it. Proceed to the foreground layers finishing up like you did with layers 1 - 4. So basically the DrawLayer routine you have will be more a DrawTile. you'd need to loop through the x and y coords instead of the layers. |
| ||
Do you have a way to show the FPS? i downloaded your demo. |
| ||
In that demo there is not. I could put one in for you if you'd like. |
| ||
Yes please :) And can you enclose here how many layers you have used? The reason i use 9 is because i will have: > baseground > Grass/flowers n stuff > Sheets n stuff > Tables/chairs n stuff > plates n stuff > food n stuff > Bridges/treetops n stuff > items on bridges > overlapping player 2 > obstacles A > obstacles B |
| ||
Hey Goldstar, looks nice :) |
| ||
Ok... I'll see what I can do tonight when I get home... It'll be a bit. I have 8 layers. I figured everything I need should fall in that range :) BTW: It does look nice Goldstar! |
| ||
> baseground > Grass/flowers n stuff > Sheets n stuff > Tables/chairs n stuff > plates n stuff > food n stuff > Bridges/treetops n stuff > items on bridges > overlapping player 2 i would say that many layers is WAY to many and unnecessary. Id take a closer look at how many you actually need.i mean are you going to have bridges over top of plates? Why would plates and bridges need to be on different layers? If you limit your code to certain layers you can easily limit your graphics production. |
| ||
make plates objects not tiles |
| ||
Uhm... the layers aint rendered. Only what is visable is rendered. So basicly, if there is 1 plate only, that only plate is rendered. As for data readings... i wouldn't be concerned. It reads bytes from banks and that is very fast. I tried rendering 9 layers without tiles, and 1 layer without tiles, FPS stays the same. Maybe 1 FPS change... |