Cocos2d 3.0 + Chipmunk + CCAnimation: moving physi

2019-09-04 04:23发布

问题:

I have a boat with attached physics body. This boat is static physics body. Boat moving with CCAnimateMoveTo from left to right. When I tap on screen my character fall down. I detect collisions well. But I want that after collision my character just fall on boat and keep moving with it. Character is dynamic body. Link to sample video: Sample video

Here I create a boat:

- (void)createBoat
{
    currentBoat = [CCSprite spriteWithImageNamed:@"Boat.png"];
    currentBoat.position  = ccp(0 - currentBoat.boundingBox.size.width, winSize.height * 0.2);
//    currentBoat.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){0, 0, currentBoat.contentSize.width, currentBoat.contentSize.height * 0.5} cornerRadius:0];


    CGPoint shape[6];
    shape[0] = ccp(0, 30);
    shape[1] = ccp(64, 10);
    shape[2] = ccp(128, 30);
    shape[3] = ccp(128, 0);
    shape[4] = ccp(0, 0);
    shape[5] = ccp(0, 30);


    currentBoat.physicsBody = [CCPhysicsBody bodyWithPolylineFromPoints:shape count:6 cornerRadius:0 looped:NO];
    currentBoat.physicsBody.type = CCPhysicsBodyTypeStatic;
    currentBoat.physicsBody.collisionGroup = @"BoatGroup";
    currentBoat.physicsBody.collisionType = @"BoatCollision";
    [physicsWorld addChild:currentBoat z:PHYSICS_Z+3];

    id actionMoveBoat = [[CCActionMoveTo alloc] initWithDuration:5.0f position:ccp(winSize.width + currentBoat.boundingBox.size.width, currentBoat.position.y)];
    id actionMethod = [CCActionCallFunc actionWithTarget:self selector:@selector(createBoat)];


    [currentBoat runAction:[CCActionSequence actions:actionMoveBoat, [[CCActionRemove alloc] init], actionMethod, nil]];
}

Character creation:

- (void)createCharacter
{
    if (needCharacter)
    {
        CCSprite *newCharacter = [CCSprite spriteWithImageNamed:@"Character.png"];
        newCharacter.opacity = 0;
        newCharacter.position  = ccp(winSize.width * 0.5, winSize.height * 0.76);
        newCharacter.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, newCharacter.contentSize} cornerRadius:0];
        newCharacter.physicsBody.affectedByGravity = NO;
        newCharacter.physicsBody.allowsRotation = YES;
        newCharacter.physicsBody.collisionGroup = @"playerGroup";
        newCharacter.physicsBody.collisionType = @"playerCollision";
        [physicsWorld addChild:newCharacter z:PHYSICS_Z+4];


        id actionFadeIn = [[CCActionFadeIn alloc] initWithDuration:0.5];
        [newCharacter runAction:actionFadeIn];


        [allCharacters addObject:newCharacter];


        needCharacter = false;
        touchDone = false;
    }
}

Then detection touch and collision:

- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CCNode *lastCharacter = [allCharacters lastObject];


    if (!touchDone)
    {
        [lastCharacter.physicsBody applyImpulse:ccp(0, 300)];
        lastCharacter.physicsBody.type = CCPhysicsBodyTypeDynamic;
        lastCharacter.physicsBody.affectedByGravity = YES;
        touchDone = true;
    }

}

- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair playerCollision:(CCNode *)currentCharacterC BoatCollision:(CCNode *)currentBoatC {


    currentCharacterC.physicsBody.collisionType = @"tmpCollision";



    CCLOG(@"score++");
    if ([allCharacters containsObject:currentCharacterC])
    {
        score++;
        [scores setString:[NSString stringWithFormat:@"%d", score]];
        [allCharacters removeAllObjects];


        if (lives != 0)
        {
            needCharacter = true;
            [self createCharacter];
        }
    }


    CCLOG(@"allCharacters = %@", allCharacters);


    return YES;
}

回答1:

well I too faced the same problem, tried increasing the friction/surface velocity etc, it didn't really work well. Finally had to resolve it my own way, whenever player lands on any body, you keep a pointer to that body as say _bodyUnderFeet of the player object. Now, in the update loop add the velocity of the _bodyUnderFeet to the players calculated velocity. See the use of zeroVel_x

Sample code is here:

void Player::update(float dt)
{
    float zeroVel_x = 0;
    if(_bodyUnderFeet != NULL)
    {
        zeroVel_x = _bodyUnderFeet->v.x;
    }
    cpBody *bd = getCPBody();
    assert(bd);
    //log("Body angle %f", bd->a);
    //check forward backward or at rest
    float accel = _accelGround;
    if(_onGroundBoost < UP_BOOST)
    {
        accel = _accelAir;
    }
    if(_touchPressedB)
    {
        if(!isFlippedX())
        {
            setFlippedX(true);
        }
        //cpBodySetVel(bd, cpv(cpBodyGetVel(bd).x - accel*0.25, 0));
        cpVect bdv = cpBodyGetVel(bd);
        bdv.x = bdv.x - zeroVel_x;
        if(bdv.x > 0) bdv.x = 0;
        if(bdv.x > -_maxVelocity.x)
            cpBodySetVel(bd, cpv(zeroVel_x + bdv.x - accel*0.25, bdv.y));
    }
    else if(_touchPressedF)
    {
        if(isFlippedX())
        {
            setFlippedX(false);
        }
        //cpBodySetVel(bd, cpv(cpBodyGetVel(bd).x + accel*0.25, 0));
        cpVect bdv = cpBodyGetVel(bd);
        bdv.x = bdv.x - zeroVel_x;
        if(bdv.x < 0) bdv.x = 0;
        if(bdv.x < _maxVelocity.x)
            cpBodySetVel(bd, cpv(zeroVel_x+bdv.x + accel*0.25, bdv.y));
    }
    else
    {
        cpFloat bd_x = cpBodyGetVel(bd).x;
        bd_x = bd_x - zeroVel_x;
        if(bd_x>0)
        {
            if(bd_x > accel*0.25)
            {
                cpBodySetVel(bd, cpv(zeroVel_x+bd_x - accel*0.25, cpBodyGetVel(bd).y));
            }
            else
            {
                cpBodySetVel(bd, cpv(zeroVel_x+0, cpBodyGetVel(bd).y));
            }
        }
        else if(bd_x < 0)
        {
            if(bd_x < accel*0.25)
            {
                cpBodySetVel(bd, cpv(zeroVel_x+bd_x + accel*0.25, cpBodyGetVel(bd).y));
            }
            else
            {
                cpBodySetVel(bd, cpv(zeroVel_x+0, cpBodyGetVel(bd).y));
            }
        }
    }

    //check jump
    if(_touchPressedJ)
    {
        if(_onGroundBoost)
        {
            cpVect bdv = cpBodyGetVel(bd);
            if(bdv.y < 0) bdv.y = 0;
            if((bdv.y + _accelUp) < _maxVelocity.y)
            {
                cpBodySetVel(bd, cpv(bdv.x, bdv.y + _accelUp));
                --_onGroundBoost;
            }
            else
            {
                cpBodySetVel(bd, cpv(bdv.x, _maxVelocity.y));
                _onGroundBoost = 0;
            }
        }
    }

    //check shots
    if(_touchPressedS)
    {
        if(!_bulletFired)
        {

        }
    }

    //check home
    if(_touchPressedH)
    {

    }

    boundRotation(bd);
}


回答2:

I think, you can increase the friction between man and boat after he fall down. and reduce the elasticity . then the boat can 'take' the man go together...

just a trick.