【问题标题】:Box2d damage physicsBox2d 损伤物理
【发布时间】:2012-06-22 01:22:03
【问题描述】:

我正在为我的项目制作类似《愤怒的小鸟》的游戏。除了最基本的:在游戏物理中提供逼真的感觉之外,大多数事情都已完成。我最挣扎的部分是伤害。我正在使用 libgdx,它提供了 Box2d 的包装器,因此代码对于任何了解 Box2d 的人来说都不应该陌生。 这是 postSolve 方法

@Override
    public void postSolve(Contact contact, ContactImpulse impulse) {    
        float[] forces = impulse.getNormalImpulses();

        int index1 = (Integer) contact.getFixtureA().getBody().getUserData();
        int index2 = (Integer) contact.getFixtureB().getBody().getUserData();

        if( forces[0] > 0.3 )
            bodies.get(index1).handleCollision(forces[0]);

        if( forces[1] > 0.3 )
            bodies.get(index2).handleCollision(forces[1]);
    }

这会拉出正在碰撞的物体并将正常的碰撞脉冲传递给它们,以便它们可以处理损坏。现在这是其中一具尸体的损坏处理函数

@Override
    public void handleCollision(float impulse) {
            health -= impulse;

            else if( health < 50 )
                isFlaggedForDelete = true;
    }

我最初根据所有身体的大小为所有身体提供健康值,并且每次发生足够强烈的碰撞时,它们都应该受到相应的伤害。

问题在于身体以图像中显示的方式排列。每当任何一个方块发生轻微的碰撞,甚至不会让它移动时,整个结构(我认为)开始振动,下面的方块被破坏(因为健康),整个结构倒塌。

我已将 b2VelocityThreshold 设置为最大值(进一步增加它会在游戏中引入身体的不良行为)。 postSolve 方法还设置了足够高的阈值。我的方法有什么问题?

谢谢。

【问题讨论】:

    标签: box2d physics


    【解决方案1】:

    我认为您在这里错误地使用了 normalImpulses 数组。尽管这个数组总是两个元素长,但它只包含与碰撞流形中的点一样多的有效值,而碰撞流形中的点通常可能只有一个。它所持有的冲量值不是针对 bodyA 和 bodyB,而是针对流形的点。

    要获得碰撞“严重”程度的正确值,您需要检查碰撞实际存在多少碰撞点,如果有两个,那么您可以取脉冲的平均值,或者最大值.

    我说的是“重”而不是“破坏”,因为即使撞击速度没有改变,对于较重的物体来说,这些冲动也会更高。 PreSolve 对所有接触的物体在每一帧都发生,所以即使你有两个几乎一动不动的物体,一个在另一个上面,如果物体很重,你仍然会得到一个很大的 normalImpulse。我想在确定碰撞是否具有破坏性之前,您需要考虑相关物体的质量。

    PostSolve 在两个灯具接触时每帧调用一次,除非它们的身体处于睡眠状态。当你说整个结构被振动损坏时,我猜只是身体在睡觉,直到它们的部分结构被碰撞,所有的 PostSolve 突然开始加起来。

    如果我是你,我会设置一个更简单的场景,比如只有一具尸体坐在地上,然后将另一具尸体放在上面。看看你从那里得到的 normalImpulse 的值,直到身体睡觉。改变它们的质量,改变下落高度等,然后再做一次,看看 normalImpulse 值是如何受到影响的。这应该让您了解在确定碰撞是否造成损坏时使用哪种阈值,或者仅仅是身体彼此重叠的结果。

    【讨论】:

    • 所以你是说 normalImpulses 数组会给我属于单个灯具的点的正常脉冲?
    • 另外你说“所以即使你有两个身体几乎一动不动地坐着,一个在另一个上面,如果身体很重,你仍然会得到一个很大的 normalImpulse”我想我实际上必须采取考虑到另一个物体的动量。
    • 接触点并不真正属于灯具,它们只是施加推动力将灯具推开的最佳位置。
    • 计算正常脉冲以将两个灯具推开,使它们不再重叠。因此,它必须抵消向下推的自然重力(如果物体堆积)以及任何碰撞的动量。将这些组件混合在一起后将它们分开可能会很棘手。一种更简单的方法是在 BeginContact 中查看两个物体第一次接触时的相对速度,但这可能有点过于简单,特别是如果您只想通过将重物放在它们身上而不产生任何影响来破坏它们。
    • 检查碰撞的两个物体的动量总和并为其设置阈值对我有用。感谢您的回答:)
    【解决方案2】:

    我认为你可以尝试减少小伤害,因为通常你真的想在某物撞到某物时施加伤害。我认为这种撞击的力量比物体振动时施加的力量要高得多。所以尝试这样的事情:

    @Override
        public void handleCollision(float impulse) {
                if (impulse > SOME_VALUE)
                    health -= impulse;
    
                if( health < 50 )
                    isFlaggedForDelete = true;
        }
    

    【讨论】:

    • if( force[0] > 0.3 ) in postSolve 做同样的事情。我不能进一步增加它。不知何故,身体振动时的正常冲动比其他身体以一定速度撞击它们时的冲动要多。也许是因为他们的体重?
    • @wirate:尝试添加阻尼。另外您使用的平均密度是多少?
    • 密度不同。他们就像4、6.5和30。问题已经解决了。谢谢:)
    【解决方案3】:

    要过滤掉自重引起的冲动,下面的代码可能会有所帮助:

    public void postSolve(Contact contact, ContactImpulse impulse) {    
    
        Fixture upperFixture = fixtureA;
        if(fixtureA.getBody().getPosition().y<fixtureB.getBody().getPosition().y)
            upperFixture = fixtureB;
    
        // don't count body weight when calculating impulse 
        float weightImpulse = 
       -upperFixture.getBody().getMass()*gravityY*worldStep; 
        // if your fps is 60, worldstep would be 1/60
    
    
        // finally we deduct impulse caused by weight from total impulse 
        float absImpulse = Math.abs(impulse.getNormalImpulses()[0]) - weightImpulse;
       // this 'absImpulse' should be zero if you put a box on the ground 
       // and don't have anything on top of the box
    
    
    }
    

    既然你知道你的盒子的设置,你也许能弄清楚多个盒子的设置。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 2017-05-21
      • 2014-07-08
      • 2012-08-13
      • 1970-01-01
      相关资源
      最近更新 更多