Tilesets & RPG maps

BlitzMax Forums/BlitzMax Programming/Tilesets & RPG maps

Trader3564(Posted 2008) [#1]
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?)


Schragnasher(Posted 2008) [#2]
i think your looking for a pixmap


Trader3564(Posted 2008) [#3]
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 :)


Bremer(Posted 2008) [#4]
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.


MGE(Posted 2008) [#5]
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. ;)


Trader3564(Posted 2008) [#6]
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++


MGE(Posted 2008) [#7]
That's about as good as it gets. Are you having and render speed issues?


Trader3564(Posted 2008) [#8]
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.


Trader3564(Posted 2008) [#9]
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


Trader3564(Posted 2008) [#10]
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.


Schragnasher(Posted 2008) [#11]
so prerender, make pixmaps for each collision layer and load them into timages. then drop them in order. onto teh backbuffer, flip


Schragnasher(Posted 2008) [#12]
and BMAX is double buffered, thats what flip is all about


Trader3564(Posted 2008) [#13]
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.


Schragnasher(Posted 2008) [#14]
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.


MGE(Posted 2008) [#15]
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. ;)


Trader3564(Posted 2008) [#16]
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.


computercoder(Posted 2008) [#17]
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



MGE(Posted 2008) [#18]
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. ;)


Trader3564(Posted 2008) [#19]
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.


computercoder(Posted 2008) [#20]
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? ;)


computercoder(Posted 2008) [#21]
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.


Trader3564(Posted 2008) [#22]
Do you have a way to show the FPS? i downloaded your demo.


computercoder(Posted 2008) [#23]
In that demo there is not. I could put one in for you if you'd like.


Trader3564(Posted 2008) [#24]
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


Czar Flavius(Posted 2008) [#25]
Hey Goldstar, looks nice :)


computercoder(Posted 2008) [#26]
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!


Schragnasher(Posted 2008) [#27]
> 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.


Schragnasher(Posted 2008) [#28]
make plates objects not tiles


Trader3564(Posted 2008) [#29]
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...