如何使用 PyBox2d 检测碰撞并使用该信息
How to detect collision using PyBox2d and use that information
我正在尝试通过重现此示例来过滤发生在我的 Box2D 世界中的碰撞:https://github.com/pybox2d/pybox2d/blob/master/examples/collision_filtering.py
我的世界里有四个 classes,汽车、车轮、建筑物和行人,我想过滤哪个实例与哪个实例发生碰撞,其中一个可能的输出是 (pseudo-code)
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)
我在给定的 classes 中应用它(为简单起见,仅 class 行人作为示例显示):
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
绘制身体和 运行 世界
但我对如何继续感到困惑,我如何使用来自碰撞过滤器的信息来打印上面关于事故的句子?
非常感谢
编辑:我找到了一个 link 可以解决我想做的事情,但它是用 C++ 编写的,我不明白
http://www.iforce2d.net/b2dtut/collision-callbacks
嘿,我刚刚在 stackexchange 上回答了你的问题:-)
碰撞很简单:
local filterData = {
categoryBits = player,
maskBits = wall + nme + platform,
groupIndex = 0
}
fixture:setFilterData(filterData)
player, wall, nme, ... 是整数变量(必须是2个数的幂):
player = 1
wall = 2
nme = 4
... = 16, 32, 64, 128, 256, ...
categoryBits = 要测试碰撞的主要对象
maskBits = 你add(带+)主物体可以碰撞的所有数字。
最好将数字存储为变量,否则它看起来像:
local filterData = {
categoryBits = 1,
maskBits = 2 + 4 + 8 + 16 ...,
groupIndex = 0
}
fixture:setFilterData(filterData)
:-)
为了回答你的第二条评论,它更复杂,所以我将其添加为另一个答案。
您不会自己处理碰撞,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 tuts。即使不是用py写的,box2d也一样,所以你只需要适应py。
一些可能有帮助的链接:
https://www.youtube.com/playlist?list=PLZm85UZQLd2SXQzsF-a0-pPF6IWDDdrXt
这就是我学习使用 box2d 的方式。希望对您有所帮助?
我正在尝试通过重现此示例来过滤发生在我的 Box2D 世界中的碰撞:https://github.com/pybox2d/pybox2d/blob/master/examples/collision_filtering.py
我的世界里有四个 classes,汽车、车轮、建筑物和行人,我想过滤哪个实例与哪个实例发生碰撞,其中一个可能的输出是 (pseudo-code)
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)
我在给定的 classes 中应用它(为简单起见,仅 class 行人作为示例显示):
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
绘制身体和 运行 世界但我对如何继续感到困惑,我如何使用来自碰撞过滤器的信息来打印上面关于事故的句子?
非常感谢 编辑:我找到了一个 link 可以解决我想做的事情,但它是用 C++ 编写的,我不明白 http://www.iforce2d.net/b2dtut/collision-callbacks
嘿,我刚刚在 stackexchange 上回答了你的问题:-)
碰撞很简单:
local filterData = {
categoryBits = player,
maskBits = wall + nme + platform,
groupIndex = 0
}
fixture:setFilterData(filterData)
player, wall, nme, ... 是整数变量(必须是2个数的幂):
player = 1
wall = 2
nme = 4
... = 16, 32, 64, 128, 256, ...
categoryBits = 要测试碰撞的主要对象
maskBits = 你add(带+)主物体可以碰撞的所有数字。
最好将数字存储为变量,否则它看起来像:
local filterData = {
categoryBits = 1,
maskBits = 2 + 4 + 8 + 16 ...,
groupIndex = 0
}
fixture:setFilterData(filterData)
:-)
为了回答你的第二条评论,它更复杂,所以我将其添加为另一个答案。
您不会自己处理碰撞,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 tuts。即使不是用py写的,box2d也一样,所以你只需要适应py。 一些可能有帮助的链接: https://www.youtube.com/playlist?list=PLZm85UZQLd2SXQzsF-a0-pPF6IWDDdrXt
这就是我学习使用 box2d 的方式。希望对您有所帮助?