使用Java中掩码图像的十六进制制作地图碰撞时遇到的问题。

huangapple go评论113阅读模式
英文:

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

问题

我正在制作一个游戏,并想到使用十六进制颜色代码来实现与地图上的对象发生碰撞,使用一张 PNG 图像作为遮罩。为了使这个方法生效,代码将扫描遮罩的每个像素,如果像素具有特定的颜色,就会在其位置生成一个无形的障碍块。然而,由于我用作遮罩的图像相当大(1582 x 1146 像素),代码在扫描每个像素时消耗了过多的 CPU 资源(我认为是 CPU,不太确定),导致游戏的帧率只有 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) // 像素的十六进制颜色验证
                    {
                        tiles[xx + (yy * WIDTH)] = new TileWall(xx, yy, Tile.TILE_WALL); // 无形的障碍块
                    }
                    /*else if (pixelAtual == )  添加另一种块
                        tiles[xx + (yy * WIDTH)] = new  TileWall(xx, yy, Tile.TILE_WALL);
                    } */
                    else {
                        tiles[xx + (yy * WIDTH)] = new TileFloor(xx, yy, Tile.TILE_FLOOR); // 无形的地板块,仅用于填充数组
                    }
                }
            }
        } 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 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 &lt; map.getWidth(); xx++) {
                for (int yy = 0; yy &lt; map.getHeight(); yy++) {
                    int pixelAtual = pixels[xx + (yy * map.getWidth())];
                    if (pixelAtual == 0xfffcff00) //Pixel&#39;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 &lt; WIDTH; xx++) {
            for (int yy = 0; yy &lt; 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?

答案1

得分: 2

次要注释:这里有 https://gamedev.stackexchange.com/ ,这可能是一个对你这类问题有用的资源。

碰撞检测可能是一个具有挑战性且计算密集的话题,消耗大量运行时和内存。然而,它也可以相当简单。这取决于你的需求和游戏设计。通常可以通过改变游戏设计来使碰撞检测更容易实现,虽然这当然是与你寻求制作哪种有趣、有趣或有益的游戏的方式相关的权衡。

你描述的方式有点像基于光栅的碰撞检测,其中使用像素定义的区域(如果在3D中,可能是由体素定义的体积)用于碰撞检测。更常见的方法是使用几何方法进行碰撞检测 - 由4个点定义的矩形、由中心和半径定义的圆、多边形等。这些方法通常可以得出良好的结果,并且对于一个人的需求来说通常足够快速,尽管它们可能会更难实现。尽管如此,关于此类算法在不同位置都有文章和学习资源,因此仍然可以相对容易地使用基于几何形状的碰撞检测。

基于矩形的碰撞检测非常容易实现。基于圆的碰撞检测仍然相当容易。基于凸多边形的碰撞检测更复杂一些,但是也有相应的资源,比如这个回答中的链接:https://stackoverflow.com/questions/3972517/2d-polygon-collision-detection。

也许还有用于碰撞检测的库,这也可能是一个不错的方法。游戏引擎和游戏库通常会提供这些功能。在线搜索一下,如果你正在使用游戏引擎,可能会有这些功能的组件或插件可用。

另外,一些支持基于光栅的碰撞检测的游戏引擎和库,比如GameMaker。但是,正如你的示例中所示,它可能会非常慢,所以必须小心使用。

关于循环,它变慢是有道理的:在最坏的情况下,可能需要遍历所有像素。1582 x 1146 在最坏的情况下会得到 1812972。假设你不创建对象,而是使用布尔值或类似的数组来表示它,那么在一个帧内可能会多次运行这个循环(每次检查碰撞时都会运行),而一个帧可能会在一秒内多次执行。所有这些都会在每秒钟内累积成巨大的负担。有各种优化此类问题的方法,对于实时游戏来说,保持每帧所花费的时间较少可能是重要的挑战。尽管再次强调,将游戏设计和需求改变为更轻松的模式可能会很有用(这又是一个权衡)。

最后提一下,根据我理解你的代码,你使用对象来表示单个像素。如果你对面向对象编程不熟悉,你可能会认为对象通常很适合直接对领域进行建模。这是一种非常常见的初学者观点(在各种教材中也很常见),但这并不是通用的观点。对于实时游戏来说,性能通常很重要,而以不同的方式使用对象而不是直接用它们来模拟领域可能是一个好主意,因为某些对象的使用可能会带来相当大的运行时开销。对于其他情况,可能会涉及其他考虑因素。例如,你可能被教导过一个类可以用来描述一个“动物”类型,然后子类型可以是“狗”和“猫”。这是一种非常直接的建模方法(也很容易教授)。然而,在实践中,使用单个数据类来描述各种各样的动物可能更合适,例如,如果你想描述大量大量大量的动物,它们没有不同的功能,只有属性。如果你试图使用子类型来描述所有这些动物,就像一些教材可能建议的那样,你可能会得到非常多的子类型,它们之间的差异很小,非常多的类会比仅仅拥有一个单一的数据类相比,在开发方面的成本超过了它们的益处。希望这最后部分是清楚的,尽管我不确定我是否表达清楚。

英文:

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: https://stackoverflow.com/questions/3972517/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.

huangapple
  • 本文由 发表于 2020年5月30日 03:00:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/62092975.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定