Search code examples
javacollision-detection

Problems making map collision using the hex of a mask image in Java


I was making a game and I came up with the idea of using hex color codes to make collisions with objects on the map using a png image as a mask. For this to work, the code would scan every pixel of this mask and, if a pixel had a specific color, an invisible block would spawn at its location. However, since the image I'm using as a mask is pretty large (1582 x 1146), the code uses way too much cpu power (I think it's the cpu, not so sure) to scan every single pixel and the game runs literally at 1 FPS.

public class World {
    private Tile[] tiles;
    private static int WIDTH = 1582, HEIGHT = 1146;

    public World(String path) {
        try {
            BufferedImage map = ImageIO.read(getClass().getResource(path));
            int[] pixels = new int[map.getWidth() * map.getHeight()];
            tiles = new Tile[map.getWidth() * map.getHeight()];
            map.getRGB(0, 0, map.getWidth(), map.getHeight(), pixels, 0, map.getWidth());
            for (int xx = 0; xx < map.getWidth(); xx++) {
                for (int yy = 0; yy < map.getHeight(); yy++) {
                    int pixelAtual = pixels[xx + (yy * map.getWidth())];
                    if (pixelAtual == 0xfffcff00) //Pixel's hex verification
                    {
                        tiles[xx + (yy * WIDTH)] = new TileWall(xx, yy, Tile.TILE_WALL); //Invisible tile wall
                    }
                    /*else if (pixelAtual == )  Adding another tile
                        tiles[xx + (yy * WIDTH)] = new  TileWall(xx, yy, Tile.TILE_WALL);
                    } */
                    else {
                        tiles[xx + (yy * WIDTH)] = new TileFloor(xx, yy, Tile.TILE_FLOOR); //Invisible tile floor, just to complete the array
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void render(Graphics g) {
        for (int xx = 0; xx < WIDTH; xx++) {
            for (int yy = 0; yy < HEIGHT; yy++) {
                Tile tile = tiles[xx + (yy * WIDTH)];
                tile.render(g);
            }
        }
    }
}

I thought this method of hex scanning would be easy to write and practical to use. Is there any other way to add collisions to the game?


Solution

  • Minor note: There's https://gamedev.stackexchange.com/ , which you may find a useful resource for these types of questions.

    Collision detection can be a challenging and indeed also computationally challenging topic, consuming lots of runtime and memory. However, it can also be fairly straight-forward. It depends on your requirements and game design. It can often be useful to change the game design to make collision detection easier to implement, though this is of course a trade-off relative to what kind of interesting, fun or profitable games you seek to make.

    The way you describe sound a bit like raster-based collision detection, where an area defined by pixels (if in 3D, it would be a volume defined by voxels) is used for collision detection. A more common approach is to instead do collision detection by using geometric approaches - a rectangle as defined by 4 points, a circle by a center and a radius, a polygon, etc. These can often give good results and be sufficient for one's needs, and they typically permit decently fast collision detection, though they can be a bit more difficult to implement. That said, there are articles and learning resources available in different places reg. such algorithms, so using collision detection based on geometric shapes should still be fairly accessible.

    A rectangle-based collision detection is very easy to implement. A circle-based one is still fairly easy. A convex-polygon-based one is more complex, but there are resources for it, such as the links in this answer: 2D Polygon Collision Detection .

    There might also be libraries for collision detection, which may well be a good approach as well. Game engines and game libraries often provide these. Search online for one, and if you are using a game engine, there may be components or plugins for such things available.

    As a side-note, there are some game engines and libraries that support raster-based collision detection, such as GameMaker. But since it (as in your example) can be very or extremely slow, one has to be careful with it.

    Reg. the loop, it does make sense that it can be slow: In the worst case, it might have to iterate through all pixels. 1582 x 1146 gives for the worst-case 1812972. Assuming you do not create objects and instead just let it be represented by an array with a boolean or similar, this might then be run multiple times (for each time you would check collisions) in a frame, and a frame may then be executed multiple times a second. This all multiplies up to a large burden every second. There are various ways to optimize such things, and for a real-time game, keeping the time spent each frame down can be important and a challenge. Though again, changing the game design and requirements to something less intensive can be useful (which again is a trade-off).

    As a final note, you use objects to represent a single pixel if I understand your code correctly. In case you are new to object-oriented programming, you may have been led to believe that objects are generally good for modelling your domain directly. That is a very common beginner belief (also common in various teaching materials), but it does not hold in general. For real-time games, performance often matters, and using objects in different ways rather than using them to directly model the domain can be a good idea, since certain usages of objects can have considerable runtime overhead. For other cases, other concerns may come into play. For instance, you may have been taught that a class can be used to describe an Animal type, and sub-types could then be Dog and Cat. This is a very direct modelling (and easy for teaching). However, in practice, describing all kinds of animals with a single data class might be more suitable, for instance if you want to describe lots and lots and lots of animals and they don't have varying functionality, only attributes. If you tried to describe all these animals using sub-types like some teaching material might suggest, you might end up with a very large number of sub-types, with minor variance between them, with the very many classes costing more than they benefit you reg. development relative to just having a single data class. I hope this last part is clear, though I am uncertain how clear I made it.