2
\$\begingroup\$

Currently I am working on a simple 2D platformer and I want to load a tiled map.

What I've started working on is loading the tiles using a text file. My first question is simple: is a text file the best way to load a map, and in what cases would different types of files be preferred?

I'm reading the file using a buffered reader. First of all I'm getting it to check the size of the map, then I'm using a second loop to create a byte array of that size. This is my code:

    try {
        BufferedReader findSize = new BufferedReader(new FileReader(filePath));
        String line;
        while ((line = findSize.readLine()) != null) {
            if(!line.startsWith("#")) {
                String[] values = line.split("\\s");
                if(values.length > rowSize)
                    rowSize = values.length;
                columnSize++;
            }
        }
        grid = new short[rowSize][columnSize];
        findSize.close();
    } catch(Exception e) {
        e.getMessage();
    }

    BufferedReader readTiles;
    try {
        readTiles = new BufferedReader(new FileReader(filePath));
        String line;
        short rowNum = -1;
        while ((line = readTiles.readLine()) != null) {
            if(!line.startsWith("#")) {
                rowNum++;
                String[] values = line.split("\\s");
                short y = 0;
                for(String v : values) {
                    grid[y][rowNum] = Byte.parseByte(v);
                    y++;
                }
            }
        }
        readTiles.close();
        initializeMap();
    } catch (Exception e) {
        e.getMessage();
    }

My second question is to ask whether this is the best way to do it. I've done some research and found that BufferedReader is faster than using the scanner, but I'm not exactly sure how I could shorten my code, and if it would be possible to create the array while checking its size. One way I've thought about doing it is through a list, but I'm not sure if this would be more efficient or even possible.

My third question concerns displaying the map. What would be the best way to do this? Should I create an array of BufferedImages and then assign each number in the current array to an index in that array?

\$\endgroup\$
  • 1
    \$\begingroup\$ You said the word "best"allot. Questions using best aren't the best (Ha, I said it too!) fit for this site. Normally if it works and it works well, it's a 'good' way to do it. If you have an opinion based question it is best to ask it on the chat or to go elsewhere. \$\endgroup\$ – TheNickmaster21 Oct 6 '13 at 16:58
  • \$\begingroup\$ I don't see how this is opinionated. I'm asking for the "best" way, meaning the most memory efficient, which can be proven. \$\endgroup\$ – Troubleshoot Oct 6 '13 at 17:04
  • 1
    \$\begingroup\$ Best is subjective, if you mean most memory efficient say that - also please only ask one question per "Question" \$\endgroup\$ – Jesse Dorsey Oct 6 '13 at 17:18
  • 1
    \$\begingroup\$ @Troubleshoot: it actually isn't guaranteed that any one approach is "best" for evne just memory efficiency. It's going to depend on what you mean by memory efficient (uses the least memory? maximizes use of the cache? minimizes fragmentation?) and really on what exactly you're doing; not all 2D tile implementations are even remotely identical. ALso, it's just pointless to care: your users do not care if you have the most efficient tiles ever, they just care if your game loads fast enough. Shaving 100ms from load is just wasted dev time. I'd call "best" the fastest solution to write. \$\endgroup\$ – Sean Middleditch Oct 6 '13 at 17:53
  • 1
    \$\begingroup\$ It's the way that the system works. It certainly won't be categorized as spam. gamedev.stackexchange.com/about \$\endgroup\$ – Jesse Dorsey Oct 6 '13 at 18:03
2
\$\begingroup\$

The "best" (for certain definitions of "best") way is to store it on disk in a binary format that exactly matches the in-memory format you're going to use; all that you need to do is open the file and read it directly in. Optionally, a file header can be used for storing information about sizes/etc that can allow you to set up memory buffers in advance. If using e.g VBOs in OpenGL you can memory-map the file and send your current pointer straight into a glBufferData call without even needing to read it into intermediate storage.

There are a number of things severely wrong with your current approach. The first big one is that you need to do two passes over the file; the first to determine sizes and set up storage, the second to actually read things in. You're also doing a lot of string parsing and splitting, which are slow operations (and in the case of splitting involve a lot of temporary short-lived allocations).

"Memory-efficiency" doesn't have much to do with any of this; you're doing slow and error-prone loading to begin with, particularly with those two passes where you've got to ensure that you read consistently in both; the potential for introducing bugs is just enormous here. Just think of what would happen if you needed to change the file format to introduce a new feature - you're giving yourself two parsers that you have to modify to support the new format.

If you need to (or prefer to) use a human-readable format, then convert it to binary as a pre-processing step, and actually load the binary version in your game. That way at least you're moving the slow and potentially buggy work out of the game itself.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.