Skip to content

Commit

Permalink
fixed another island bug
Browse files Browse the repository at this point in the history
  • Loading branch information
erincatto committed Aug 24, 2024
1 parent 79448bd commit ed4846b
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 59 deletions.
11 changes: 8 additions & 3 deletions src/body.c
Original file line number Diff line number Diff line change
Expand Up @@ -1161,8 +1161,10 @@ void b2Body_SetType( b2BodyId bodyId, b2BodyType type )
continue;
}

b2LinkJoint( world, joint );
b2LinkJoint( world, joint, false);
}

b2MergeAwakeIslands( world );
}

// Body type affects the mass
Expand Down Expand Up @@ -1550,6 +1552,7 @@ void b2Body_Enable( b2BodyId bodyId )

// Transfer joints. If the other body is disabled, don't transfer.
// If the other body is sleeping, wake it.
bool mergeIslands = false;
int jointKey = body->headJointKey;
while ( jointKey != B2_NULL_INDEX )
{
Expand Down Expand Up @@ -1593,11 +1596,13 @@ void b2Body_Enable( b2BodyId bodyId )
// Now that the joint is in the correct set, I can link the joint in the island.
if ( jointSetId != b2_staticSet )
{
b2LinkJoint( world, joint );
b2LinkJoint( world, joint, mergeIslands );
}
}

b2ValidateConnectivity( world );
// Now merge islands
b2MergeAwakeIslands( world );

b2ValidateSolverSets( world );
}

Expand Down
12 changes: 9 additions & 3 deletions src/island.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ static void b2AddJointToIsland( b2World* world, int islandId, b2Joint* joint )
b2ValidateIsland( world, islandId );
}

void b2LinkJoint( b2World* world, b2Joint* joint )
void b2LinkJoint( b2World* world, b2Joint* joint, bool mergeIslands )
{
b2Body* bodyA = b2GetBody( world, joint->edges[0].bodyId );
b2Body* bodyB = b2GetBody( world, joint->edges[1].bodyId );
Expand Down Expand Up @@ -378,8 +378,14 @@ void b2LinkJoint( b2World* world, b2Joint* joint )
b2AddJointToIsland( world, islandIdB, joint );
}

// Joints need to have islands merged immediately to keep the island graph valid.
b2MergeAwakeIslands( world );
// Joints need to have islands merged immediately when they are created
// to keep the island graph valid.
// However, when a body type is being changed the merge can be deferred until
// all joints are linked.
if (mergeIslands)
{
b2MergeAwakeIslands( world );
}
}

void b2UnlinkJoint( b2World* world, b2Joint* joint )
Expand Down
3 changes: 2 additions & 1 deletion src/island.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <stdbool.h>
#include <stdint.h>

typedef struct b2Body b2Body;
Expand Down Expand Up @@ -74,7 +75,7 @@ void b2LinkContact( b2World* world, b2Contact* contact );
void b2UnlinkContact( b2World* world, b2Contact* contact );

// Link a joint into the island graph when it is created
void b2LinkJoint( b2World* world, b2Joint* joint );
void b2LinkJoint( b2World* world, b2Joint* joint, bool mergeIslands );

// Unlink a joint from the island graph when it is destroyed
void b2UnlinkJoint( b2World* world, b2Joint* joint );
Expand Down
13 changes: 11 additions & 2 deletions src/joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ static b2JointPair b2CreateJoint( b2World* world, b2Body* bodyA, b2Body* bodyB,
if ( joint->setIndex > b2_disabledSet )
{
// Add edge to island graph
b2LinkJoint( world, joint );
bool mergeIslands = true;
b2LinkJoint( world, joint, mergeIslands );
}

b2ValidateSolverSets( world );
Expand Down Expand Up @@ -712,7 +713,15 @@ void b2DestroyJointInternal( b2World* world, b2Joint* joint, bool wakeBodies )

bodyB->jointCount -= 1;

b2UnlinkJoint( world, joint );
if (joint->islandId != B2_NULL_INDEX)
{
B2_ASSERT( joint->setIndex > b2_disabledSet );
b2UnlinkJoint( world, joint );
}
else
{
B2_ASSERT( joint->setIndex <= b2_disabledSet );
}

// Remove joint from solver set that owns it
int setIndex = joint->setIndex;
Expand Down
141 changes: 91 additions & 50 deletions test/test_world.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,56 +200,97 @@ static int TestIsValid( void )

int TestForAmy( void )
{
b2WorldDef worldDef = b2DefaultWorldDef();
b2WorldId world_id = b2CreateWorld( &worldDef );

b2BodyDef body_def = b2DefaultBodyDef();

body_def.type = b2_staticBody;
body_def.position = ( b2Vec2 ){ 0., 0. };
b2BodyId body_id = b2CreateBody( world_id, &body_def );
b2Polygon polygon = b2MakeBox( 1., 1. );
b2ShapeDef shape_def = b2DefaultShapeDef();
b2CreatePolygonShape( body_id, &shape_def, &polygon );

b2BodyDef simulon_body_def = b2DefaultBodyDef();

simulon_body_def.position = ( b2Vec2 ){ 0., -7.5 };
simulon_body_def.type = b2_dynamicBody;

b2BodyId simulon_body_id = b2CreateBody( world_id, &simulon_body_def );
b2Circle ball = { { 0.0, 0.35 }, 0.5 };

b2ShapeDef simulon_shape_def = b2DefaultShapeDef();
b2CreateCircleShape( simulon_body_id, &simulon_shape_def, &ball );

b2Polygon the_box = b2MakeRoundedBox( 0.1, 0.1, 0.01 );
b2CreatePolygonShape( simulon_body_id, &simulon_shape_def, &the_box );
b2BodyDef head_body_def = b2DefaultBodyDef();
head_body_def.position = ( b2Vec2 ){ 0., 6. };
head_body_def.type = b2_dynamicBody;
b2BodyId head_body_id = b2CreateBody( world_id, &head_body_def );
b2RevoluteJointDef joint_def5 = b2DefaultRevoluteJointDef();
joint_def5.bodyIdA = simulon_body_id;
joint_def5.bodyIdB = head_body_id;
joint_def5.localAnchorA = ( b2Vec2 ){ 0.0, 0.8 };
joint_def5.localAnchorB = ( b2Vec2 ){ 0.0, -0.17 / 2.0 };

b2JointId revolute_joint_id = b2CreateRevoluteJoint( world_id, &joint_def5 );
b2DistanceJointDef joint_def6 = b2DefaultDistanceJointDef();
joint_def6.bodyIdA = simulon_body_id;
joint_def6.bodyIdB = head_body_id;
joint_def6.localAnchorA = ( b2Vec2 ){ 0.0, 1.7 };
joint_def6.localAnchorB = ( b2Vec2 ){ 0.0, 0.8 };
joint_def6.length = 0.005;
joint_def6.hertz = 1.;
b2CreateDistanceJoint( world_id, &joint_def6 );

b2DestroyBody( simulon_body_id );

b2World_Step( world_id, 1. / 60., 4 );

b2DestroyWorld( world_id );
{
b2WorldDef worldDef = b2DefaultWorldDef();
b2WorldId world_id = b2CreateWorld( &worldDef );

b2BodyDef body_def = b2DefaultBodyDef();

body_def.type = b2_staticBody;
body_def.position = ( b2Vec2 ){ 0., 0. };
b2BodyId body_id = b2CreateBody( world_id, &body_def );
b2Polygon polygon = b2MakeBox( 1., 1. );
b2ShapeDef shape_def = b2DefaultShapeDef();
b2CreatePolygonShape( body_id, &shape_def, &polygon );

b2BodyDef simulon_body_def = b2DefaultBodyDef();

simulon_body_def.position = ( b2Vec2 ){ 0., -7.5 };
simulon_body_def.type = b2_dynamicBody;

b2BodyId simulon_body_id = b2CreateBody( world_id, &simulon_body_def );
b2Circle ball = { { 0.0, 0.35 }, 0.5 };

b2ShapeDef simulon_shape_def = b2DefaultShapeDef();
b2CreateCircleShape( simulon_body_id, &simulon_shape_def, &ball );

b2Polygon the_box = b2MakeRoundedBox( 0.1, 0.1, 0.01 );
b2CreatePolygonShape( simulon_body_id, &simulon_shape_def, &the_box );
b2BodyDef head_body_def = b2DefaultBodyDef();
head_body_def.position = ( b2Vec2 ){ 0., 6. };
head_body_def.type = b2_dynamicBody;
b2BodyId head_body_id = b2CreateBody( world_id, &head_body_def );
b2RevoluteJointDef joint_def5 = b2DefaultRevoluteJointDef();
joint_def5.bodyIdA = simulon_body_id;
joint_def5.bodyIdB = head_body_id;
joint_def5.localAnchorA = ( b2Vec2 ){ 0.0, 0.8 };
joint_def5.localAnchorB = ( b2Vec2 ){ 0.0, -0.17 / 2.0 };

b2JointId revolute_joint_id = b2CreateRevoluteJoint( world_id, &joint_def5 );
b2DistanceJointDef joint_def6 = b2DefaultDistanceJointDef();
joint_def6.bodyIdA = simulon_body_id;
joint_def6.bodyIdB = head_body_id;
joint_def6.localAnchorA = ( b2Vec2 ){ 0.0, 1.7 };
joint_def6.localAnchorB = ( b2Vec2 ){ 0.0, 0.8 };
joint_def6.length = 0.005;
joint_def6.hertz = 1.;
b2CreateDistanceJoint( world_id, &joint_def6 );

b2DestroyBody( simulon_body_id );

b2World_Step( world_id, 1. / 60., 4 );

b2DestroyWorld( world_id );
}

{
b2WorldDef worldDef = b2DefaultWorldDef();
b2WorldId world_id = b2CreateWorld( &worldDef );

b2BodyDef ground_body_def = b2DefaultBodyDef();
ground_body_def.type = b2_staticBody;
b2BodyId ground_body_id = b2CreateBody( world_id, &ground_body_def );

b2BodyDef box_body_def = b2DefaultBodyDef();
box_body_def.type = b2_dynamicBody;
box_body_def.position = ( b2Vec2 ){ 0.0, 0.0 };
b2BodyId box_body_id = b2CreateBody( world_id, &box_body_def );
b2Polygon polygon = b2MakeBox( 1., 1. );
b2ShapeDef shape_def = b2DefaultShapeDef();
b2ShapeId box_shape = b2CreatePolygonShape( box_body_id, &shape_def, &polygon );

b2DistanceJointDef distance_joint_def = b2DefaultDistanceJointDef();
distance_joint_def.hertz = 1.;
distance_joint_def.dampingRatio = 0.1;
distance_joint_def.bodyIdA = ground_body_id;
distance_joint_def.bodyIdB = box_body_id;
distance_joint_def.minLength = 0.005;
distance_joint_def.enableSpring = true;
distance_joint_def.enableLimit = false;
distance_joint_def.collideConnected = false;
distance_joint_def.length = 0.005;
b2Body_SetTransform( ground_body_id, ( b2Vec2 ){ 0.0, 0.0 }, ( b2Rot ){ 1., 0. } );
distance_joint_def.localAnchorA = ( b2Vec2 ){ 0.0, 0.0 };
distance_joint_def.localAnchorB = ( b2Vec2 ){ 0.0, 0.0 };
b2JointId distance_joint_id = b2CreateDistanceJoint( world_id, &distance_joint_def );

b2Body_SetType( box_body_id, b2_staticBody );
b2World_Step( world_id, 1. / 60., 4 );

b2DestroyJoint( distance_joint_id );

b2DestroyWorld( world_id );
}

return 0;
}
Expand Down

0 comments on commit ed4846b

Please sign in to comment.