Game Development Community

Ideas based on TileMap Chapter

by David Everhart · in · 12/09/2008 (9:49 am) · 12 replies

I loved the chapter on programming with tilemaps. I am testing out a new approach to implementing my game, kinda like a graphical roguelike using the tilemap approach (Pixel artists doing static sprites and portraits are MUCH more affordable :) ). If I have say a region or dungeon map that is say 500x500 tiles, it seems like that may be a bit much to put on one tile layer. So i have two ideas, and wanted to see what everyone thought.

1) Create 50x50 tilelayers, and break apart my world into chunks (defined in XML). Load each tile layer as they cross boundaries or load as they come within a certain threshold.

2) Create a 32x32 tilelayer, and keep a 35x35 chunk of world loaded, and shift the tiles as needed. For example, if they go over 1 horizontally, it would delete the first column, shift the tiles to the left by 1, then load in the next column from my world xml.


Any thoughts or ideas are appreciated.

#1
12/15/2008 (11:56 am)
I have decided to go with option #1. I will use 100x100 tilemaps, and as they approach within 2 rounds of a characters move points ,I will background load the other TileLayers as needed. Consequently, Can I do a sceneload on a new thread?
#2
12/15/2008 (2:44 pm)
Crap! My nice long response was lost for some reason. :(

Short response is that I think option 1 is the best and will result in more predictable garbage collection, since you can call GC.Collet() as you move from one region to another (if needed). Otherwise, the GC could kick-in at any unexpected time and bring the game to a stop. Also, another issue is in loading the XML, so look into ways to compile it as an .XNB with XNA's XML content imported. I'm still meaning to look into that sometime - I think Torque X should have a custom .txscene content importer.

As for a sceneload on a new thread. I'm pretty sure that you can, but I've never tried it. I don't see why it wouldn't work as long as you block competing tasks (such as unloading) that might happen at the same time. But it should work just fine.

John K.
#3
12/15/2008 (8:14 pm)
Doh, that sucks, happened to me after writing a nice long blog, now I use our good friend notepad as a copy until it posts :) Hmm, that is a good idea on the xna xml content importer, Ill check into that. I did some preliminary testing with loading and unloading layers via sceneloader,and it seems to work well. Option #2 is how UO does it, you can actually see the tiles on the edge flash sometimes.

Ill test out the background thread in a few days. On my first attempt at Arillian, I actually loaded all the animations in a background thread (kicked off in the pre begin run function, forgot its name) while the game loaded up. Since the animations took upwards of a few seconds, and the game started instantly, it seemed to work ok.

Here is an example of the maps I am planning on making (just picked up the dundjinni software) for the 100x100 approach:
Map Sample
#4
12/15/2008 (11:24 pm)
Ah, you never mentioned Dundjinni! That is a fun product to play with. Now I see your concern about the load, because with all of DJ's beauty, comes big load times for the rich detailed tiles. I can see your option #2 working for a C++ game, where you can hang on to a small pointer reference for each tile, but I'm not sure C# is up to the challenge. I just don't think that the tiles can be cloned fast enough to keep up a smooth flow. You might need to go with option #1 with the background loading. Unless....

Hmmm....

How about an option #3... a shader! Let the GPU do the drawing for you, directly to the backbuffer. That way, there's no CPU overhead and no worries about C# and garbage collection, etc. Insteads create an Effect shader that handles all the tilemap rendering. All that your CPU would worry about would be managing the collisions. Need to think about this some more.

John K.
#5
12/16/2008 (7:07 am)
Hehe, Dundjinni makes pretty maps :) I have a pixel artist working on some monsters, but i will use programmer art till its done. I thought about doing as you mentioned, writing everything to the buffer then flushing it when its done. When I was learning MDX, that was the approach I first learned about, kinda like a scratchpad to do multiple passes or whatnot, then dump to screen. hmm, maybe I will have to dig some of that old code out!


Update: Looks like XNA handles the back buffer swapping, and the Draw actually writes to the backbuffer directly from what I have been reading online. I am curious about this effects shader now :)
#6
12/16/2008 (5:24 pm)
Hi, I'm curious about the idea of an Effect shader (is this a pixel shader?), since I know nothing about shaders and how this could help, what would the general concept be?
...a bit like this? The shader which runs on the GPU is receiving information about coordinates on the tilemap and simply grabbing and drawing the correct tile image data directly to a buffer as they come into view? (as determined by the shader)
If it is on the backbuffer does this count as a "pass" ? And is it generally the idea that the TileLayer has this Effect shader on it, and when drawing a frame of the game it says, oh there is a certain shader here, lets do this, and it draws whatever it is using the GPU very fast and says ok I'm done and continues with whatever else is going on when drawing to the screen ?

I guess my next question is, if using an effect shader would be faster for drawing tile maps.. why isn't that already the method for drawing them? :) does it raise compatibility issues since it is relying on GPU abilities?
#7
12/16/2008 (9:20 pm)
Essentially, you're right on - perfect. That's exactly how it would work and it does count as a pass on each frame draw. But the best part is that the GPU is specifically designed for this kind of work, compared to a general-purpose CPU which has to work harder at it.

The reason, that Torque X doesn't just do this is because David is looking for something pretty specific - drawing HUGE tile layers. Instead, Torque X sacrifices some performance for a lot of flexibility and control. For example, the shader solution is going to be an output-only solution. The rendering details are sent to the shader and the shader draws, whereas Tilemaps that run on the CPU can return back to the game code a lot of properties and perform broader functions.

Also since the GPU has a lot of memory and speed, you can probably just point the shader to one single texture file that has all the tiles on it and let it cut out and render the specific tile it needs. I don't think there will be much compatibility concern, since its all PixelShader 2.0 compliant HLSL.

And this is still all just concept, it might not work.

John K.
#8
12/17/2008 (4:39 am)
I went and read up on the HLSL chapter in your book, as well as this Reimers XNA Tutorials. Based on your sample HLSL fx code(page 363), it looks like the input has a texturecoordinate that is passed to the vertexshader, which then just passes it to the pixel shader.

If I were to implement this in code, would I create a link to the texture in the vertexshader, and then in the outputstructure just define texture coordinates?A tile map , with just collisions could render on top of it, with some static sprites (like characters), while the vertex shader is handing off a portion of a large image to the pixel shader. I would guess the vertex output would need to be updated as the camera is moving. Am I in left field, this is all new to me :)
#9
12/17/2008 (8:44 am)
I think you're pretty close. You probably need to send the shader the texture with all the tilemaps, some value to know which tile to render, and the screen coordinate to render it. This means doing some translation from T2D's World coordinates to screen coordinates. The shader will also need the camera's position and lighting vectors for bump mapping. But this sounds like the right direction.

John K.
#10
12/18/2008 (9:43 am)
Hmm, the example in your book uses a t3dscenegraph, as it seems all shader examples seem to be in 3d. In Torquex, for T2d, it would seem the TileLayer already has its own _createandfillvb method based on the camera. I believe the T2DTileLayer already populates the vertex buffer, but how would I tie in a shader to that tilelayer to override its rendering? Sounds like a core class change possibly.

I did test using 4 1500x1500 images in a square configuration, then putting a tilelayer underneath it with only collision areas having a white tile in order to set collisions. That did not work as my test srpite I was moving around did not collide with the tile layers collision, even though the coolides with was set to the object type of the tiles objectype. There was no discernable lag or long load times however.

Ill continue testing around.
#11
12/19/2008 (11:10 am)
Hey John,

What do you think of using a dyanmic vertex buffer to store all the vertices, and then updating the indexbuffer per render for only those that can be seen? Or is my understanding of vertex and index buffers off? I have been thikning of creating a derived class from T2DTileLayer and modifying the render peice. I am still going to try the shader peice, but will do it in XNA since I am not too familiar with Torquex and application of shaders in a T2D space (I assume it has something to do with T2Quad).
#12
12/21/2008 (8:15 pm)
Just a quick update, I think I have found a solid solution using XNA, so will be focusing on that. I am going with the old tried and true show only what you need to of the map (Nick Gravelyn has some excellent videos on it), using custom non torque tilelayers. This will allow me to build huge tile layers if needed, though I suspect 150x150 will be my largest. This means I will probably build my own custom tile map editor as well specific to my game. I appreciate the responses.