Skip to content

Commit 349f8d8

Browse files
authored
Fix joint validation (#954)
Joint creation may wake a body. This was triggering a validation error while the joint wasn't fully built. I moved the validation closer to the API. Added motion locking sample. This shows that motion locking is somewhat of a kludge because constraints in the locked direction can be softened.
1 parent ed04b1a commit 349f8d8

File tree

6 files changed

+116
-5
lines changed

6 files changed

+116
-5
lines changed

include/box2d/types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ typedef struct b2BodyDef
226226
/// Use this to store application specific body data.
227227
void* userData;
228228

229-
/// Motions locks to restrict linear and angular movement
229+
/// Motions locks to restrict linear and angular movement.
230+
/// Caution: may lead to softer constraints along the locked direction
230231
b2MotionLocks motionLocks;
231232

232233
/// Set this flag to false if this body should never fall asleep.

samples/sample.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ void Sample::MouseDown( b2Vec2 p, int button, int mod )
327327
if ( B2_IS_NON_NULL( queryContext.bodyId ) )
328328
{
329329
b2BodyDef bodyDef = b2DefaultBodyDef();
330+
bodyDef.type = b2_kinematicBody;
330331
m_groundBodyId = b2CreateBody( m_worldId, &bodyDef );
331332

332333
b2MouseJointDef jointDef = b2DefaultMouseJointDef();
@@ -336,7 +337,7 @@ void Sample::MouseDown( b2Vec2 p, int button, int mod )
336337
jointDef.base.localFrameB.p = b2Body_GetLocalPoint( queryContext.bodyId, p );
337338
jointDef.hertz = 7.5f;
338339
jointDef.dampingRatio = 0.7f;
339-
jointDef.maxForce = 1000.0f * b2Body_GetMass( queryContext.bodyId ) * b2Length(b2World_GetGravity(m_worldId));
340+
jointDef.maxForce = 100.0f * b2Body_GetMass( queryContext.bodyId ) * b2Length(b2World_GetGravity(m_worldId));
340341
m_mouseJointId = b2CreateMouseJoint( m_worldId, &jointDef );
341342

342343
b2Body_SetAwake( queryContext.bodyId, true );

samples/sample_bodies.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,3 +874,113 @@ class Kinematic : public Sample
874874
};
875875

876876
static int sampleKinematic = RegisterSample( "Bodies", "Kinematic", Kinematic::Create );
877+
878+
// Motion locking can be a bit squishy
879+
class MixedLocks : public Sample
880+
{
881+
public:
882+
explicit MixedLocks( SampleContext* context )
883+
: Sample( context )
884+
{
885+
if ( m_context->restart == false )
886+
{
887+
m_context->camera.m_center = { 0.0f, 2.5f };
888+
m_context->camera.m_zoom = 3.5f;
889+
}
890+
891+
{
892+
b2BodyDef bodyDef = b2DefaultBodyDef();
893+
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
894+
895+
b2ShapeDef shapeDef = b2DefaultShapeDef();
896+
b2Segment segment = { { -40.0, 0.0f }, { 40.0f, 0.0f } };
897+
b2CreateSegmentShape( groundId, &shapeDef, &segment );
898+
}
899+
900+
b2Polygon box = b2MakeSquare( 0.5f );
901+
b2ShapeDef shapeDef = b2DefaultShapeDef();
902+
903+
{
904+
b2BodyDef bodyDef = b2DefaultBodyDef();
905+
bodyDef.position = { 2.0f, 1.0f };
906+
bodyDef.name = "static";
907+
908+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
909+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
910+
}
911+
912+
{
913+
b2BodyDef bodyDef = b2DefaultBodyDef();
914+
bodyDef.type = b2_dynamicBody;
915+
bodyDef.position = { 1.0f, 1.0f };
916+
bodyDef.name = "free";
917+
918+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
919+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
920+
}
921+
922+
{
923+
b2BodyDef bodyDef = b2DefaultBodyDef();
924+
bodyDef.type = b2_dynamicBody;
925+
bodyDef.position = { 1.0f, 3.0f };
926+
bodyDef.name = "free";
927+
928+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
929+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
930+
}
931+
932+
{
933+
b2BodyDef bodyDef = b2DefaultBodyDef();
934+
bodyDef.type = b2_dynamicBody;
935+
bodyDef.position = { -1.0f, 1.0f };
936+
bodyDef.motionLocks.angularZ = true;
937+
bodyDef.name = "angular z";
938+
939+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
940+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
941+
}
942+
943+
{
944+
b2BodyDef bodyDef = b2DefaultBodyDef();
945+
bodyDef.type = b2_dynamicBody;
946+
bodyDef.position = { -2.0f, 2.0f };
947+
bodyDef.motionLocks.linearX = true;
948+
bodyDef.name = "linear x";
949+
950+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
951+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
952+
}
953+
954+
{
955+
b2BodyDef bodyDef = b2DefaultBodyDef();
956+
bodyDef.type = b2_dynamicBody;
957+
bodyDef.position = { -1.0f, 2.5f };
958+
bodyDef.motionLocks.linearY = true;
959+
bodyDef.motionLocks.angularZ = true;
960+
bodyDef.name = "lin y ang z";
961+
962+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
963+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
964+
}
965+
966+
{
967+
b2BodyDef bodyDef = b2DefaultBodyDef();
968+
bodyDef.type = b2_dynamicBody;
969+
bodyDef.position = { 0.0f, 1.0f };
970+
bodyDef.motionLocks.linearX = true;
971+
bodyDef.motionLocks.linearY = true;
972+
bodyDef.motionLocks.angularZ = true;
973+
bodyDef.name = "full";
974+
975+
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
976+
b2CreatePolygonShape( bodyId, &shapeDef, &box );
977+
}
978+
}
979+
980+
static Sample* Create( SampleContext* context )
981+
{
982+
return new MixedLocks( context );
983+
}
984+
};
985+
986+
static int sampleMixedLocks = RegisterSample( "Bodies", "Mixed Locks", MixedLocks::Create );

src/body.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ bool b2WakeBody( b2World* world, b2Body* body )
341341
if ( body->setIndex >= b2_firstSleepingSet )
342342
{
343343
b2WakeSolverSet( world, body->setIndex );
344+
b2ValidateSolverSets( world );
344345
return true;
345346
}
346347

src/joint.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ static b2JointPair b2CreateJoint( b2World* world, const b2JointDef* def, b2Joint
331331
jointSim = b2JointSimArray_Add( &set->jointSims );
332332
memset( jointSim, 0, sizeof( b2JointSim ) );
333333

334-
// These must be set to accomodate the merge below
334+
// These must be set to accommodate the merge below
335335
jointSim->jointId = jointId;
336336
jointSim->bodyIdA = bodyIdA;
337337
jointSim->bodyIdB = bodyIdB;

src/solver_set.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,6 @@ void b2WakeSolverSet( b2World* world, int setIndex )
150150

151151
// destroy the sleeping set
152152
b2DestroySolverSet( world, setIndex );
153-
154-
b2ValidateSolverSets( world );
155153
}
156154

157155
void b2TrySleepIsland( b2World* world, int islandId )

0 commit comments

Comments
 (0)