Box2d 中快速移动的物体有时会相互穿过
我知道 Box2d 世界中快速移动的物体会产生隧道效应并相互穿过。解决方案是将尸体定义为子弹。我这样做了,但身体有时仍然会相互交叉,特别是如果相遇点不完全朝向中间并且身体在交叉时部分重叠。有什么解决办法吗?
这就是我制作所有物体的方式:
redBall = [CCSprite spriteWithFile:@"red-ball" rect:CGRectMake(0, 0, 34, 34)];
redBall.tag = 1;
[self addChild:redBall];
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set((winSize.width/2)/PTM_RATIO, redBall.position.y/PTM_RATIO);
ballBodyDef.userData = redBall;
ballBodyDef.bullet = true;
_ballBody = _world->CreateBody(&ballBodyDef);
// Create circle shape
b2CircleShape circle;
circle.m_radius = 17.0/PTM_RATIO;
// Create shape definition and add to body
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 0.2f;
ballShapeDef.friction = 0.0f;
ballShapeDef.restitution = 1.0f;
_ballFixture = _ballBody->CreateFixture(&ballShapeDef);
我在 TouchesEnd 中移动这个球,如下所示:
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGPoint shootVector = ccpSub(location, striker.position);
CGFloat shootAngle = ccpToAngle(shootVector);
CGPoint normalizeShootVector = ccpNormalize(shootVector);
float x1 = - cos(shootAngle);
float y1 = - sin(shootAngle);
int power = 0;
float dist =ccpDistance(location, redBall.position);
if (dist >= 200)
power = 20;
else if (dist >= 100)
power = 10;
else if (dist >=75)
power = 7;
else if (dist >= 60)
power = 4;
else if (dist >= 50)
power = 3;
else if (dist >= 35)
power = 2;
else
power = 1;
b2Vec2 force = b2Vec2(x1*power, y1*power);
_ballBody->ApplyLinearImpulse(force,ballBodyDef.position);
}
这只是计算触摸点到球的距离,根据距离找到施加在球上的力量,然后将球移动到触碰。这个球会与任何其他挡住它的球发生碰撞。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
让我进一步详细说明达菲莫的回答。
还记得 CCLayer 的
tick
方法包含以下代码吗?:两个 int32 变量告诉 box2D 应该执行多少次迭代(即传递)来施加力、检测碰撞等。根据 box2D手册,增加这些值会以性能为代价提高模拟的准确性,反之亦然,减少这些值。因此,我建议您调整这些值,尤其是positionIterations,直到您对结果满意为止。
编辑:
这是另一个建议。再次记住
tick
方法的调用速率与 fps 相同,即每秒最多 60 帧?这意味着b2World::Step
函数以 1/60 秒的间隔进行离散模拟,因此如果快速移动的物体所用时间少于该时间,则它可以设法穿过另一个物体。因此,要解决这个问题,您需要提高离散模拟的频率,假设达到每秒 180 步。但问题是如何? Cocos2D-iPhone 为每一帧调用tick
方法,增加帧速率(如果可能的话)会降低性能并浪费所有处理能力。以下是在不更改帧速率的情况下通过在同一周期内多次调用
b2World::Step
函数来实现此目的的方法:Let me elaborate further on duffymo's answer.
Remember the CCLayer's
tick
method contains the following codes?:The two int32 variables tell box2D how many iterations (i.e. passes) it should do to apply forces, detect collisions etc. According to box2D manual, increasing these values improves the accuracy of the simulation at the cost of performance, and vice versa for decreasing these values. So I would suggest you tweak these values, especially the positionIterations, until you are satisfied with the result.
EDIT:
Here is another suggestion. Remember again that the
tick
method is being called at the same rate as the fps, which is at most 60 per second? That means theb2World::Step
function is doing discrete simulation at 1/60 second intervals, so a fast moving body manage to pass through another body if it takes less than that amount of time. So to solve this, you need to increase the frequency of the discrete simulation, let's say to 180 steps per second. But the question is how? Cocos2D-iPhone calls thetick
method for every frame, and increasing the framerate (if it's even possible) will reduce the performance and waste all the processing power.Here's how you can do it without changing the framerate, by calling the
b2World::Step
function a couple of times within the same tick:您需要改进渗透检测:提高空间或时间或两者的灵敏度。
You need to refine your penetration detection: increase the sensitivity in either space or time or both.