Box2D динамическое тело застревает (iPhone) - PullRequest
1 голос
/ 05 июля 2011

У меня есть наземный объект и объект в форме копья (динамический).Когда кнопка нажата, линейная скорость применяется к копью.Работает нормально, но иногда застревает на земле.Это происходит в большинстве случаев (не всегда), когда сторона, противоположная шкуре копья, сталкивается прямо с землей.Я прилагаю некоторые изображения, чтобы вы, ребята, получили картинку: enter image description here

Вот мой код:

#import "HelloWorldLayer.h"

#define PTM_RATIO 32


@implementation HelloWorldLayer

+(CCScene *) scene{
    CCScene *scene = [CCScene node];

    HelloWorldLayer *layer = [HelloWorldLayer node];
    [scene addChild: layer];

    return scene;
}

-(id) init {

    if( (self=[super init])) {

        isSimulating = NO;

        CGSize winSize = [CCDirector sharedDirector].winSize;

        self.isAccelerometerEnabled = YES;
        self.isTouchEnabled = YES;

        // Create sprite and add it to the layer
        _spear = [CCSprite spriteWithFile:@"image_SPEAR.png"];
        _spear.position = ccp(40, 30);

        [self addChild:_spear];


        label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:20];
        CGSize size = [[CCDirector sharedDirector] winSize];
        label.position =  ccp( size.width /2 , size.height/2 );
        [self addChild: label];

        CCMenuItem *starMenuItem = [CCMenuItemImage 
                                    itemFromNormalImage:@"ball.png" selectedImage:@"ball.png" 
                                    target:self selector:@selector(starButtonTapped:)];
        starMenuItem.position = ccp(60, 250);
        CCMenu *starMenu = [CCMenu menuWithItems:starMenuItem, nil];
        starMenu.position = CGPointZero;
        [self addChild:starMenu];


        // Create a world
        b2Vec2 gravity = b2Vec2(0.0f, -20.0f);
        bool doSleep = true;
        _world = new b2World(gravity, doSleep);

        // Create edges around the entire screen
        b2BodyDef groundBodyDef;
        groundBodyDef.position.Set(0,0);
        b2Body *groundBody = _world->CreateBody(&groundBodyDef);
        b2PolygonShape groundBox;
        b2FixtureDef boxShapeDef;
        boxShapeDef.shape = &groundBox;
        groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
        groundBody->CreateFixture(&boxShapeDef);
        groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
        groundBody->CreateFixture(&boxShapeDef);
        groundBox.SetAsEdge(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
        groundBody->CreateFixture(&boxShapeDef);
        groundBox.SetAsEdge(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
        groundBody->CreateFixture(&boxShapeDef);
        boxShapeDef.friction = 0.3f;


        [self setup];

    }
    return self;
}

- (void)setup {

    NSLog(@"Setting up...");
    //set the sprite's initial position
    _spear.position = ccp(40, 30);
    _spear.rotation = 0.0f;


    //row 1, col 1
    int num = 7;
    b2Vec2 verts[] = {
        b2Vec2(-36.0f / PTM_RATIO, -2.7f / PTM_RATIO),
        b2Vec2(20.1f / PTM_RATIO, -2.1f / PTM_RATIO),
        b2Vec2(24.4f / PTM_RATIO, -4.6f / PTM_RATIO),
        b2Vec2(36.7f / PTM_RATIO, -1.4f / PTM_RATIO),
        b2Vec2(23.9f / PTM_RATIO, 2.7f / PTM_RATIO),
        b2Vec2(20.7f / PTM_RATIO, 0.0f / PTM_RATIO),
        b2Vec2(-36.0f / PTM_RATIO, -0.5f / PTM_RATIO)
    };






    // Create spear body and shape
    b2BodyDef spearBodyDef;
    spearBodyDef.type = b2_dynamicBody;
    spearBodyDef.position.Set(40.0/PTM_RATIO, 30.0/PTM_RATIO);
    //spearBodyDef.angle =  45.0 * (180.0f/b2_pi);
    spearBodyDef.userData = _spear;
    _spearBody = _world->CreateBody(&spearBodyDef);

    b2PolygonShape spearShape;
    spearShape.Set(verts, num);

    b2FixtureDef spearShapeDef;
    spearShapeDef.shape = &spearShape;
    spearShapeDef.density = 0.75f;
    spearShapeDef.friction = 0.2f;
    spearShapeDef.restitution = 0.2f;
    _spearBody->CreateFixture(&spearShapeDef);

}


- (void)starButtonTapped:(id)sender {

    if (isSimulating) {
        NSLog(@"Not simulating now...");

        [self unschedule:@selector(tick:)];
        _world->DestroyBody(_spearBody);
        _spearBody = NULL;
        [self setup];
    } else {
        NSLog(@"Simulating now...");
        [self schedule:@selector(tick:)];

        float angle = _spearBody->GetAngle();

        b2Vec2 force;
        force.Set(cos(angle) * 15.0f , sin(angle) * 15.0f);
        _spearBody->SetLinearVelocity(force);
    }
    isSimulating = !isSimulating;

}

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    if (!isSimulating) {

        UITouch* touch = [touches anyObject];
        CGPoint location = [touch locationInView: [touch view]];
        location = [[CCDirector sharedDirector] convertToGL: location];

        float angleRadians = atanf((float)location.y / (float)location.x);
        float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);

        _spear.rotation = -1 * angleDegrees;
        _spearBody->SetTransform(_spearBody->GetPosition(), angleRadians);

        [label setString:[NSString stringWithFormat:@"Angle: %f    X: %f    Y:%f", angleDegrees, location.x, location.y]];
        NSLog(@"%@", @"touched");

    }

}



- (void)tick:(ccTime) dt {
    _world->Step(dt, 10, 10);
    for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {    
        if (b->GetUserData() != NULL) {
            CCSprite *ballData = (CCSprite *)b->GetUserData();
            ballData.position = ccp(b->GetPosition().x * PTM_RATIO,
                                    b->GetPosition().y * PTM_RATIO);
            ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
        }        
    }
}

- (void) dealloc {
    delete _world;
    _world = NULL;

    [super dealloc];
}
@end

Я предполагаю, что это связано с трением и реституцией, но я попробовалмного ценностей и ничто не заставляет это поведение уходить.Спасибо.

** ОБНОВЛЕНИЕ: ** Я выяснил, что вызывает это.Каждый раз, когда он застревает, это когда копье выходит за пределы земли.Каждый раз.Но зачем вообще выходить за пределы земли?Вот изображение, показывающее это.Внизу копье находится снаружи тела: enter image description here

Ответы [ 4 ]

3 голосов
/ 05 июля 2011

Попробуйте отключить сон ...

bool doSleep = false;
_world = new b2World(gravity, doSleep);

У меня была похожая проблема в одной из моих игр на базе box2d, и именно эта «особенность» и послужила причиной этого.

2 голосов
/ 10 октября 2012

обратите внимание, что в последней версии Cocos2D вам необходимо использовать следующее, чтобы предотвратить такое поведение прилипания:

_world->SetAllowSleeping(false);
1 голос
/ 05 июля 2011

На самом деле box2D имеет итерационный решатель. Таким образом, качество моделирования напрямую зависит от количества итераций. Попробуйте увеличить итерацию положения и / или скорости, делая Step. Также убедитесь, что вы используете фиксированный временной шаг (обычно это дает лучшие результаты). А также, если ваше копье движется быстро, попробуйте включить непрерывную физику и установить тело копья в качестве пули (свойство b2BodyDef).

1 голос
/ 05 июля 2011

Ваша форма копья не выпуклая.Я настоятельно рекомендую вам использовать функцию отладочной отрисовки Box2D, чтобы время от времени проверять.http://www.iforce2d.net/b2dtut/debug-draw

Вот как на самом деле выглядит многоугольник - линии - это то, что вы указали, затененная область - это то, что вы получили:

enter image description here

...