Быстро движущиеся тела в Box2d иногда проходят сквозь друг друга - PullRequest
4 голосов
/ 19 марта 2011

Я знаю, что быстро движущиеся тела в мире 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);      
}

Это просто расчет расстояния точки касания от мяча, нахождение силы, применяемой к мячу, в зависимости от расстояния и перемещение мяча в направлении касания. И этот шар сталкивается с любым другим шаром, который встречается на его пути.

Ответы [ 2 ]

5 голосов
/ 22 марта 2011

Позвольте мне подробнее остановиться на ответе Даффимо.

Помните, что метод CCLayer tick содержит следующие коды?:

int32 velocityIterations = 8;
int32 positionIterations = 1;

world->Step(dt, velocityIterations, positionIterations);

Две переменные int32 сообщают box2D, сколько итераций (то есть проходов) нужно выполнить, чтобы приложить силы, обнаружить столкновения и т. Д. Согласно руководству box2D , увеличение этих значений повышает точность моделирования за счет затрат. производительности, и наоборот для уменьшения этих значений. Поэтому я бы посоветовал вам настроить эти значения, особенно положения позиции, до тех пор, пока вы не будете удовлетворены результатом.

EDIT:

Вот еще одно предложение. Помните еще раз, что метод tick вызывается с той же скоростью, что и частота кадров в секунду, то есть максимум 60 в секунду? Это означает, что функция b2World::Step выполняет дискретное моделирование с интервалами 1/60 секунды, поэтому быстро движущемуся телу удается пройти через другое тело, если для этого требуется меньше времени. Таким образом, чтобы решить эту проблему, вам нужно увеличить частоту дискретного моделирования, скажем, до 180 шагов в секунду. Но вопрос в том, как? Cocos2D-iPhone вызывает метод tick для каждого кадра, а увеличение частоты кадров (если это возможно) приведет к снижению производительности и потере всей вычислительной мощности.

Вот как вы можете сделать это без изменения частоты кадров, вызвав функцию b2World::Step пару раз в течение одного такта:

int32 velocityIterations = 8;
int32 positionIterations = 1;
uint substeps = 3;
float32 subdt = dt / substeps;

for (uint i = 0; i < substeps; i++) {
    world->Step(subdt, velocityIterations, positionIterations);

    // do your physics-related stuff inside here but leave any sprites manipulation outside this loop
}
0 голосов
/ 19 марта 2011

Вам необходимо уточнить обнаружение проникновения: увеличить чувствительность либо в пространстве, либо во времени, либо в обоих случаях.

...