9
\$\begingroup\$

About

These are actually two questions in one. First of all I am looking for a way to efficiently store large amounts of tile data. The other aspect deals with querying the data set and displaying tiles. Let me give you some background first.

We are making a browser based multiplayer tycoon game using the CraftyJS library to render it to Canvas. In the background of the GUI we're running Yii Framework on PHP and it all connects to a Python random map generator and game engine.

This is how the first rough map render looks: https://i.sstatic.net/hqdLn.jpg

Storing the map data

The game world is randomly generated each time the game starts. The size is 100x100 hexagonal tiles for each player. That means that for a three player game, there are 90.000 tiles created. Currently I just create a JavaScript array from which I render the map.

This works fine for rendering, but for any kind of interaction with the map we need to store which player owns the tile, what kind of structure is build on top of it, what's it's current price and so on. At first, at least for the prototype, we wanted to use MySQL, but after some testing, it's not exactly as fast as I'd like. Maybe an object store like MongoDB would be better suited for storing tile data instead of an SQL table. Or maybe something else?

Displaying the map

Another problem I see is moving around the map. Currently I'm creating Crafty entities for each tile even if it's not in the viewport. This is slow, because even though Crafty renders only the ones in the viewport, it stores and possibly iterates through all the tiles on each render event. What I currently have is a drawn generated map which is very slow to load and stutters when you move around, now I'd like to make it playable.

My first idea was to load the displayed subset of tiles that are in the viewport. But when a player would move the viewport to a blank area, I'd need to query the server and wait for the response back, only then can the map be rendered. This would be fine in a native application, but it's laggy in a web game.

The way to get smooth performance from the map could be preloading a bigger subset of tiles into a javascript array and use it as a cache. The player would have a few screens "cached" and when he moves the viewport, I'd load more tiles to the JS "cache".

Am I headed in the right direction? I would love to get some more information from someone who has done something similar. I am new to game development, but have been going through a lot of sources over the last couple of weeks.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ I'm surprised that you identified MySQL as a bottleneck. What did you test to get to the conclusion that it's slowing things down? \$\endgroup\$
    – bummzack
    Commented Nov 2, 2011 at 8:05
  • \$\begingroup\$ @bummzack If he has a row per tile I can hardly see how things could not be slow. \$\endgroup\$ Commented Nov 2, 2011 at 8:34
  • 1
    \$\begingroup\$ @eBusiness Querying some thousand rows from a DB should be not a problem really. This should still be in the range of some milliseconds. Also it wouldn't be 90'000 rows, but rather 30'000 rows for 3 players (100x100 per player). \$\endgroup\$
    – bummzack
    Commented Nov 2, 2011 at 8:49
  • \$\begingroup\$ Sorry for the confusing math, there is also twice the space between the players in addition to the player zone so that they are an equal distance from each other, which makes it 90k. Querying is not a problem. Selecting 90k tiles and building a map is. But it's not a good way to do it. I will serialize the map data and use query the tiles in the db when detailed information is requested. \$\endgroup\$
    – element
    Commented Nov 2, 2011 at 11:17

2 Answers 2

2
\$\begingroup\$

Gameplay
First of all I'd like to ask you, do you actually need 10000 tiles per player? While I don't know what kind of game you are making it is generally true that large maps make long games. The largest map in Civilization 5 is 10240 tiles, and that only sorta works because you don't need to play on more than a fraction of it.

Database
You should not try to run a game like this off a database, you need to keep the data in application memory. You could use a database to back up the game. For a complete backup save a serialization of the game data, and then you can increment it by saving the orders given and then rerun those if the backup needs to be used.

JavaScript storage
As for the client, I'd say you better keep the entire map loaded, at least if you stick to the gazillion tiles having it all in a nice object tree might be a bit too much, so you should probably keep the data in a "semi-binary" encoded format. Strings work excellent for this kind of stuff, alternately, you can safely store unsigned integers up to 53 bits in a 64 bit float, stuff a lot of those in an array and I think you'll see a pretty modest memory footprint.

JavaScript visualization
While I won't say that you necessarily shouldn't use canvas, you actually don't need it for stuff like this. Set it all up as a bunch of img elements, and change the src property to display different parts of the map.

Pro tip
By the way, sometimes it is easier to share the seed used for generating it than sharing the whole map.

\$\endgroup\$
7
  • \$\begingroup\$ +1, but sadly a web-app written in PHP usually has no means to keep game-state in memory. \$\endgroup\$
    – bummzack
    Commented Nov 2, 2011 at 8:07
  • \$\begingroup\$ @bummzack, Ahh, right, I think I somehow skipped the word PHP and just read Python. Then a change of backend framework might be in order. Node.js could be an option. \$\endgroup\$ Commented Nov 2, 2011 at 8:32
  • \$\begingroup\$ I'm building a competitive transport tycoon, think of OpenTTD, a map the size of 512x512 (262k) is not that big for a couple of players. I realize that it's ambitious, but if the map is not that big, the game would end too soon. Because it's a multiplayer game I need to sync the changes to the map between players. My first instinct was to just use the concepts I know from web development and go with a datbase. It doesn't need to be super realtime. I'm going with JS visualization, because I'd like to have dynamic stuff on the map. \$\endgroup\$
    – element
    Commented Nov 2, 2011 at 9:00
  • \$\begingroup\$ Consider my answer to be some pointers, in the end you'll have to work out the performance yourself, it's a serious issue, and you may have to make some compromises. \$\endgroup\$ Commented Nov 2, 2011 at 9:42
  • \$\begingroup\$ I agree, your answer gave me a lot of food for thought. I will try to find a way to keep serialized map data in memory and keep the database as a backup. But then I have to figure out how to share changes between the players. I will get back with what I come up with after I do some further testing. \$\endgroup\$
    – element
    Commented Nov 2, 2011 at 11:24
1
\$\begingroup\$

MySQL is not slow. Most likely you are performing naïve queries or have sub-optimal indexes. NoSQL approaches like MongoDB may be faster, maybe not. Your access pattern and choice of query is what really matters here. It's possible to give advice on how to improve performance, but not without seeing what you are already doing.

The way to get smooth performance from the map could be preloading a bigger subset of tiles into a javascript array and use it as a cache.

Yes, of course. There's not much to add here - the client asks for tiles from the server, so you just have to ensure that the ones you ask for cover an area larger than the screen.

Addendum:

we're running Yii Framework on PHP and it all connects to a Python random map generator and game engine.

If you're competent with Python then I'd advise that you ditch the PHP middleman. If you run your game as a Python process then you can keep your tile data in memory much more easily and reduce the MySQL accesses significantly. It helps that Python is a much saner language than PHP, too.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .