如何使用PyBox2d检测碰撞并使用该信息

时间:2019-11-05 11:51:58

标签: python pygame collision-detection box2d

我正在尝试通过重现以下示例来过滤Box2D世界中发生的碰撞:https://github.com/pybox2d/pybox2d/blob/master/examples/collision_filtering.py

我的世界中有四个类别,分别是汽车,车轮,建筑和行人,我想过滤哪个实例与哪个实例相撞,并且可能的输出之一是(伪代码)

if contact.FixtureA.isinstance(Pedestrian) and contact.FixtureB.isinstance(Car):
    print("You have caused a traffic accident")

我有这组类别


CAR_CATEGORY = 2
PEDESTRIAN_CATEGORY = 4
BUILDING_CATEGORY = 8
box2world = world(gravity =(0.0, 0.0), doSleep =True)

我也尝试过这种方法:但是它不起作用(什么都不做)

class myContactListener(b2ContactListener):
    def __init__(self):
        b2ContactListener.__init__(self)
    def BeginContact(self, contact):
        fixture_a = contact.fixtureA
        fixture_b = contact.fixtureB

        body_a, body_b = fixture_a.body, fixture_b.body
        ud_a, ud_b = body_a.userData, body_b.userData
        pedestrian = None
        car = None
        for ud in (body_a, body_b):
            if isinstance(ud, Pedestrian):
                pedestrian = ud
            elif isinstance(ud, Car):
                car = ud

        if car is not None and pedestrian is not None:
            if began:
                print("It does stuff")
            else:
                print("It does something")
    def EndContact(self, contact):
        pass
    def PreSolve(self, contact, oldManifold):
        pass
    def PostSolve(self, contact, impulse):
        pass


box2world = world(contactListener=myContactListener(),gravity =(0.0, 0.0), doSleep =True)

并且我将其应用于给定的类(为简单起见,仅以行人类为例):

class Pedestrian():
    def __init__(self,box2world, ped_velocity =25, position =None,):

        if position == None:
            position = [5,5]
        self.ped_velocity = ped_velocity
        self.position = position
        self.box2world = box2world
        self.nearest_building = 0
        self.body = self.box2world.CreateDynamicBody(position = position, 
                                                       angle = 0.0,
                                                       fixtures = b2FixtureDef(
                                                            shape = b2CircleShape(radius = 1),
                                                            density = 2,
                                                            friction = 0.3,
                                                            filter = b2Filter(
                                                                categoryBits=PEDESTRIAN_CATEGORY,
                                                                maskBits=BUILDING_CATEGORY + CAR_CATEGORY,
                                                                groupIndex=0,
                                                                    )))
        self.current_position = [self.body.position]
        self.body.userData = {'obj': self}

然后我用pygame绘制身体并运行世界

但是我对如何继续感到困惑,如何使用碰撞过滤器中的信息来例如从上方打印有关事故的句子?

非常感谢 编辑:我找到了一个链接,它可以完全解决我想做的事情,但是它是用C ++编写的,我不理解 http://www.iforce2d.net/b2dtut/collision-callbacks

2 个答案:

答案 0 :(得分:2)

嘿,我刚刚回答了您关于stackexchange的问题:-)

对于碰撞很简单:

local filterData = {
   categoryBits = player,
   maskBits = wall + nme + platform,
   groupIndex = 0
}
fixture:setFilterData(filterData)

玩家墙壁 nme ,...是整数变量(必须为2的幂):

player = 1
wall = 2
nme = 4
... = 16, 32, 64, 128, 256, ...

categoryBits =您要测试碰撞的主要对象

maskBits =您添加(带有+)所有主要对象可以碰撞的数字。

最好将数字存储为变量,否则看起来像这样:

local filterData = {
   categoryBits = 1,
   maskBits = 2 + 4 + 8 + 16 ...,
   groupIndex = 0
}
fixture:setFilterData(filterData)

:-)

答案 1 :(得分:1)

回答您的第二条更复杂的评论,因此我将其添加为另一个答案。

您自己无法处理碰撞,Box2D会为您完成,但是您需要进行设置。

-创建您的世界

world = b2.World.new(0, 24, true)

-将听众附加到您的世界(用于碰撞处理)

world:addEventListener(Event.BEGIN_CONTACT, self.onBeginContact, self)
world:addEventListener(Event.END_CONTACT, self.onEndContact, self)
world:addEventListener(Event.PRE_SOLVE, self.onPreSolveContact, self)
world:addEventListener(Event.POST_SOLVE, self.onPostSolveContact, self)

-在游戏循环中,您需要调用Box2D更新

self.world:step(1/60, 1, 1)

-然后在这里,您将在这些box2d函数侦听器中检查每个对象的冲突

-- collisions handler
function LF_Bullet:onBeginContact(e)
    local bodyA = e.fixtureA:getBody()
    local bodyB = e.fixtureB:getBody()
    if bodyA.type == 100 or bodyB.type == 100 then
        self.removebullet = true
    end
    if bodyA.type == 200 and bodyB.type == 100 then
        bodyA.isdead = true
    end
    if bodyA.type == 100 and bodyB.type == 200 then
        bodyB.isdead = true
    end
    if bodyA.type == 201 and bodyB.type == 100 then
        bodyA.isdead = true
    end
    if bodyA.type == 100 and bodyB.type == 201 then
        bodyB.isdead = true
    end
end

function LF_Bullet:onPreSolveContact(e)
end

function LF_Bullet:onPostSolveContact(e)
end

function LF_Bullet:onEndContact(e)
end

这是一个使用 gideros mobile http://giderosmobile.com/用LUA编写的快速示例。

关于box2d的必选网站当然是: https://www.iforce2d.net/b2dtut/

这是一个广泛的主题,您可能需要关注一些youtube tut。即使它不是用py编写的,box2d的工作原理也一样,因此您只需要适应py。 一些链接可能会有所帮助: https://www.youtube.com/playlist?list=PLZm85UZQLd2SXQzsF-a0-pPF6IWDDdrXt

这就是我使用box2d学习的方法。希望有帮助吗?