即使抬升块根本不动,位于较高点的棱柱形接头(b2PrismaticJointDef)上的抬升块也会对位于抬升块表面上的动态物体产生冲击。

也许是javascript端口的错误。但是我想修复它,因为我在游戏中需要电梯。

更新v1

我已使用Box2DFlash 2.1a https://code.google.com/p/box2dweb/的box2dweb javascript端口。

更新v2

这是Flash http://hyzhak.github.com/darlingjs/performance/box2dweb/上的类似演示,它具有相同的问题,因此可能在Flash或原始Box2D引擎上存在此问题。

http://jsfiddle.net/hyzhak/2kjDZ/

var b2Vec2 = Box2D.Common.Math.b2Vec2,
    b2BodyDef = Box2D.Dynamics.b2BodyDef,
    b2Body = Box2D.Dynamics.b2Body,
    b2FixtureDef = Box2D.Dynamics.b2FixtureDef,
    b2World = Box2D.Dynamics.b2World,
    b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,
    b2CircleShape = Box2D.Collision.Shapes.b2CircleShape,
    b2DebugDraw = Box2D.Dynamics.b2DebugDraw,
    b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef;

(function() {
    var world = buildWorld();

    var leftBlock = buildBlock({world: world, x: 2, y: 8, width: 2, height: 12, static: true});
    var rightBlock = buildBlock({world: world, x: 12, y: 8, width: 2, height: 12, static: true});
    var bottomBlock = buildBlock({world: world, x: 7, y: 13, width: 8, height: 2, static: false});
    var box = buildBlock({world: world, x: 7, y: 10, width: 2, height: 2, static: false});

    var joint = buildPrismaticJoint({world: world,
                                     anchorA: new b2Vec2(7, 13),
                                     axis: new b2Vec2(0, 1),
                                     bodyA: bottomBlock,
                                     bodyB: world.GetGroundBody()});

    var debugDraw = buildDebugDraw(world);

    setInterval(function(){
        world.Step(1 / 60, 10, 10);
        world.DrawDebugData();
        world.ClearForces();
    },1000/60);
})();

function buildWorld() {
    return new b2World(
        new b2Vec2(0, 10), //gravity vector
        true
    );
}

function buildBlock(state) {
    var fixDef = new b2FixtureDef;
    fixDef.shape = new b2PolygonShape;
    fixDef.density = 1.0;
    fixDef.friction = 0.5;
    fixDef.restitution = .5;
    fixDef.shape.SetAsBox(state.width / 2, state.height / 2);
    var bodyDef = new b2BodyDef;
    bodyDef.type = state.static?b2Body.b2_staticBody:b2Body.b2_dynamicBody;
    bodyDef.position.Set(state.x, state.y);
    var body = state.world.CreateBody(bodyDef);
    body.CreateFixture(fixDef);
    return body;
}

//buildPrismaticJoint(world, 9, 15, 0, 1, bottomBlock, world.GetGroundBody());
function buildPrismaticJoint(state) {
    var jointDef = new b2PrismaticJointDef();
    jointDef.Initialize(state.bodyA, state.bodyB, state.anchorA, state.axis);
    jointDef.collideConnected = false;
    jointDef.lowerTranslation = 0.0;
    jointDef.upperTranslation = 5.0;
    jointDef.enableLimit = true;
    jointDef.maxMotorForce = 400.0;
    jointDef.motorSpeed = 3.0;
    jointDef.enableMotor = true;
    return state.world.CreateJoint(jointDef);
}

function buildDebugDraw(world) {
    var debugDraw = new b2DebugDraw();
    debugDraw.SetSprite(document.getElementById("playground").getContext("2d"));
    debugDraw.SetDrawScale(20.0);
    debugDraw.SetFillAlpha(0.5);
    debugDraw.SetLineThickness(1.0);
    debugDraw.SetFlags(
        b2DebugDraw.e_shapeBit |
        b2DebugDraw.e_jointBit |
        b2DebugDraw.e_aabbBit |
        b2DebugDraw.e_pairBit |
        b2DebugDraw.e_centerOfMassBit |
        b2DebugDraw.e_controllerBit
    );
    world.SetDebugDraw(debugDraw);

    return debugDraw;
}

最佳答案

使用Box2D v2.2.1 C ++代码遇到相同的问题。我在静态物体和运动(动态)物体之间使用b2PrismaticJoint来模拟“提升”(或提升)。

当举升机沿棱柱关节到达平移的上端时,它似乎停止了。但是,当另一个车身坐在升降机顶部并到达平移的上端时,升降机顶部的车身开始“反弹”,好像升降机仍在施加力。 (我相信这就是正在发生的情况,即升降机的车身沿棱柱形关节并没有进一步平移,但是棱柱形关节的马达仍在转动,并向车身施加向上的力)。

我最初通过在达到平移上限时手动将棱柱关节的电动机速度设置为0.0来解决此问题。在我的主要游戏循环中,即以帧频调用的函数(在Box2D中为“ tick:”或在Cocos2D中为“ update:”),我插入了以下内容(我在这里使用Objective-C,而kLiftJointValue是任意整数常量):

// Iterate over all joints (used to prevent upper end oscillations from psimaticJoints on lifts)
for (b2Joint* j = world->GetJointList(); j; j = j->GetNext())
{
    if ((int)(j->GetUserData()) == kLiftJointValue) // check to see if lift is at upper end of translation
    {
        CGFloat currentTranslation = ((b2PrismaticJoint*)j)->GetJointTranslation();
        CGFloat lowerLimit = ((b2PrismaticJoint*)j)->GetLowerLimit();
        CGFloat upperLimit = ((b2PrismaticJoint*)j)->GetUpperLimit();
        b2Body *bodyA = j->GetBodyA();
        b2Body *bodyB = j->GetBodyB();
        BOOL notStopped = (bodyA->GetType() == b2_dynamicBody || bodyB->GetType() == b2_dynamicBody);

        if (fabsf(currentTranslation - lowerLimit) <= 0.01*(upperLimit - lowerLimit) && notStopped )
        {
            CCLOG(@"Stopping platform");
            (j->GetBodyA())->SetType(b2_staticBody);
            (j->GetBodyB())->SetType(b2_staticBody);
            ((b2PrismaticJoint*)j)->SetMotorSpeed(0.0);
        }
    }
}


上面的代码简单地遍历世界上的所有关节,并寻找适当标记的关节,如果身体已平移到允许的最大平移范围的1%之内,则移动的身体将变为静态,并且可以通过设置电机来禁用电机速度为0。您还可以使用Box2D碰撞检测,然后将关节的电动机速度设置为0 ...

然后,我意识到实现此举升的最佳方法(不打扰举升器顶部的任何物体)是逐渐使棱镜接头的电机速度逐渐减速。这是我的方法:

// Iterate over all joints (used to prevent upper end oscillations from psimaticJoints on lifts)
for (b2Joint* j = world->GetJointList(); j; j = j->GetNext())
{
    if ((int)(j->GetUserData()) == kLiftJointValue) // check to see if lift is at upper end of translation
    {
        CGFloat currentTranslation = ((b2PrismaticJoint*)j)->GetJointTranslation();
        CGFloat lowerLimit = ((b2PrismaticJoint*)j)->GetLowerLimit();
        CGFloat upperLimit = ((b2PrismaticJoint*)j)->GetUpperLimit();
        b2Body *bodyA = j->GetBodyA();
        b2Body *bodyB = j->GetBodyB();
        BOOL notStopped = (bodyA->GetType() == b2_dynamicBody || bodyB->GetType() == b2_dynamicBody);

        if (fabsf(currentTranslation - lowerLimit) <= 0.25*(upperLimit - lowerLimit) && notStopped)
        {
            // Get current motor speed and update
            CGFloat currentSpeed = ((b2PrismaticJoint*)j)->GetMotorSpeed();
            CGFloat newSpeed;

            if (currentSpeed < 0.0)
            {
                if (fabsf(currentTranslation - lowerLimit) <= 0.01*(upperLimit - lowerLimit) && notStopped )
                {
                    CCLOG(@"Stopping platform");
                    (j->GetBodyA())->SetType(b2_staticBody);
                    (j->GetBodyB())->SetType(b2_staticBody);
                    ((b2PrismaticJoint*)j)->SetMotorSpeed(0.0);
                }
                else
                {
                    CCLOG(@"Decelerating: speed=%f", currentSpeed);
                    newSpeed = 0.95*currentSpeed;
                }
            }
            else if (currentSpeed > 0.0)
            {
                CCLOG(@"Accelerating: speed=%f", currentSpeed);

                newSpeed = 1.05*currentSpeed;

                if (newSpeed > 20.0)
                    newSpeed = 20.0;
            }

            // update motor speed
            ((b2PrismaticJoint*)j)->SetMotorSpeed(newSpeed);
        }
    }
}


您需要使用各种常数(尤其是常数0.95和1.05),因为它们已针对特定的电动机属性(在我的情况下为maxMotorForce = 1000和motorSpeed = 20)进行了微调。

当然,在我项目的其他地方,我都在运行计时器,这些计时器可以根据需要重置举升机体和关节电机的性能(以使其升起,然后通过将关节的电机速度反转为正值来使其回退)。

当升降机平移到另一个(底部)极限附近时,我没有实施加速/减速技术,因为我不关心升降机停止时乘坐该升降机的东西在该方向上的作用力。但是,当升降机从底部离开或返回底部时,可以使用与上述相同的方法平稳地加速或减速...

关于javascript - Box2D引擎的javascript端口的棱柱关节的奇怪行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15760919/

10-12 02:49