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:
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!