在上部点上的棱柱形接头(b2PrismaticJointDef)上的提升块给动力体提供了冲击力,即使提升块根本不移动,也会放置在提升块表面上。
也许是javascript端口的bug。但是我想修理它,因为我需要在游戏中使用电梯。
我使用了Box2DFlash 2.1a https://code.google.com/p/box2dweb/的 box2dweb javascript端口。
以下是关于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;
}
答案 0 :(得分:0)
我使用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)。
当然,在我的项目的其他地方,我有定时器运行,根据需要重置升降机机身和关节电机属性(使其向上移动,然后通过以正值反转接头的电机速度来向下移动)。
当电梯在另一个(底部)极限附近转换时,我没有实施加速/减速技术,因为当电梯停止时我不关心乘坐电梯的东西在这个方向上施加的力。但是,当电梯从底部离开或返回底部时,可以使用与上述相同的方法平稳地加速或减速......