我对libGDX碰撞检测有疑问。因为这是一个相当具体的问题,我还没有在互联网上找到任何好的解决方案。
所以,我已经创造了#34;人类"由不同的身体部位组成,每个部位都有矩形碰撞检测。
现在我想实施武器和技能,例如:
问题
在有这样的技能的情况下,在碰撞检测中使用矩形会让玩家感到非常沮丧:他们会成功躲避技能,但碰撞探测器仍然会对它们造成伤害。
方法1:
在我开始使用Libgdx之前,我创建了一款带有自定义引擎和类似技能的Android游戏。我在那里解决了问题:
这是一种沉重的方式,但由于只检查重叠的像素,而游戏的其余部分非常清晰,所以它完全正常。
目前我的技能图像被加载为" TextureRegion",其中无法访问单个像素。 我发现libGDX有一个Pixmap类,可以进行像素检查。问题是:将它们加载为Pixmaps另外1.将更加沉重和2.击败纹理系统的整个目的。
另一种方法是将所有技能加载为Pixmap。你怎么想:这会是一个好方法吗?是否有可能在屏幕上绘制许多Pixmaps而没有任何问题和滞后?
方法2:
另一种方法是创建具有技能形状的多边形并将其用于碰撞检测。
A) 但是,我如何为每一项技能定义一个多边形形状(其中有超过150种)?浏览片刻后,我找到了这个有用的工具:http://www.aurelienribon.com/blog/projects/physics-body-editor/ 它允许手动创建多边形形状,然后将它们保存为JSON文件,可由libGDX应用程序读取。现在来了困难:
b)中 如果有任何平滑的方法可以自动生成图像中的多边形,那么这可能是解决方案。我可以简单地将每个精灵部分连接到生成的多边形,并检查那种冲突。但是有一些问题:
我目前的想法
我在这一点上陷入困境,因为有几种可能的方法,但所有方法都有困难。在我选择一条路径并继续编码之前,如果你能留下一些你的想法和知识,那就太好了。
libGDX中可能包含有用的类和代码,可以在几秒钟内解决我的问题 - 因为我是libGDX的新手,但我还不太了解它。
目前我认为我会采用方法1:处理像素检测。这样我就可以在之前的Android游戏中进行精确的碰撞检测。
您怎么看?
问候 菲利克斯
答案 0 :(得分:1)
我个人认为,像素到像素的碰撞会对性能造成过大影响,并提供一些我仍然会感到受骗的情况 - (我被斧头的手柄击中了? )
如果是我,我会为每个技能添加一个“Hitbox”。 StreetFighter是一款使用这种技术的流行游戏。 (较新的版本是3D版,但是hitbox碰撞仍然是2D )Hitbox可以与动画一起逐帧更改。
这里的空白点添加示例图片 - 同时谷歌“Streetfighter hitbox”
对于你的斧头,沿着一端或两端的边缘可能有一个定义的矩形命中框 - 甚至在斧头的整个金属头上。
这使得它非常简单,不必弄乱精确的多边形,但也不会像每个像素都是自己的命中箱一样过于沉重。
答案 1 :(得分:0)
我使用了您引用的精确正文编辑器,它可以为您生成多边形和/或圆形。我还使用Jackson库为生成的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
中构建的速度限制答案 2 :(得分:0)
不知道这对你们来说是否仍然重要,但我建立了一个小的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))
如果有更新,您可以在此处找到它们:export positions