我正在使用Box2D第一次认真对待我正在制作的中型Flash游戏。我目前使用Box2D的经验仅限于创建一个世界,身体,并以功能的方式将这些身体添加到世界。
我发现将Box2D集成到我的游戏环境中很容易,维护编写良好的代码并完成了一些处理碰撞的教程。我现在面临的问题是我的游戏会有很多身体,每个身体都以不同的方式与其他身体互动,而且我发现很难编写自己的b2ContactListener
子类而不会让它变得非常混乱。< / p>
根据我使用的教程,我创建了自己的b2ContactListener
子类,并添加了BeginContact()
方法的覆盖。 BeginContact()
在调用时收到的参数将引用b2Contact
的实例,通过该实例,我可以访问两个b2Fixture
实例(两个已发生冲突的实例)。然后,我可以访问与每个b2Body
相关联的b2Fixture
实例。
问题:目前我有一种迂回的方法可以找出两个相撞的东西(即它们是墙和导弹,还是玩家和树等)使用GetUserData()
并将其作为示例:
var f1Player:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Player
var f2Player:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Player
var f1Tree:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Tree
var f2Tree:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Tree
// ... continutes with all possible combinations.
// Example of managing a collision:
if(f1Player && f2Tree)
{
// Player (FixtureA) and Tree (FixtureB)
}
if(f2Player && f1Tree)
{
// Player (FixtureB) and Tree (FixtureA)
}
正如您所看到的,这将导致极长且无法管理。我还必须编写每组动作执行两次以满足某个元素为FixtureA或FixtureB,反之亦然(显然是以函数调用的形式,参数交换而不是字面重写)。
这显然不是正确的方法,但我无法找到更全面解释碰撞检测管理的资源。
是否有人使用可以共享的Box2D进行碰撞检测管理?另外,使用SetUserData( entityThatOwnsTheBody );
正确使用该方法的方法是什么?
答案 0 :(得分:2)
是的,确实有点令人讨厌。实际上我认为你拥有它的方式非常典型。
fwiw Box2D在测试灯具是否重叠时必须处理类似的问题。有一堆功能,如b2CollideCircles,b2CollidePolygonAndCircle,b2CollidePolygons等,当两个灯具相互靠近时,引擎会选择应该使用哪些功能。
它通过将函数指针放在一个二维数组中来实现,然后使用两个形状类型作为索引在该数组中查找相应的函数。有关详细信息,请参阅b2Contact.cpp中的前三个函数。
当然,如果你不能在AS3中传递这样的函数引用,那么我想这个答案没有多大帮助,但我认为无论如何我会发布,因为C / C ++ / JS用户可能会来。
答案 1 :(得分:1)
我使用了c++
版Box2d
,但我认为同样的方法可以在actionscript中使用。我创建了一个类Object
,它包含一个b2Body *_body
指针和一个指向图形表示的指针。 _body
的{{1}}被设置为指向UserData
。 class Object *
有以下方法:
Object
在virtual bool acceptsContacts ();
virtual void onContactBegin (const ContactData &data);
virtual void onContactEnded (const ContactData &data);
virtual void onContactPreSolve (const ContactData &data);
virtual void onContactPostSolve (const ContactData &data);
子类中检测到碰撞时,它会检查碰撞的物体是否有用户数据。如果是这样,它将用户数据转换为b2ContactListener
,如果任何冲突的对象接受了联系人 - 它创建了Object*
(一个包含有关冲突的所有必需信息的类)并将其放入其内部{{1稍后交付。
返回ContactData
方法后,list
会将所有联系信息提供给要处理的对象。交付延迟,以便您可以在处理碰撞时(在执行更新时不允许)创建新的实体,关节等等。
此外,如果在碰撞处理过程中删除了其中一个碰撞的主体,您必须通知b2World::update
(只需在ContactListener
内放一个指针),这样就可以使相应的联系人无效而不会传递它们
答案 2 :(得分:1)
我提出了比原作更好的东西。
首先,我只是让我的Being
课程(拥有b2Body
)将自己设置为其身体&#39; UserData
。此类还将包含onContact()
方法,类似于以下内容:
public class Being
{
private var _body:b2Body;
public function Being()
{
// Define the body here.
// ...
_body.SetUserData(this);
}
public function onCollision(being:Being = null):void
{
//
}
}
然后在我自己的b2ContactListener
实现中,我只是传递了碰撞Being
(如果没有Being
分配给碰撞b2Body
&#39;则为空。 s UserData
)反对Being
&#39; s onCollision()
:
override public function BeginContact(contact:b2Contact):void
{
var bodyA:b2Body = contact.GetFixtureA().GetBody();
var bodyB:b2Body = contact.GetFixtureB().GetBody();
var beingA:Being = bodyA.GetUserData() as Being || null;
var beingB:Being = bodyB.GetUserData() as Being || null;
beingA && beingA.onCollision(beingB);
beingB && beingB.onCollision(beingA);
}
最后在Being
的每个子类中,我可以轻松地为某种类型的其他Being
之间的碰撞准备逻辑:
class Zombie extends Being
{
override public function onCollision(being:Being = null):void
{
if(being && being is Bullet)
{
// Damage this Zombie and remove the bullet.
// ...
}
}
}