Как переместить спрайт с телом динамической физики с постоянной скоростью

До недавнего времени я просто менял координату x моего спрайта при каждом обновлении, и я был доволен этим. Но вчера, находясь в режиме отладки, я обнаружил, что после определенной скорости физическое тело не будет правильно выравниваться со спрайтом, например: введите здесь описание изображения Позже мне сказали (от Birkemose на форуме cocos2d), что предпочтительным способом перемещения физического тела из A в B является приложение к нему импульса. Но я понятия не имею, как добиться постоянной скорости таким образом. Это код, который я использовал для перемещения без применения какого-либо импульса:

-(void)update:(CCTime)delta{
    rollingHero.position=ccp(rollingHero.position.x+scrollSpeed*delta,    
                         rollingHero.position.y);
    physicsNode.position=ccp(physicsNode.position.x-scrollSpeed*delta,
                         physicsNode.position.y);
}

Поэтому, чтобы создать ощущение движения, я прокручиваю узел физики и героя в противоположных направлениях с одинаковой скоростью прокрутки. Я пробовал много разных вариантов подачи импульса, но так и не смог заставить его двигаться с постоянной скоростью. Скорость увеличивается, и герой оказывается за кадром. Буду очень признателен, если кто-нибудь опубликует пример кода.


person Mikayil Abdullayev    schedule 01.11.2014    source источник


Ответы (1)


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

static const float kRollingHeroMoveSpeed     = 10.f;
static const float kRollingHeroAccelConstant = 10.f;

-(void)update:(CCTime)delta {

    // check velocity of sprite
    if(_rollingHero.physicsBody.velocity.x < kRollingHeroMoveSpeed) {

        // if velocity is under limit, push character
        [_rollingHero.physicsBody applyImpulse:ccp(kRollingHeroAccelConstant, 0)];
    }
}

Лучший способ сделать это — перейти на уровень C физического движка Chipmunk2D, лежащего в основе физики Cocos2D.

-(void)onEnter {
    [super onEnter];

    // tell physics engine to use our C function to update physics body
    _rollingHero.physicsBody.body.body->velocity_func = playerUpdateVelocity;
}

static void playerUpdateVelocity(cpBody *body, 
                                 cpVect gravity, 
                                 cpFloat damping, 
                                 cpFloat dt) {

    // check validity of cpBody
    cpAssertSoft(body->m > 0.0f && body->i > 0.0f, "Body's mass and moment must be positive to simulate. (Mass: %f Moment: %f)", body->m, body->i);

    // update velocity and angular velocity
    body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));
    body->w = body->w*damping + body->t*body->i_inv*dt;

    // reset force vector
    body->f = cpvzero;
    // reset torque
    body->t = 0.0f;

    // set body's velocity to desired velocity
    body->v.x = kRollingHeroMoveSpeed;
}

Вот cpBody.h на Github.

person Morgan Chen    schedule 02.11.2014
comment
Спасибо за идеальный и подробный ответ - person Mikayil Abdullayev; 02.11.2014