xaguzman / pathfinding

Java pathfinding framework.
Apache License 2.0
97 stars 27 forks source link

Load larger maps (700k) #18

Closed undefined-user-ctrl closed 6 years ago

undefined-user-ctrl commented 6 years ago

Hello,

First, great job! I'm using it for a while not and its awesome. Thanks!

Using a 172k map file, with some layers, works fine.

Now i have a bigger map (700~k), and i need to load it, but it crashes due to out of memory.

com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load asset: maps/mapFloors.tmx at com.badlogic.gdx.assets.AssetManager.handleTaskError(AssetManager.java:576) at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:377) Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load asset: maps/mapFloors.tmx at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:139) at com.badlogic.gdx.assets.AssetLoadingTask.update(AssetLoadingTask.java:90) at com.badlogic.gdx.assets.AssetManager.updateTask(AssetManager.java:501) at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:375) at com.riot.game.RiotGame.render(RiotGame.java:65)  at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:459)  at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1527)  at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1244)  Caused by: com.badlogic.gdx.utils.GdxRuntimeException: java.lang.OutOfMemoryError at com.badlogic.gdx.utils.async.AsyncResult.get(AsyncResult.java:46) at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:137) Caused by: java.lang.OutOfMemoryError at org.xguzm.pathfinding.util.ObjectIntMap.(ObjectIntMap.java:80) at org.xguzm.pathfinding.util.ObjectIntMap.(ObjectIntMap.java:54) at org.xguzm.pathfinding.grid.GridCell.(GridCell.java:20) at org.xguzm.pathfinding.gdxbridge.NavTmxMapLoader.loadNavigationLayer(NavTmxMapLoader.java:62) at org.xguzm.pathfinding.gdxbridge.NavTmxMapLoader.loadTileLayer(NavTmxMapLoader.java:43) at com.badlogic.gdx.maps.tiled.TmxMapLoader.loadTilemap(TmxMapLoader.java:213) at com.badlogic.gdx.maps.tiled.TmxMapLoader.loadAsync(TmxMapLoader.java:110) at com.badlogic.gdx.maps.tiled.TmxMapLoader.loadAsync(TmxMapLoader.java:42) at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:74) at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:34) at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:58)

As i can see, the AssetManger can load the map, but at some point it cant handle all layers and tiles.

After some research, i didnt find any topic about big map files in Libgdx or here. Do you know any method for handling bigger maps? Do i need to break it? (My problem is that this current map has only the top layer (floor), and its gonna have several floors.

undefined-user-ctrl commented 6 years ago

Noticed that if i remove all blank layers, it runs again, but what should i do when i need to fill the lower floors?

xaguzman commented 6 years ago

The maps will be delimited by the ram memory that your game runs on (in this case, your development computer). I never faced this problem due to handling small maps.

I would suggest just breaking down your map into sections and handle them separatedly with some kind of warp mechanism

tootoll commented 6 years ago

You can try it with cell data to load map with separate code and see if ti helps Basicly my map have one special separate layer that have 2 tile types one is green other is red, red one have custom property value "Blocked" and its value (true or false) isnt important, it needs only to have that value in. The layer is not render and its hidden on saving the map. image

image

So based on that data i collect it and put it in GridCell so that pathfind will work. That spetial layer need to have fully created so no blank cells, only green or redones with blocked on red.


    private AStarGridFinder<GridCell> finder;
    private NavigationGrid navGrid;
    private List<GridCell> pathToEnd;
...
    public void show() {
        map = assetManager.get("mape/pocetna_mapa.tmx");

        MapProperties prop = map.getProperties();
        int mapWidth = prop.get("width", Integer.class);
        int mapHeight = prop.get("height", Integer.class);

        GridCell[][] cells = new GridCell[mapHeight][mapWidth];//map declaration for pathfind alg.
        layerNumber = map.getLayers().getCount()-1;//get layer for pathfind where 2 tile types are defined, first have "Blocked" property other dont have it
        TiledMapTileLayer tml = (TiledMapTileLayer) map.getLayers().get(layerNumber);
        for (int xx = 0; xx < mapHeight; xx++){
            for (int yy = 0; yy < mapWidth; yy++){
                if (tml.getCell(yy, xx).getTile().getProperties().get("Blocked") == null){
                    cells[xx][yy] = new GridCell(xx, yy, true);
                }else {
                    cells[xx][yy] = new GridCell(xx, yy, false);
                }
            }
        }
        GridFinderOptions opt = new GridFinderOptions();
        opt.allowDiagonal = false;
        finder = new AStarGridFinder(GridCell.class, opt);
        navGrid = new NavigationGrid(cells, false);
...
    private void gotoTile(int sY, int sX){//our tiles are 32x32
        pathToEnd = finder.findPath(playerClass.getPositionX()/32, playerClass.getPositionY()/32, sX, sY, navGrid);
        playerClass.setDestinationTileY(sY*32);//set dest tile to move player to
        playerClass.setDestinationTileX(sX*32);//set dest tile to move player to
        //func to move player to desired tile pathToEnd holds array of cells to move player to
        destTile();
    }
undefined-user-ctrl commented 6 years ago

Thanks for all your reply. I have a server and my devices are clients. So, in the end, i didn't need to load nagivations maps on clients, so i just removed the loading of this layer. Something happens that make this layers heavy (like 100mb+ to load those layers), even if i had on like 10 blocks on then. Mayboe @tootoll answer would fix the problem, i did not try to fill all the navlayer.

But one possible way to fix it would be to not create cells when there are no blocks in the cell, and when looking if navigable, depending on the strategy (cellblocked or cellavaliable), if the block doenst exists you can return either walkable or not.

It works now for my case, thanks again for the great job!