How to detect collision using PyBox2d and use that information

梦想的初衷 提交于 2020-01-25 00:20:49

问题


I am trying to filter collisions occurring in my Box2D world by reproducing this example: https://github.com/pybox2d/pybox2d/blob/master/examples/collision_filtering.py

I have four classes in my world, Car, Wheel, Building, and Pedestrian, I want to filter which instance collided with which and one of the possible outputs is (pseudo-code)

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

I have this set of categories


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

I also tried this: but it doesn't work (it does nothing)

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)

and I apply this in given classes (only class Pedestrian shown as example for simplicity):

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}

And then I draw the bodies and run the world using pygame

But I am confused about how to continue, how could I use the information from the collisionfilter to be able to for example print the sentence about the accident from above?

Thank you very much EDIT: I have found a link which solves exactly what I want to do, but it is written in C++ and I do not understand it http://www.iforce2d.net/b2dtut/collision-callbacks


回答1:


to answer your second comment that is more complex so I add it as another answer.

You don't handle collisions yourself, Box2D does it for you but you need to set things up.

- create your world

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

- attach listeners to your world (for collisions handling)

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)

- in your game loop you need to call Box2D update

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

- then ANSWER IS HERE you check collisions for each objects in those box2d functions listeners

-- 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

This is a quick example written in LUA using gideros mobile http://giderosmobile.com/.

A must website regarding box2d is of course: https://www.iforce2d.net/b2dtut/

It is a vast subject and you may want to follow some youtube tuts. Even if it is not written in py, box2d works the same so you just have to adapt to py. Some links that may help: https://www.youtube.com/playlist?list=PLZm85UZQLd2SXQzsF-a0-pPF6IWDDdrXt

That's how I learned using box2d. Hope that helps?




回答2:


hey I just answered your question on stackexchange :-)

For collisions it's easy:

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

player, wall, nme, ... are integers variables (must be power of 2 numbers):

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

categoryBits = main object you want to test collisions on

maskBits = you add (with +) all the numbers the main object can collide with.

It's better to store the numbers as variables otherwise it would look like:

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

:-)



来源:https://stackoverflow.com/questions/58710804/how-to-detect-collision-using-pybox2d-and-use-that-information

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!