当前位置: 首页 > 知识库问答 >
问题:

libGDX-精确碰撞检测-多边形创建?

锺离鸿
2023-03-14

我有一个关于libGDX碰撞检测的问题。因为这是一个相当具体的问题,我还没有在互联网上找到任何好的解决方案。

因此,我已经创建了由不同身体部位组成的“人类”,每个部位都有矩形碰撞检测。

现在我想实现武器和技能,例如看起来像这样:

技能示例图像

问题

当有这样的技能时,在碰撞检测中使用矩形会让玩家非常沮丧:他们会成功躲避技能,但碰撞检测器仍然会伤害他们。

方法 1:

在我开始使用Libgdx之前,我已经创建了一个具有自定义引擎和类似技能的Android游戏。在那里,我按照以下方式解决了问题:

  1. 检测矩形碰撞
  2. 计算重叠矩形截面
  3. 检查技能重叠部分的每一个像素是否透明
  4. 如果发现任何非透明像素-

这是一种繁重的方式,但由于只检查重叠像素,而游戏的其余部分非常轻,因此它完全可以正常工作。

目前,我的技能图像被加载为“TextureRegion”,无法访问单个像素。我发现libGDX有一个Pixmap类,它允许这样的像素检查。问题是:如果将它们作为像素贴图加载,则1。会更重,2。会破坏纹理系统的整体功能。

另一种方法是仅将所有技能加载为像素映射。你怎么看:这会是一个好方法吗?是否可以在屏幕上绘制许多Pixhtml" target="_blank">map而不会出现任何问题和滞后?

方法2:

另一种方法是创建具有技能形状的多边形,并将其用于碰撞检测。

a) 但我该如何为每项技能定义多边形形状(共有150多种)?浏览了一会儿之后,我发现了一个有用的工具:http://www.aurelienribon.com/blog/projects/physics-body-editor/它允许手动创建多边形,然后将其保存为JSON文件,可供libGDX应用程序读取。现在困难来了:

  • Physics Body Editor连接到Box2d(我没有使用)。我要么仅仅因为一个微小的碰撞检测就必须添加整个Box2d物理引擎(我根本不需要),要么我必须编写一个自定义BodyEditorLoader,这将是一项艰巨、复杂和耗时的任务
  • 同一技能精灵的一些图像在形状上有很大差异(如第二个技能精灵示例)。使用BodyEditor工具时,我不仅需要定义每个技能的形状,还需要定义每个技巧的多个图像(最多12个)的形状。在实现这几十个多边形形状时,这将是非常耗时且非常混乱的

b)如果有任何平滑的方法可以自动从图像中生成多边形,那可能是解决方案。我可以简单地将每个精灵部分连接到生成的多边形,并通过这种方式检查冲突。不过有一些问题:

    < li >是否有任何平滑工具可以从图像中生成多边形形状(并且不需要太多时间)? < li >我不认为像这样的工具(如果有的话)可以直接处理纹理。它可能需要位图。不过,在多边形创建之后,不需要保持位图的加载。还是一个极其繁重的任务!

我现在的想法

我在这一点上陷入了困境,因为有几种可能的方法,但它们都有各自的困难。在我选择一条路径并继续编码之前,如果您能留下一些想法和知识,那就太好了。

libGDX中可能包含有用的类和代码,可以在几秒钟内解决我的问题 - 因为我是libGDX的新手,我只是对它知之甚少。

目前,我想我会采用方法1:使用像素检测。这样,我就可以在我以前的Android游戏中精确检测碰撞。

你怎么想呢?

你好,费利克斯

共有3个答案

钱星辰
2023-03-14

不知道这对你们来说是否仍然重要,但是我构建了一个小的python脚本来返回图像边缘点的像素位置。剧本还有改进的空间,但对我来说,现在还可以...

from PIL import Image, ImageFilter

filename = "dship1"

image = Image.open(filename + ".png")
image = image.filter(ImageFilter.FIND_EDGES)
image.save(filename + "_edge.png")
cols = image.width
rows = image.height
points = []
w = 1
h = 1
i = 0
for pixel in list(image.getdata()):
    if pixel[3] > 0:
        points.append((w, h))

    if i == cols:
        w = 0
        i = 0
        h += 1
    w += 1
    i += 1

with open(filename + "_points.txt", "wb") as nf:
    nf.write(',\n'.join('%s, %s' % x for x in points))

如果有更新,您可以在这里找到它们:导出位置

南宫森
2023-03-14

我已经使用了你提到的那个正文编辑器,它能够为你生成多边形和/或圆形。我还用杰克逊库为生成的JSON制作了一个加载器。这可能不是你的答案,因为你必须实现box2d。但是这是我是如何做到的。

/**
* Adds all the fixtures defined in jsonPath with the name'lookupName', and 
* attach them to the 'body' with the properties defined in 'fixtureDef'. 
* Then converts to the proper scale with 'width'.
*
* @param body the body to attach fixtures to
* @param fixtureDef the fixture's properties
* @param jsonPath the path to the collision shapes definition file
* @param lookupName the name to find in jsonPath json file
* @param width the width of the sprite, used to scale fixtures and find origin.
* @param height the height of the sprite, used to find origin.
*/
public void addFixtures(Body body, FixtureDef fixtureDef, String jsonPath, String lookupName, float width, float height) {
  JsonNode collisionShapes = null;
  try {
    collisionShapes = json.readTree(Gdx.files.internal(jsonPath).readString());
  } catch (JsonProcessingException e) {
    e.printStackTrace();
  } catch (IOException e) {
    e.printStackTrace();
  }
  for (JsonNode node : collisionShapes.findPath("rigidBodies")) {
    if (node.path("name").asText().equals(lookupName)) {
      Array<PolygonShape> polyShapes = new Array<PolygonShape>();
      Array<CircleShape> circleShapes = new Array<CircleShape>();

      for (JsonNode polygon : node.findPath("polygons")) {
        Array<Vector2> vertices = new Array<Vector2>(Vector2.class);
        for (JsonNode vector : polygon) {
          vertices.add(new Vector2(
            (float)vector.path("x").asDouble() * width,
            (float)vector.path("y").asDouble() * width)
            .sub(width/2, height/2));
        }
        polyShapes.add(new PolygonShape());
        polyShapes.peek().set(vertices.toArray());
      }

      for (final JsonNode circle : node.findPath("circles")) {
        circleShapes.add(new CircleShape());
        circleShapes.peek().setPosition(new Vector2(
          (float)circle.path("cx").asDouble() * width,
          (float)circle.path("cy").asDouble() * width)
          .sub(width/2, height/2));

        circleShapes.peek().setRadius((float)circle.path("r").asDouble() * width);
      }

      for (PolygonShape shape : polyShapes) {
        Vector2 vectors[] = new Vector2[shape.getVertexCount()];
        for (int i = 0; i < shape.getVertexCount(); i++) {
          vectors[i] = new Vector2();
          shape.getVertex(i, vectors[i]);
        }
        shape.set(vectors);
        fixtureDef.shape = shape;
        body.createFixture(fixtureDef);
      }

      for (CircleShape shape : circleShapes) {
        fixtureDef.shape = shape;
        body.createFixture(fixtureDef);
      }
    }
  }
}

我会这样称呼它:

physics.addFixtures(body, fixtureDef, "ship/collision_shapes.json", shipType, width, height);

然后进行碰撞检测:

public ContactListener shipsExplode() {
  ContactListener listener = new ContactListener() {

    @Override
    public void beginContact(Contact contact) {
      Body bodyA = contact.getFixtureA().getBody();
      Body bodyB = contact.getFixtureB().getBody();

      for (Ship ship : ships) {
        if (ship.body == bodyA) {
          ship.setExplode();
        }
        if (ship.body == bodyB) {
          ship.setExplode();
        }
      }
    }
  };
  return listener;
}

然后,您将向世界添加侦听器:

world.setContactListener(physics.shipsExplode());

我的精灵的宽度和高度很小,因为一旦你开始使用box2d,你就要以米而不是像素为单位进行处理。例如,一个精灵的高度为 0.8f,宽度为 1.2f。如果使精灵的宽度和高度以像素为单位,则物理引擎会达到内置的速度限制 http://www.iforce2d.net/b2dtut/gotchas

庾和昶
2023-03-14

就我个人而言,我会觉得像素到像素的碰撞对性能来说太过分了,并且提供了一些我仍然会感觉被欺骗的实例——(我被斧头的手柄击中了?)

如果是我,我会在每个技能上加一个“生命盒”。街头霸王是一个使用这种技术的流行游戏。(新版本是3D的,但hitbox collision仍然是2D)hitbox可以随着动画逐帧变化。

< sub >此处空白处添加示例图片-同时搜索“街头霸王hitbox”

对于你的斧子来说,沿着一个或两个末端的边缘可以有一个定义好的矩形点击框——或者甚至在斧子的整个金属头上。

这使得它相当简单,不必弄乱精确的多边形,但也不像每个像素都是自己的hitbox那样性能太重。

 类似资料:
  • 问题内容: Libgdx中是否可以验证多边形和圆之间的碰撞? 我看到了课程,但只发现了Circle和Rectangle的碰撞测试。那其他多边形呢? 如果我需要手动进行操作,那么使用Libgdx的最佳方法是什么? 问题答案: 因此,我设法在Circle和Polygon之间创建了碰撞测试方法。至少,它对我有用。 这是代码:

  • 我正在为我的播放器和bullet类创建一些围绕精灵的矩形,以使用LibGDX的Intersector类中的重叠方法检测碰撞。 我有一个问题: 当我实例化Player和Bullet时,我使用sprite.getBoundingRectangle()在精灵周围创建一个边界框,它返回一个Rectangle对象。我在主类的其他地方更新这些的移动。 当我更新子弹/玩家精灵的移动时,我是否也需要更新子弹/玩家

  • 使用< code >加速计,我的精灵图像会左右移动,如果我触摸屏幕,精灵会移动到Y轴。我想在不同的精灵之间进行碰撞检测,这样如果精灵穿过一个物体,它就会停下来藏在那个物体里。我已经看了这个https://www.youtube.com/watch?v=T1aN-vTqLc的教程,但什么也没发生。进行碰撞检测的正确方法是什么?我不知道我的编码有什么问题。任何建议或更好的教程谢谢和进步 这是我的编码

  • 所以我试图用pygame制作一个我们之间的游戏。我刚刚开始,所以我没有太多东西,现在正在制作地图。然而,我正在努力解决的一件事是碰撞逻辑。地图目前有一个细长的八边形形状,但是我想不管是什么形状,我都会使用类似pygame多边形的东西。当我运行我现在的代码时,它会检查我的玩家(pygame矩形)和墙壁(pygame多边形)之间的碰撞,它说: 我发现这是因为pygame多边形返回了一个矩形,但在碰撞检

  • 我的问题主要与它背后的理论有关。我为一个项目制作了一个2D游戏,通过使用Rectangle类中的.overlapps方法检测碰撞,碰撞处理得很好。首先,被认为是连续或离散碰撞技术。当我读到这个理论时,我说它是离散的,但我在网上的文章中读到离散的主要缺点是它在实际发生碰撞后检测到碰撞。所以,我的问题是:它实际上是离散的吗?如果是这样的话,我看不出它有什么缺点吗?谢谢

  • 我花了数小时寻找解决方案:我正在用libgdx开发一个自上而下的小游戏(可能这与我使用的引擎有关)。现在我必须在我的角色(圆形)和墙(矩形)之间实现碰撞检测。如果可以滑动,我希望角色在碰撞时沿着墙滑动。让我解释一下: 如果我向上移动45度,我可能会撞到墙的下面、左边或角落。 如果我与左边相撞,我想停止x运动,只向上移动。如果我离开墙壁,那么我想继续向上移动。与下侧相同(停止y运动) 如果我与角落相