Pulling This Together: A Height-mapped, Lit Tile Engine!DEMO4 is designed to demonstrate the advantages to having made it this far - it pulls most of the work from earlier sections into one, reasonably coherent engine. A lot would need to be done to make this into a working game, but it's a pretty good start. What this demo does is add a map structure, storing a height and lighting level for each vertex. This is something that would be extremely hard to do in a regular tile engine - the vertical element usually had to be added with clever artist tricks, and ramps had been known to give artists serious headaches. The first major change incorporated in DEMO4 is the tMapNode class. This is simply a storage class (I'd have used a struct, except that in C++ structs are stored as classes anyway so there really isn't a lot of point!). The entire class definition is as follows:
Basically, this class stores VertexHeight (an offset from the normal pixel location), a color for each vertex, and an index number designed to identify that tile's texture. In a real game, there would be plenty more - possibly including a pointer to any tiles that live above this one, giving you the option of infinite layering (something I'm fond of in this age of super-fast rendering!). Within CEngine, I've expanded the scrolling code to cope with having a map defined, rather than just static tiles. ScrollX now indicates the upper-left tile to be rendered. ScrollXOffset indicates the pixel offset by which to adjust the rendering pass. Direction has been added so that the scroller will bounce left, then right, then left, etc. I didn't add vertical scrolling, even though it would have been easy to do so - exactly the same principles apply. GameInit has gained code to initialize these variables. GameMain now also calls a new method, MakeDemoMap. MakeDemoMap is a relatively simple routine to initialize the map with random heights. It includes some tile adjacency stuff taken straight from TANSTAAFL's isometric tutorial (q.v.). It also assigns a lighting level based on the height of a vertex - higher equals brighter. This isn't a bad lighting system for a simple landscape render; in a real game, you would probably want something a little more sophisticated. Lighting systems is another topic that could easily fill another tutorial, so for now I'll give you the basics of how to apply the results - and let you experiment. Who knows, I may be talked into writing a lighting tutorial someday! GameMain includes some basic scrolling logic, now:
This is pretty basic. If Direction is 0, it subtracts 1 from ScrollXOffset. If ScrollXOffset is less than 1, it moves tile. If it has run out of map, it reverses direction. When Direction is equal to 1, it does the same thing but in the other direction! GameMain also includes a call to Demo4Render, which has gained some extra parameters. WorldX and WorldY are now passed to it, and these specify the coordinates (in tilespace) of the top-left tile to be rendered. GameDone hasn't been touched. It didn't really need to be! Demo4Render is largely the same as previous incarnations, but some changes have been made to incorporate both the map structure and heightmapped rendering. The most trivial (but important) change is that WhereX and WhereY are now reset to World coordinates rather than zero. If I didn't do this, I'd be rendering the same portion of map every frame - which is boring! Almost all of the changes in Demo4 come within the renderer's inner loop: The Vertex sx and sy assignment section has changed. The height for each vertex is now subtracted from its sy coordinate; I chose subtraction so that positive height numbers would give the appearance of hills, while negative would give valleys… it just seemed more logical to me, that way around. The vertex position assignments now look like this:
That wasn't too difficult! The neat thing is, this tiny change causes all of the textures to warp as appropriate with NO change to the rendering/blitting code! Isn't that wonderful? I like this so much that I should probably go and take a nice, long, cold drink. I remember trying to do this the hard way (2D!)… not pleasant. Enough to give me gray hair, anyway! The color code has also changed, so that it uses the stored colors rather than making you wonder if I'm on drugs. ;-) This is another pretty simple change:
Believe it or not, that's all that it took to produce a neatly shaded, height-mapped tiling engine. There are plenty of optimizations that could be applied, lots of room for additional innovation, but that's the basics. With luck, lots of vertex-shaded tile games will appear, now! (If you write something cool, and think this article helped, I'd love to get email from you!) |
|||||||||||