Skip to content

Commit

Permalink
body names
Browse files Browse the repository at this point in the history
sensor testing
  • Loading branch information
erincatto committed Jan 20, 2025
1 parent d67d348 commit 83ee3a6
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 3 deletions.
6 changes: 6 additions & 0 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ B2_API b2BodyType b2Body_GetType( b2BodyId bodyId );
/// properties regardless of the automatic mass setting.
B2_API void b2Body_SetType( b2BodyId bodyId, b2BodyType type );

/// Set the body name. Up to 31 characters excluding 0 termination.
B2_API void b2Body_SetName( b2BodyId bodyId, const char* name );

/// Get the body name. May be null.
B2_API const char* b2Body_GetName( b2BodyId bodyId );

/// Set the user data for a body
B2_API void b2Body_SetUserData( b2BodyId bodyId, void* userData );

Expand Down
6 changes: 6 additions & 0 deletions include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ typedef struct b2BodyDef
/// Sleep speed threshold, default is 0.05 meters per second
float sleepThreshold;

/// Optional body name for debugging. Up to 31 characters (excluding null termination)
const char* name;

/// Use this to store application specific body data.
void* userData;

Expand Down Expand Up @@ -1390,6 +1393,9 @@ typedef struct b2DebugDraw
/// Option to draw the mass and center of mass of dynamic bodies
bool drawMass;

/// Option to draw body names
bool drawBodyNames;

/// Option to draw contact points
bool drawContacts;

Expand Down
3 changes: 2 additions & 1 deletion samples/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ static void UpdateUI()
ImGui::Checkbox( "Contact Impulses", &s_settings.drawContactImpulses );
ImGui::Checkbox( "Friction Impulses", &s_settings.drawFrictionImpulses );
ImGui::Checkbox( "Center of Masses", &s_settings.drawMass );
ImGui::Checkbox( "Body Names", &s_settings.drawBodyNames );
ImGui::Checkbox( "Graph Colors", &s_settings.drawGraphColors );
ImGui::Checkbox( "Counters", &s_settings.drawCounters );
ImGui::Checkbox( "Profile", &s_settings.drawProfile );
Expand Down Expand Up @@ -666,7 +667,7 @@ int main( int, char** )

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

g_draw.DrawBackground();
//g_draw.DrawBackground();

double cursorPosX = 0, cursorPosY = 0;
glfwGetCursorPos( g_mainWindow, &cursorPosX, &cursorPosY );
Expand Down
1 change: 1 addition & 0 deletions samples/sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ void Sample::Step( Settings& settings )
g_draw.m_debugDraw.drawJointExtras = settings.drawJointExtras;
g_draw.m_debugDraw.drawAABBs = settings.drawAABBs;
g_draw.m_debugDraw.drawMass = settings.drawMass;
g_draw.m_debugDraw.drawBodyNames = settings.drawBodyNames;
g_draw.m_debugDraw.drawContacts = settings.drawContactPoints;
g_draw.m_debugDraw.drawGraphColors = settings.drawGraphColors;
g_draw.m_debugDraw.drawContactNormals = settings.drawContactNormals;
Expand Down
186 changes: 186 additions & 0 deletions samples/sample_events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1465,3 +1465,189 @@ class BodyMove : public Sample
};

static int sampleBodyMove = RegisterSample( "Events", "Body Move", BodyMove::Create );

class SensorTypes : public Sample
{
public:
enum CollisionBits
{
GROUND = 0x00000001,
SENSOR = 0x00000002,
DEFAULT = 0x00000004,

ALL_BITS = ( ~0u )
};

explicit SensorTypes( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 0.0f, 3.0f };
g_camera.m_zoom = 4.5f;
}

{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.name = "ground";

b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = GROUND;
shapeDef.filter.maskBits = SENSOR | DEFAULT;

b2Segment groundSegment = { { -6.0f, 0.0f }, { 6.0f, 0.0f } };
b2CreateSegmentShape( groundId, &shapeDef, &groundSegment );

groundSegment = { { -6.0f, 0.0f }, { -6.0f, 4.0f } };
b2CreateSegmentShape( groundId, &shapeDef, &groundSegment );

groundSegment = { { 6.0f, 0.0f }, { 6.0f, 4.0f } };
b2CreateSegmentShape( groundId, &shapeDef, &groundSegment );
}

{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.name = "static sensor";
bodyDef.type = b2_staticBody;
bodyDef.position = { -3.0f, 0.8f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );

b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = SENSOR;
shapeDef.isSensor = true;
b2Polygon box = b2MakeSquare( 1.0f );
m_staticSensorId = b2CreatePolygonShape( bodyId, &shapeDef, &box );
}

{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.name = "kinematic sensor";
bodyDef.type = b2_kinematicBody;
bodyDef.position = { 0.0f, 0.0f };
bodyDef.linearVelocity = { 0.0f, 1.0f };
m_kinematicBodyId = b2CreateBody( m_worldId, &bodyDef );

b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = SENSOR;
shapeDef.isSensor = true;
b2Polygon box = b2MakeSquare( 1.0f );
m_kinematicSensorId = b2CreatePolygonShape( m_kinematicBodyId, &shapeDef, &box );
}

{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.name = "dynamic sensor";
bodyDef.type = b2_dynamicBody;
bodyDef.position = { 3.0f, 1.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );

b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = SENSOR;
shapeDef.isSensor = true;
b2Polygon box = b2MakeSquare( 1.0f );
m_dynamicSensorId = b2CreatePolygonShape( bodyId, &shapeDef, &box );

// Add some real collision so the dynamic body is valid
shapeDef.filter.categoryBits = DEFAULT;
shapeDef.isSensor = false;
box = b2MakeSquare( 0.8f );
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}

{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.name = "ball_01";
bodyDef.position = { -5.0f, 1.0f };
bodyDef.type = b2_dynamicBody;

b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );

b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = DEFAULT;
shapeDef.filter.maskBits = GROUND | DEFAULT | SENSOR;

b2Circle circle = { { 0.0f, 0.0f }, 0.5f };
b2CreateCircleShape( bodyId, &shapeDef, &circle );
}
}

void PrintOverlaps( b2ShapeId sensorShapeId, const char* prefix )
{
char buffer[256] = {};

// Determine the necessary capacity
int capacity = b2Shape_GetSensorCapacity( sensorShapeId );
m_overlaps.resize( capacity );

// Get all overlaps and record the actual count
int count = b2Shape_GetSensorOverlaps( sensorShapeId, m_overlaps.data(), capacity );
m_overlaps.resize( count );

int start = snprintf( buffer, sizeof( buffer ), "%s: ", prefix );
for ( int i = 0; i < count && start < sizeof( buffer ); ++i )
{
b2ShapeId visitorId = m_overlaps[i];
if ( b2Shape_IsValid( visitorId ) == false )
{
continue;
}

b2BodyId bodyId = b2Shape_GetBody( visitorId );
const char* name = b2Body_GetName( bodyId );
if ( name == nullptr )
{
continue;
}

start += snprintf( buffer + start, sizeof( buffer ) - start, "%s, ", name );
}

DrawTextLine( buffer );
}

void Step( Settings& settings ) override
{
b2Vec2 position = b2Body_GetPosition( m_kinematicBodyId );
if (position.y < 0.0f)
{
b2Body_SetLinearVelocity( m_kinematicBodyId, { 0.0f, 1.0f } );
//b2Body_SetKinematicTarget( m_kinematicBodyId );
}
else if (position.y > 3.0f)
{
b2Body_SetLinearVelocity( m_kinematicBodyId, { 0.0f, -1.0f } );
}

Sample::Step( settings );

PrintOverlaps( m_staticSensorId, "static" );
PrintOverlaps( m_kinematicSensorId, "kinematic" );
PrintOverlaps( m_dynamicSensorId, "dynamic" );

b2Vec2 origin = { 5.0f, 1.0f };
b2Vec2 translation = { -10.0f, 0.0f };
b2RayResult result = b2World_CastRayClosest( m_worldId, origin, translation, b2DefaultQueryFilter() );
g_draw.DrawSegment( origin, origin + translation, b2_colorDimGray );

if (result.hit)
{
g_draw.DrawPoint( result.point, 10.0f, b2_colorCyan );
}
}

static Sample* Create( Settings& settings )
{
return new SensorTypes( settings );
}

b2ShapeId m_staticSensorId;
b2ShapeId m_kinematicSensorId;
b2ShapeId m_dynamicSensorId;

b2BodyId m_kinematicBodyId;

std::vector<b2ShapeId> m_overlaps;
};

static int sampleSensorTypes = RegisterSample( "Events", "Sensor Types", SensorTypes::Create );
1 change: 1 addition & 0 deletions samples/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct Settings
bool drawContactImpulses = false;
bool drawFrictionImpulses = false;
bool drawMass = false;
bool drawBodyNames = false;
bool drawGraphColors = false;
bool drawCounters = false;
bool drawProfile = false;
Expand Down
42 changes: 42 additions & 0 deletions src/body.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,21 @@ b2BodyId b2CreateBody( b2WorldId worldId, const b2BodyDef* def )
}

b2Body* body = b2BodyArray_Get( &world->bodies, bodyId );

if ( def->name )
{
for ( int i = 0; i < 31; ++i )
{
body->name[i] = def->name[i];
}

body->name[31] = 0;
}
else
{
memset( body->name, 0, 32 * sizeof( char ) );
}

body->userData = def->userData;
body->setIndex = setId;
body->localIndex = set->bodySims.count - 1;
Expand Down Expand Up @@ -1181,6 +1196,33 @@ void b2Body_SetType( b2BodyId bodyId, b2BodyType type )
b2ValidateSolverSets( world );
}

void b2Body_SetName(b2BodyId bodyId, const char* name)
{
b2World* world = b2GetWorld( bodyId.world0 );
b2Body* body = b2GetBodyFullId( world, bodyId );

if ( name != NULL )
{
for ( int i = 0; i < 31; ++i )
{
body->name[i] = name[i];
}

body->name[31] = 0;
}
else
{
memset( body->name, 0, 32 * sizeof( char ) );
}
}

const char* b2Body_GetName(b2BodyId bodyId)
{
b2World* world = b2GetWorld( bodyId.world0 );
b2Body* body = b2GetBodyFullId( world, bodyId );
return body->name;
}

void b2Body_SetUserData( b2BodyId bodyId, void* userData )
{
b2World* world = b2GetWorld( bodyId.world0 );
Expand Down
2 changes: 2 additions & 0 deletions src/body.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ typedef struct b2World b2World;
// Body organizational details that are not used in the solver.
typedef struct b2Body
{
char name[32];

void* userData;

// index of solver set stored in b2World
Expand Down
14 changes: 14 additions & 0 deletions src/box2d.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,18 @@
<Item Name="Address">(void*)this</Item>
</Expand>
</Type>

<Type Name="b2WorldId">
<DisplayString>index: {index1}</DisplayString>
<Expand>
<ExpandedItem>b2_worlds[ index1 - 1 ]</ExpandedItem>
</Expand>
</Type>

<Type Name="b2Body">
<DisplayString>
{b2_worlds[world0].bodies.data[index1-1].name,na},
{b2_worlds[world0].bodies.data[index1-1].type}
</DisplayString>
</Type>
</AutoVisualizer>
4 changes: 2 additions & 2 deletions src/shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ int b2Shape_GetSensorCapacity(b2ShapeId shapeId)
}

b2Shape* shape = b2GetShape( world, shapeId );
if ( shape->sensorIndex != B2_NULL_INDEX )
if ( shape->sensorIndex == B2_NULL_INDEX )
{
return 0;
}
Expand All @@ -1472,7 +1472,7 @@ int b2Shape_GetSensorOverlaps( b2ShapeId shapeId, b2ShapeId* overlaps, int capac
}

b2Shape* shape = b2GetShape( world, shapeId );
if ( shape->sensorIndex != B2_NULL_INDEX )
if ( shape->sensorIndex == B2_NULL_INDEX )
{
return 0;
}
Expand Down
Loading

0 comments on commit 83ee3a6

Please sign in to comment.