Tile-based landscape frenzy!

On the First day, Niriel created the Entities. And the Entities were floating in the empty void. And Niriel got bored and said “Let there be tiles all over the place”. And there were tiles, and the Entities could walk on the tiles, and everybody was pretty much happy, except Entity number 3 who’s always complaining.

First tile map in infiniworld.

Two entities walking around in an area. Notice that the area is centered on one entity (the one controlled by the player at that time). The color of the tiles correspond to the nature of the floor (rock, dirt, grass, sand, shallow water, deep water).

Download.

  1. Go there : https://github.com/Niriel/Infiniworld,
  2. click on the big gray “Downloads” button (right of the page),
  3. choose “v0.0.3”.

Play.

Many many keys !

  • Enter/Return: create a new entity.
  • ; and ' (semicolon and quote): take control the previous/next entity
  • \ (backslash): create a new area.  But it’s useless in this version since the areas created that way don’t have tiles.
  • [ and ] (left and right square brackets): move to the previous or the next area.  Note that the game starts in the area None, which means that no area is displayed.  You must press [ or ] to start seeing something.
  • . and / (period and slash): teleport the selected entity to the previous or the next area.
  • W, A, S and D: move the selected entity.  Note that diagonal movements are allowed, and in that case you are not perfectly lined up with the tiles: you moved by square root of two in x and y.
  • Esc: quit. You can also click on the “close” button of the game window.

The controls are not awesome yet. They’re hard-coded for a US keyboard, and not even US international: the quote key doesn’t work for me because it waits for another key after that in order to put an accent on it. But hey, that’s a start.

The little new details.

  • The window has a title now. I think there may be a bug in my version of Ubuntu preventing me to set the title after creating the window (it only changes the name in the task bar). So I set the title before creating the window and hop, it works.
  • FPS counter. Since the game loop authorizes a max of 60 FPS, that’s what I get. Actually the picture shows 59 FPS, it jitters between 60 and 59. Maybe because of the inaccuracy of time.sleep?

The big things.

There are two major modifications to the code:

  • The world can have several areas.
  • Areas have tiles.

When you run this demo, a world is generated.  It contains three areas.  Each area contains 16384 tiles (128 by 128).  I chose this relatively high number to challenge myself and make sure I could render the area fast enough.  If I couldn’t, I would give up on pygame and python.  Fortunately I am still in my 60 FPS budget which makes me very happy.  My first two implementations crashed me down to 5 FPS:

  1. The first implementation was the straight-forward brute force: “Ask pygame to display everything, pygame is smart enough to realize it has nothing to do 95 % of the time, right ?”.  Actually it wasn’t that bad on small maps, as this method was faster than my second implementation.
  2. The second implementation just added a line to the first one with a little test in it:  “For each tile, check if it intersects the view, and if it does then draw it”.  The result was horrendous since I was processing 16k tiles.  Looks like pygame.Rect.colliderect() is not super fast since I got a better performance without checking for smaller maps.
  3. I threw that away.  Since I know in advance the min and max world coordinates of my View, I just have to look for the tiles that are within these coordinates.  And it’s fast, and scales well.  I could have done that in the first place but it’s a bit more code to write and maybe the other methods would have been okay.

Python does not have two-dimensional arrays so implementing the TileMap was not straightforward.  The first idea that comes to mind is to use a list of lists.  I didn’t like it because:

  • it is a bit hard to guarantee that all the lists have the same length;
  • it’s a mess to resize, you have to extend or shrink and shift every list;
  • I don’t like to write my coordinates between brackets like tiles[x][y];
  • I cannot have negative indices ! Negative indices will probably be very nice to have when the world is procedurally generated, as I do not want to impose arbitrary barriers on two sides of my map.

And then I realized we’re in the marvelous world of Python and that we do not actually need rigid two-dimensional arrays when we have dictionaries and hashable tuples!  So a tile map is stored in a dictionary: keys are (x, y) tuples.  It is fast, and has none of the drawbacks listed above.  Sold !

The TileModel object is very simple, it just contains a nature for the floor, and a height for said floor.  If the height is 0 it means you could walk on it.  If it’s 1, it means it’s raised, like a cliff, and you can’t go. I should have named it “elevation” instead of height.It is not a 3D game, and I must resist the temptation of allowing the player to stand on high tiles. That will be for the next game. Also, tiles don’t block the movements of the entities yet, since there is no physics engine; the entities are even free to run out of the map.

Next step: Physics !

Stay tuned to learn how I include string theory into the physics engine!

Advertisements

About Niriel

Cynical utopist who likes red wines from Languedoc and playing Minecraft instead of working on his own game.

Posted on 12/08/2011, in Infiniworld and tagged , , . Bookmark the permalink. 4 Comments.

  1. Following the evolution of the game is exciting.
    However in the version v0.0.3, the world stays grey (no entities, no tiles). In the previous version, I could see and move the entities. This may be relative to the display of pygame on my Mac.
    I’m curious to see how the string theory will be implemented in the game.

    • The view does start gray indeed. That’s because the area displayed is None by default until a ViewAreaEvent is broadcast to tell which area we should view. None is not an area object, it has no entities, no tiles, so it’s not displaying anything but the default gray background. You can look at the real areas by pressing the [ and ] keys. Does the view remain gray after you pressed these keys ?

      Likewise, Entities created with the Enter key are in no Area. They have to be moved to an area to be visible (semicolon and quote keys on a US keyboard).

      I hope it works !

      • Thanks! Yes, it works now. Actually playing with a non US keyboard when you are not sure of what should happen exactly is a real mess. I may write a kind of configuration file to customize the key bindings.
        The entities move smoothly amongst the colored tiles now. Cool!

        • Woo ! Configuring the keys is something we need. If you want to contribute it’s cool :).

          Check out this commit:

          https://github.com/Niriel/Infiniworld/commit/11be6e7f63d3a6b263534e627c0b8c2fc6c35422

          It has collision detection and response with elastic collision.

          I suspect that commit has a bug for very fast moving objects. The bug is that too many EntityMovedEvent are posted for fast-moving objects. That’s not a problem for now but it will be one when I implement frame interpolation (we render 60 frames per second but update the physics only 20 times, we need to interpolate). Anyway, in that demo you cannot even move that fast.

What do you think about it?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: