0
\$\begingroup\$

I got a quite strange bug. It is difficult to explain it in two words, but i'll try to do this in short.

  • My b2Body has restitution, friction, density, mass and collision group.
  • I'm controlling my b2Body via setting linear velocity to it (called on every iteration):
(void)moveToDirection:(CGPoint)direction onlyHorizontal:(BOOL)horizontal {
    b2Vec2 velocity = [controlledObject getBody]->GetLinearVelocity();

        double horizontalSpeed = velocity.x + controlledObject.acceleration * direction.x;

        velocity.x = (float32) (abs((int) horizontalSpeed) < controlledObject.runSpeed
                ? horizontalSpeed
                : controlledObject.maxSpeed * direction.x);

        if (!horizontal)
        {
            velocity.y = velocity.y + controlledObject.runSpeed * direction.y;
        }

        [controlledObject getBody]->SetLinearVelocity(velocity);
    }
  • My floor is static b2Body, it has as restitution, friction, density, mass and same collision group
  • in some reason, I'm setting b2Body's friction of my Hero to zero when it is moving, and returning it to 1 when he stops.
  • When I'm pushing run button, hero runs. when i'm releasing it, he stops. All of this works perfect.
  • On jumping, I'm setting linear velocity to my Hero:
(void)jump {
    b2Vec2 velocity = [controlledObject getBody]->GetLinearVelocity();
    velocity.y = velocity.y + [[AppDel cfg] getHeroJumpVlelocity];
    [controlledObject getBody]->SetLinearVelocity(velocity);
}
  • If I'll run, jump, and release run button, while he is in air, all will work fine.
  • And here is my problem: If I'll run, jump, and continue running on landing (or when he goes from one static body to another: there is small fall, probably), Hero will start move, like he has no friction, but he has! I checked this via beakpoints: he has friction, but I can move left of right, and he will never stop, until i'll jump (or go from one static body to another), with unpressed running button.

I already tried:

  • Set friction to body on every iteration
  • double-check am I setting friction to right fixture.
  • Set Linear Damping to Hero: his move slows down on gugged moveing.

A little more code:

I have a sensor and body fixtures in my hero:

 (void) addBodyFixture
{
    b2CircleShape dynamicBox;
    dynamicBox.m_radius = [[AppDel cfg] getHeroRadius];

    b2FixtureDef bodyFixtureDef;
    bodyFixtureDef.shape = &dynamicBox;
    bodyFixtureDef.density = 1.0f;
    bodyFixtureDef.friction = [[AppDel cfg] getHeroFriction];
    bodyFixtureDef.restitution = [[AppDel cfg] getHeroRestitution];
    bodyFixtureDef.filter.categoryBits = 0x0001;
    bodyFixtureDef.filter.maskBits = 0x0001;
    bodyFixtureDef.filter.groupIndex = 0;
    bodyFixtureDef.userData = [NSNumber numberWithInt:FIXTURE_BODY];

    [physicalBody addFixture:bodyFixtureDef];
}

 (void) addSensorFixture
{
    b2CircleShape sensorBox;
    sensorBox.m_radius = [[AppDel cfg] getHeroRadius] * 0.95;
    sensorBox.m_p.Set(0, -[[AppDel cfg] getHeroRadius] / 10);
    b2FixtureDef sensor;
    sensor.shape = &sensorBox;
    sensor.filter.categoryBits = 0x0001;
    sensor.filter.maskBits = 0x0001;
    sensor.filter.groupIndex = 0;
    sensor.isSensor = YES;
    sensor.userData = [NSNumber numberWithInt:FIXTURE_SENSOR];

    [physicalBody addFixture:sensor];
}

Here I'm tracking is hero in air:

void FixtureContactListener::BeginContact(b2Contact* contact)
{
    // We need to copy out the data because the b2Contact passed in
    // is reused.
    Squirrel *squirrel = (Squirrel *)contact->GetFixtureB()->GetBody()->GetUserData();
    if (squirrel)
    {
        [squirrel addContact];
    }
}

void FixtureContactListener::EndContact(b2Contact* contact) 
{
    Squirrel *squirrel = (Squirrel *)contact->GetFixtureB()->GetBody()->GetUserData();
    if (squirrel) 
    {
        [squirrel removeContact];
    }
}

Here is Hero's logic on contacts:

- (void) addContact
{

    if (contactCount == 0)
        [self landing];
    contactCount++;
}
- (void) removeContact
{
    contactCount--;
    if (contactCount == 0)
        [self flying];
    if (contactCount <0)
        contactCount = 0;
}

- (void)landing
{
    inAir = NO;
    acceleration = [[AppDel cfg] getHeroRunAcceleration];
    [sprite stopAllActions];
    (running ? [sprite runAction:[self runAction]] : [sprite runAction:[self standAction]]);
}
- (void)flying
{
    inAir = YES;
    acceleration = [[AppDel cfg] getHeroAirAcceleration];
    [sprite stopAllActions];
    [self flyAction];
}

Here is Hero's moving logic:

- (void)stop
{

    running = NO;
    if (!inAir)
    {
        [sprite stopAllActions];
        [sprite runAction:[self standAction]];
    }
}

- (void)left
{
    [physicalBody setFriction:0];
    if (!running && !inAir)
    {
        [sprite stopAllActions];
        [sprite runAction:[self runAction]];
    }
    running = YES;
    moveingDirection = NO;
    [bodyControls moveToDirection:CGPointMake(-1, 0) onlyHorizontal:YES];
}

- (void)right
{
    [physicalBody setFriction:0];
    if (!running && !inAir)
    {
        [sprite stopAllActions];
        [sprite runAction:[self runAction]];
    }
    running = YES;
    moveingDirection = YES;
    [bodyControls moveToDirection:CGPointMake(1, 0) onlyHorizontal:YES];
}
- (void)jump
{
    if (!inAir) 
    {
        [bodyControls jump];
    }
}

And here is my update method (called on every iteration):

 - (void)update:(NSMutableDictionary *)buttons
    {   
        if (!isDead)
        {
            [self updateWithButtonName:BUTTON_LEFT inButtons:buttons whenPressed:@selector(left) whenUnpressed:@selector(stop)];
            [self updateWithButtonName:BUTTON_RIGHT inButtons:buttons whenPressed:@selector(right) whenUnpressed:@selector(stop)];
            [self updateWithButtonName:BUTTON_UP inButtons:buttons whenPressed:@selector(jump) whenUnpressed:@selector(nothing)];
            [self updateWithButtonName:BUTTON_DOWN inButtons:buttons whenPressed:@selector(nothing) whenUnpressed:@selector(nothing)];
            [sprite setFlipX:(moveingDirection)];


        }

        [self checkPosition];
        if (!running)
            [physicalBody setFriction:[[AppDel cfg] getHeroFriction]];
        else
            [physicalBody setFriction:0];
    }

- (void)updateWithButtonName:(NSString *)buttonName inButtons:(NSDictionary *)buttons whenPressed:(SEL)pressedSelector whenUnpressed:(SEL)unpressedSelector
{
    NSNumber *buttonNumber = [buttons objectForKey:buttonName];
    if (buttonNumber  == nil)
        return;

    if ([buttonNumber boolValue])
        [self performSelector:pressedSelector];
    else
        [self performSelector:unpressedSelector];
}

- (void)checkPosition
{
    b2Body *body = [self getBody];
    b2Vec2 position = body->GetPosition();
    CGPoint inWorldPosition = [[AppDel cfg] worldMeterPointFromScreenPixel:CGPointMake(position.x * PTM_RATIO, position.y * PTM_RATIO)];
    if (inWorldPosition.x < 0 || 
        inWorldPosition.x > WORLD_WIDGH / PTM_RATIO ||
        inWorldPosition.y <= 0)
    {
        [self kill];
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Don't set the linear velocity apply a force to the body. Box2d cant apply friction (etc...) if you keep overriding the changes by setting the velocity. \$\endgroup\$ Feb 29, 2012 at 11:24
  • \$\begingroup\$ tnx for response, I thought about that, but I'm porting this from flash (with box2d), and there this work. may be we use dofferent versions? Or, I must set friction in another part of code? but where? I cant clearly understand this stuff. Can you advice something more specific? \$\endgroup\$
    – SentineL
    Feb 29, 2012 at 12:02

1 Answer 1

2
\$\begingroup\$

I needed only reset friction on presolve:

void FixtureContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
    contact->ResetFriction();

}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .