Map generation #4.5 – tidying up some ends

In my last post about this map-making process, I seemed to have left off at the part where the image itself is generated in its own separate program. Converting this image into a matrix for use in Graff was relatively straightforward. Pygame’s surfarray module allows one to access a surface (the screen) and treat it as a matrix of color values. From there I pulled out the color, used a dict datatype to convert that color into a tile type, and then write that into a matrix for use with the Graff; that wasn’t much of a problem.

However, one glitch I’ve noticed is that often the map would have some holes in it–it seemed like the algorithm would skip over a tile, perhaps because it couldn’t find a properly-fitting tile, so sometimes you get things that looked like this:

glitchy tiles

As it turns out, that was the case. I simply did not make enough tiles to cover each possible combination. After thinking that I’d have to make a mind-boggling number of additions to the 6×6 tile pieces I already have, I edited the code so that if the tile it needed could not be found, it should spit out that key combination and then I’d see where that would take me. Altogether, only about 30 “impossible” combinations of tiles ever seemed to come up, so I just added those extra ones onto the tileset.

After doing that, the results are much cleaner. Some glitches still remain (mainly I missed a few combinations, it seems), and I’ll probably adapt this to work with a smaller scale (say 3×3 instead of 6×6) or make changes to it to develop other areas, but I think I’ve just about exhausted the usefulness of posting about this process.

Still a little glitchy, but better!

Oh, there is also the problem of the map not always being one complete piece. I still haven’t decided in what way I’ll solve that one yet, but there are some more interesting questions about Graff that I think I need to find an answer to first.

Brief update.

Got some feedback on how the player movement worked and so I decided to switch it to the original idea I had–when the player gets too close to the bounds of the screen, then the screen recenters itself on the player, as opposed to re-centering every single time the player moves. Likewise the grass is now drawn so that it looks “attached” to the tile, instead of before where the grass appeared to just float under the screen like an odd parallax effect (see image; night sky is what the grass looked like if anyone hasnt tried out this thing).

Also, I’ve worked in the map generator into the game itself. It looks a bit weird, to be sure:
ingame map generator
But I feel like currently that’s due to tileset issues and not necessarily the code. Don’t mind the odd looking minimap, still have a few kinks to work out.

Also, now I’ve got a way to output screenshots (properly labelled to boot) into a ‘screenshots’ directory when you press the printscreen key. Saves time when I’m on Windows, thats for sure.

A scrolling tile map you say?

So, my blog stats spiked today.  I’m not sure if it’s a fluke, bots, or my using post tags having some sort of effect, but in either case this wordpress stuff says something about top searchings being for a scrolling tile map.  Whether it was just one guy who searched for it, as long as it lets me procrastinate on getting real work done on this, I guess I’ll post about how I actually got scrolling to work with pygame.

First of all, I’ve got hidden away in Scene.py a class called Tile (or Maptile or something to that effect).  Ultimate it’s a 32×32 pygame sprite that, for now, has stored on it just an image and its rect.  During map intialization, the class that holds the overall Map ends up intializing a 32×24 grid of these things, and sets their rects all to be (X Y 32 32), with XY being the topleft corner coordinates on the pygame display window.  Why 32×24?  My game window is 1024×768, and if you divide those by 32 (the size of each tile), thats how many tiles you break the scene into.

Independent of this, I have a separate piece of code that basically makes a giant 70×70 2d character array representing the gameworld.  Well, technically it uses Python’s Numeric module and so it uses numbers instead, but eh.  So the array might look like this:

[[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,1,1,1]]

Where 1 = wall, 0 = floor.

To get scrolling action going, ultimately I have a function called GenerateView, with it taking an input of XY coordinates representing the topleft coords of the display window.  First, this function clips off the topleft coords if they are out of bounds–say the player is already in the topleft and generate view gets called; if we want the player centered, and the player is already at (0,0), then using the above schema it would take an input of (-1,-1) and try to access nonexistant tiles to draw from!

So once the coords get clipped to within proper values, it’s simply a matter of reading the character array and starting from the topleft coords, reassign each Tile() object the proper image based upon the value of that particular entry in the 2d array–oh, and reassigning the worldcoordinates, too.  There’s a little bit more to it for dirty rectangle updates, and that’s why I rewrote the function in the first place, but yeah. It’s right around here where I’d write in something for remembering where items and dropped loot are as well, but that’s not in yet.

Now that I’ve described that, the actual fun occurs within the Player class.  Put simply, every time the player moves in a direction, it checks to see if player.x and player.y are too big or too small–whatever values those are, are arbitrary.  If so, the above GenerateView function is called, the player picture gets moved back to the tile he should be on, and that’s that.

So to get constant scrolling in a turn-based tile system such as what I’ve got, GenerateView can be called any time the player leaves the center tile by having narrow bounds for player.x and player.y–if the player holds down the right arrow key, every update frame moves the player, it’s then found to be past the boundry each update, and then GenerateView is called each update to recenter the view on the player, giving the effect of scrolling.  In practice and with dirty rects, I only lose about 4 frames per seconds when I have constant scrolling, but of course that’s in a currently half-finished prototype that will probably be bulky and overloaded when/if I get done with this thing.  🙂 [update from the future: there really hasnt been much, if any, of performance issues so long as you code somewhat efficiently]

What’s one advantage to having GenerateView set each tile according to the 2d array that’s not related to scrolling?  If I want to modify the map (say with digging, spells damaging/converting tiles, whatever), all I have to do is change a cell in that 2d array from a 1 to a 0 and call GenerateView again, and everything else is taken care of.  🙂

Don’t forget to check out the front page for the latest!