1
\$\begingroup\$

I am currently developing a 2d mmorpg and am having some memory issues with regards to my tile based map. The client takes a little while to load and then sits around 1GB ram, because I am loading each tile, for each layer, into memory. My map is currently 1/3 of its expected size.

My map has multiple layers which are drawn on top of each other - ground, building, and object. Each of these layers is stored in a separate short[] array. My question is how can I do this better.

I have thought of some ideas:

  • Load zones into memory (i.e. 500x500) and when user goes into next zone disgard and load new 500x500
  • Load zones into memory (i.e. 500x500) and when user goes 250 tiles east disgard 0-250 tiles
  • Read from filesystem rather than memory

Can anyone give some suggestions and perspectives as to why, which above (or other ideas) work best?

Somes notes/issues I've found:

  • My game has 1 seamless world map(hard to split to zones)
  • Users can be teleported by GM/DEVs - but will usually only happen if they are stuck somewhere(potiential issues for storing chunks in memory)
  • My game is www.KisnardOnline.com for anyone interested.

Thanks anyone/everyone for taking a look and your help.

\$\endgroup\$
2
\$\begingroup\$

I can address your ideas and some of the issues related with them.

Load zones into memory (i.e. 500x500) and when user goes into next zone disgard and load new 500x500

This is the basic idea of what you want to achieve for a seamless world. However, if left at this basic approach you will incur what is known as "image popping". When the player gets to the boundary of that zone, he will see nothing, and then, BAM, the entire zone is pushed into his screen. So, while this is the right step, it has some issues.

Load zones into memory (i.e. 500x500) and when user goes 250 tiles east disgard 0-250 tiles

This is more of the complete step to your previous idea was looking for. Now, you are essentially buffering the viewport against image popping. This is a much better solution then the previous.

Read from filesystem rather than memory

No, no, don't do that. Ram is MUCH faster then the file system. Not too mention, you need to have room in ram to pull in that data, so if you're blocking room for that data...just read it anyways!

My game has 1 seamless world map(hard to split to zones)

You solved that issue with your second idea.

Users can be teleported by GM/DEVs - but will usually only happen if they are stuck somewhere(potiential issues for storing chunks in memory)

I don't want to recommend this because I hate loading screens, but if it's an issue with graphics lag etc, you might have to throw up a loading screen when gm teleports them. Or, just let the elements pop in. It's fun to watch sometimes.

\$\endgroup\$
  • \$\begingroup\$ Awesome thanks for the help. Have you ever seen this(zones with throwing away/loading new) done before? I tried searching a bit(to get some ideas on what others are doing) as to not re-invent the wheel. \$\endgroup\$ – KisnardOnline Dec 22 '14 at 17:18
  • \$\begingroup\$ You can do some research on quadtrees. I don't know how easy they are to implement in java. \$\endgroup\$ – Joe Swindell Dec 22 '14 at 17:23
  • \$\begingroup\$ I posted what I have worked on so far below, but am having issues when the player is on the perimeter of the map. Can you help me figure out what is wrong? Fresh set of eyes map help :) \$\endgroup\$ – KisnardOnline Dec 22 '14 at 20:28
  • \$\begingroup\$ @JoeSwindell Language shouldn't matter. I really think that the Java tag could be removed, although it may have some relevance because it runs in a VM which can affect performance; this question still doesn't have much to do with language. \$\endgroup\$ – Lysol Dec 22 '14 at 22:06
  • \$\begingroup\$ @AidanMueller I disagree, java memory management should be treated differently when you are going to be working beyond physical memory limitations. Not being able to garbage collect could have unintended consequences performance wise. Not that every program will, but if you're aware you at least know whats going on. \$\endgroup\$ – Joe Swindell Dec 22 '14 at 22:25
0
\$\begingroup\$

Here is what I have come up with so far (note: player is in center of chunk & chunk always odd number sized)... It has the following issues(when the character is on the edge of the map):

  • change characterX/Y to 0,0 and the bottom left(0,2) coordinate will be 7

    0, 0, 0

    0, 1, 1

    7, 1, 8

  • change characterX/Y to 8,8 and the top right(2,0) coordinate of the chunk will be 7

    1, 1, 6

    1, 1, 0

    0, 0, 0

Here is the code for anyone who wants to figure this out with me or can learn from it:

public class MapChunkLoad {

    public static void main(String[] args) {
        short[] groundLayer;
        int mapWidth = 9;
        int mapHeight = 9;
        int chunkWidth = mapWidth / 3; //3
        int chunkHeight = mapHeight / 3; //3
        int characterX = 8;
        int characterY = 8;
        String map = "1, 1, 1, 1, 1, 1, 1, 1, 7, " +
                     "1, 8, 8, 1, 1, 1, 1, 1, 1, " +
                     "1, 8, 9, 9, 1, 1, 1, 1, 1, " +
                     "1, 1, 9, 9, 1, 1, 1, 1, 1, " +
                     "1, 1, 1, 1, 1, 1, 1, 1, 1, " +
                     "1, 1, 1, 1, 1, 1, 1, 1, 1, " +
                     "1, 1, 1, 1, 1, 1, 1, 1, 1, " +
                     "1, 1, 1, 1, 1, 1, 1, 1, 1, " +
                     "6, 1, 1, 1, 1, 1, 1, 1, 1";
        String[] strArr = map.split(", ");
        groundLayer = new short[chunkWidth * chunkHeight];

        //load chunk into groundLayer
        int arrayIndex = 0;
        int count = (characterX - (chunkWidth/2)) + ((characterY - (chunkHeight/2)) * mapWidth); //top left tile within chunk

        for (int y = 0; y < chunkHeight; y++){
            for (int x = 0; x < chunkWidth; x++){
                if (count > -1 && count < strArr.length){
                    groundLayer[arrayIndex] = Short.parseShort(strArr[count]);
                    System.out.println("arrayIndex[" + arrayIndex + "] = " + strArr[count]);
                } else {
                    groundLayer[arrayIndex] = 0;
                    System.out.println("arrayIndex[" + arrayIndex + "] = " + 0);
                }

                arrayIndex++;
                count++;
            }
            count += (mapWidth - chunkWidth);
        }

        System.out.println("");
        //print map grid
        int printcount = 0;
        for (int y = 0; y < chunkHeight; y++){
            for (int x = 0; x < chunkWidth; x++){
                if (x == chunkWidth - 1){
                    System.out.println(groundLayer[printcount]);
                } else {
                    System.out.print(groundLayer[printcount] + ", ");
                }
                printcount++;
            }
        }

    }
}
\$\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.