Advertisement

Tiling terrain

Started by May 14, 2010 09:08 AM
4 comments, last by Duck123 14 years, 7 months ago
Here's a screenshot from my game when it's running: All of the art here was made with Blender. 3D modeled protagonist, posed in Blender, animated in Blender. Map tiles modeled in Blender, grass is a Blender particle system. And so on. They're all pre-rendered and then used as sprites in a Python/Pygame engine I've written -- so at least that part isn't Blender. There are 20 different kinds of map tile, and each currently has two variant shapes; adding more means making new models in Blender and rendering them (fortunately, the render/crop/resize work is automated by some scripts I wrote). I'm not terribly happy with how crude the terrain tiles are in comparison to the protagonist model. However, I can't think of any approaches that would make a decent tiling terrain setup that wouldn't require me to be a pixel artist, which I'm really...not. It took me several years to get to the point where I was generating usable game assets with Blender, and at this point I'm not really interested in investing a similar amount of effort just so I can get nicely-tiling terrain -- given that, beyond making art tesselate, I'm not certain what there is that pixel art can do (in this art style) that I can't do with Blender. The only approach I can think of that would make at-all decent-looking terrain would involve making lots of "meaningful" tiles (boulders, pipes, panels, buried skeletons, etc.) and filling in the map with those instead of repeating squares. But that makes for very busy-looking maps, and of course it's a lot of work. Any other ideas?
Jetblade: an open-source 2D platforming game in the style of Metroid and Castlevania, with procedurally-generated levels
I don't know about the programming side of it, but the art side of it is pretty easy to create tileable textures - you just use anything, and run the offset filter in photoshop, then clone the edges - obviously some things will tile better than others, there are some great tutorials explaining this out there - google away.

Its so easy, you'll facepalm when you really sit down and do it :)
Advertisement
I typically use procedural methods for creating terrain tiles. I've created a library that works with Perlin noise functions that map to seamless 2D images, upon which I then perform various operations to composite a final color map. Even as chiefly a programmer, I can get pretty good results.

The largest issue I have with your tiles is the seams between them. I'm not sure how you are generating them, but you might have better results if you "stitched" the edges so that bump-map information as well as color information will tile seamlessly, thus ensuring the tiles sit next to one another without the black seams.

I outline a few procedural methods in my journal (you might have to go back a ways, updating is sporadic) if you are curious. You can also google for libnoise to try out some procedural methods hands-on.
The tiles are generated in Blender; basically I'm making models of cubes with whatever special surfaces I want to apply (e.g. a layer of grass, or some sheet metal), then rendering the results and displaying them in-game. The result is a tile with an "exterior" or "surface" and an "interior", with the interior being the part that is visually not tiling nicely. The issue I have with manual stitching is that I have over 20 different terrain types, and I want to be able to have variants of each so that the exteriors aren't always visually perfectly flat; that means making a massive number of interiors that all tile nicely.

An alternative approach would involve drawing the exteriors and interiors separately. Then the interior would just be "pull this 50x50 segment of a tiling texture out and blit it down". I suppose that would probably work pretty well, at the cost of having a special kind of object in the game that doesn't draw like other objects.
Jetblade: an open-source 2D platforming game in the style of Metroid and Castlevania, with procedurally-generated levels
Quote: Original post by Derakon
The issue I have with manual stitching is that I have over 20 different terrain types, and I want to be able to have variants of each so that the exteriors aren't always visually perfectly flat; that means making a massive number of interiors that all tile nicely.


This sounds like an ideal situation for procedurally generating your tiles. It is possible, given a properly constructed library, to build procedural generators that create a surface of specified characteristics that tiles well with itself. It is also possible, using certain masking and blending operations, to tweak the process so that alternate candidates are created: tiles that tile well with one another, but whose patterns vary inside the seamless borders to avoid obvious repetition. Once the appropriate functions are setup, it is merely a matter of tweaking the parameters via script or some other interface, and churning out as many alternate tiles and tile sets as you need.

Here is an example. It is written to work with my own personal library:

fr1=C4DBasicFractal(FBM,GRADIENT,QUINTIC)  -- Setup a noise fractal, fBm variant using Perlin's gradient noise, 4 dimensions to feed the seamless mapperfr1:setSeed(randInt())  -- Seed it randomlyad1=CMap4D_2D()       -- Adapter to map a seamlessly tiling region from the fractal function to a 2D greyscale bufferad1:set4DSource(fr1)fr2=C4DBasicFractal(BILLOW,GRADIENT,QUINTIC)  -- Another noise fractal, this one Billow variant.fr2:setSeed(randInt())ad2=CMap4D_2D()ad2:set4DSource(fr2)curve=CMap2D_RGBA_Curve()  -- Setup adapter module to convert a 2D greyscale map to a color map via a color curvecurve:set2DSource(ad1)  -- Attach it to our first fractal adaptercurve:setPoint(0,CRGBAf(95/255,45/255,6/255,1))  -- Setup a simple color curvecurve:setPoint(1,CRGBAf(188/255,112/255,63/255,1))bump=C2DBumpMap()     -- Module to create a bump map from a 2D greyscale input modulebump:setLight(1.5,3.5,-1.5)  -- Set a light direction vectorbump:setSharpness(1)bump:set2DSource(ad2)  -- Link it to our Billow fractalmult=CRGBA_Multiply_2D()   -- Adapter module to scale a colormap by a greyscale bump mapmult:setRGBASource(curve)mult:set2DSource(bump)-- Setup the seamlessly looping ranges for the 2 basis noise functionsad1:setLoopRanges(0,4,0,4)ad1:setMapRanges(0,4,0,4)ad2:setLoopRanges(0,2,0,2)ad2:setMapRanges(0,2,0,2)-- Setup an output module to save the resultout=COutputModule(256,256,RGB)out:setRGBASource(mult)out:eval("a.tga")  -- Evaluate and map all functions and output the result to file


In this snippet, I set up 2 fractals based on Perlin's gradient noise, and map them seamlessly into 2D buffers. I use one to map a color curve, and the other to create a bump map which is used to scale the color map. The result, with some tweaking to parameters, ends up looking something like:


Now, I could add an intermediate step in the process that generates a mask. This mask would be full white (1) at the edges, and blend to some arbitrary pattern of black, white, and all values in between in the center. Generate a second set of fractals and use the mask to blend between both sets for a dirt tile that tiles with all others that use the same initial pair of fractals for the edges, but which has variation in the center coming from the second set of fractals. Then, set up a script to seed the interior fractals, and evaluate any arbitrary number of variants that all match up together.

Add to that the capability to setup further functions, modules, turbulence generators, patterns, and masks to generate different patterns and tile types, as well as to create smooth (or rough, as you require) transitions between different tile types. If you have a wide variety of basis functions, patterns and so forth, you can create literally infinite numbers of tile variations, some very complex indeed, yet easy to tweak the parameters to modify the output to suit your taste.

The neat thing (to me) about a procedurally based system is how quickly I can get good results up and running. Total time spent writing the above script was about 2 minutes, plus a minute or two of parameter tweaking, and it takes less than a second to evaluate a 256x256 rgb image. Generating a set of 50 would take a mere minute or two, as opposed to the minutes if not hours spent modeling the features in Blender.
U should make it full 3D. That might slow the game down a bit but just download a better graphic thing. But it will make the game better.

This topic is closed to new replies.

Advertisement