#include "draw.h"
#include "sample.h"
#include "settings.h"
#include "box2d/box2d.h"
#include "box2d/math_functions.h"
#include <GLFW/glfw3.h>
#include <imgui.h>
class ChainShape : public Sample
{
public:
enum ShapeType
{
e_circleShape = 0,
e_capsuleShape,
e_boxShape
};
explicit ChainShape( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 0.0f, 0.0f };
g_camera.m_zoom = 25.0f * 1.75f;
}
m_groundId = b2_nullBodyId;
m_bodyId = b2_nullBodyId;
m_chainId = b2_nullChainId;
m_shapeId = b2_nullShapeId;
m_shapeType = e_circleShape;
m_restitution = 0.0f;
m_friction = 0.2f;
CreateScene();
Launch();
}
void CreateScene()
{
if ( B2_IS_NON_NULL( m_groundId ) )
{
b2DestroyBody( m_groundId );
}
b2Vec2 points[] = {
{ -56.885498, 12.8985004 }, { -56.885498, 16.2057495 }, { 56.885498, 16.2057495 }, { 56.885498, -16.2057514 },
{ 51.5935059, -16.2057514 }, { 43.6559982, -10.9139996 }, { 35.7184982, -10.9139996 }, { 27.7809982, -10.9139996 },
{ 21.1664963, -14.2212505 }, { 11.9059982, -16.2057514 }, { 0, -16.2057514 }, { -10.5835037, -14.8827496 },
{ -17.1980019, -13.5597477 }, { -21.1665001, -12.2370014 }, { -25.1355019, -9.5909977 }, { -31.75, -3.63799858 },
{ -38.3644981, 6.2840004 }, { -42.3334999, 9.59125137 }, { -47.625, 11.5755005 }, { -56.885498, 12.8985004 },
};
int count = sizeof( points ) / sizeof( points[0] );
b2ChainDef chainDef = b2DefaultChainDef();
chainDef.points = points;
chainDef.count = count;
chainDef.isLoop = true;
chainDef.friction = 0.2f;
b2BodyDef bodyDef = b2DefaultBodyDef();
m_groundId = b2CreateBody( m_worldId, &bodyDef );
m_chainId = b2CreateChain( m_groundId, &chainDef );
}
void Launch()
{
if ( B2_IS_NON_NULL( m_bodyId ) )
{
b2DestroyBody( m_bodyId );
}
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { -55.0f, 13.5f };
m_bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.density = 1.0f;
shapeDef.friction = m_friction;
shapeDef.restitution = m_restitution;
if ( m_shapeType == e_circleShape )
{
b2Circle circle = { { 0.0f, 0.0f }, 0.5f };
m_shapeId = b2CreateCircleShape( m_bodyId, &shapeDef, &circle );
}
else if ( m_shapeType == e_capsuleShape )
{
b2Capsule capsule = { { -0.5f, 0.0f }, { 0.5f, 0.0 }, 0.25f };
m_shapeId = b2CreateCapsuleShape( m_bodyId, &shapeDef, &capsule );
}
else
{
float h = 0.5f;
b2Polygon box = b2MakeBox( h, h );
m_shapeId = b2CreatePolygonShape( m_bodyId, &shapeDef, &box );
}
}
void UpdateUI() override
{
float height = 135.0f;
ImGui::SetNextWindowPos( ImVec2( 10.0f, g_camera.m_height - height - 50.0f ), ImGuiCond_Once );
ImGui::SetNextWindowSize( ImVec2( 240.0f, height ) );
ImGui::Begin( "Chain Shape", nullptr, ImGuiWindowFlags_NoResize );
const char* shapeTypes[] = { "Circle", "Capsule", "Box" };
int shapeType = int( m_shapeType );
if ( ImGui::Combo( "Shape", &shapeType, shapeTypes, IM_ARRAYSIZE( shapeTypes ) ) )
{
m_shapeType = ShapeType( shapeType );
Launch();
}
if ( ImGui::SliderFloat( "Friction", &m_friction, 0.0f, 1.0f, "%.2f" ) )
{
b2Shape_SetFriction( m_shapeId, m_friction );
b2Chain_SetFriction( m_chainId, m_friction );
}
if ( ImGui::SliderFloat( "Restitution", &m_restitution, 0.0f, 2.0f, "%.1f" ) )
{
b2Shape_SetRestitution( m_shapeId, m_restitution );
}
if ( ImGui::Button( "Launch" ) )
{
Launch();
}
ImGui::End();
}
void Step( Settings& settings ) override
{
Sample::Step( settings );
g_draw.DrawSegment( b2Vec2_zero, { 0.5f, 0.0f }, b2_colorRed );
g_draw.DrawSegment( b2Vec2_zero, { 0.0f, 0.5f }, b2_colorGreen );
}
static Sample* Create( Settings& settings )
{
return new ChainShape( settings );
}
b2BodyId m_groundId;
b2BodyId m_bodyId;
b2ChainId m_chainId;
ShapeType m_shapeType;
b2ShapeId m_shapeId;
float m_restitution;
float m_friction;
};
static int sampleChainShape = RegisterSample( "Shapes", "Chain Shape", ChainShape::Create );
class CompoundShapes : public Sample
{
public:
explicit CompoundShapes( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 0.0f, 6.0f };
g_camera.m_zoom = 25.0f * 0.5f;
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Segment segment = { { 50.0f, 0.0f }, { -50.0f, 0.0f } };
b2CreateSegmentShape( groundId, &shapeDef, &segment );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { -15.0f, 1.0f };
m_table1Id = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon top = b2MakeOffsetBox( 3.0f, 0.5f, { 0.0f, 3.5f }, b2Rot_identity );
b2Polygon leftLeg = b2MakeOffsetBox( 0.5f, 1.5f, { -2.5f, 1.5f }, b2Rot_identity );
b2Polygon rightLeg = b2MakeOffsetBox( 0.5f, 1.5f, { 2.5f, 1.5f }, b2Rot_identity );
b2CreatePolygonShape( m_table1Id, &shapeDef, &top );
b2CreatePolygonShape( m_table1Id, &shapeDef, &leftLeg );
b2CreatePolygonShape( m_table1Id, &shapeDef, &rightLeg );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { -5.0f, 1.0f };
m_table2Id = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon top = b2MakeOffsetBox( 3.0f, 0.5f, { 0.0f, 3.5f }, b2Rot_identity );
b2Polygon leftLeg = b2MakeOffsetBox( 0.5f, 2.0f, { -2.5f, 2.0f }, b2Rot_identity );
b2Polygon rightLeg = b2MakeOffsetBox( 0.5f, 2.0f, { 2.5f, 2.0f }, b2Rot_identity );
b2CreatePolygonShape( m_table2Id, &shapeDef, &top );
b2CreatePolygonShape( m_table2Id, &shapeDef, &leftLeg );
b2CreatePolygonShape( m_table2Id, &shapeDef, &rightLeg );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { 5.0f, 1.0f };
m_ship1Id = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Vec2 vertices[3];
vertices[0] = { -2.0f, 0.0f };
vertices[1] = { 0.0f, 4.0f / 3.0f };
vertices[2] = { 0.0f, 4.0f };
b2Hull hull = b2ComputeHull( vertices, 3 );
b2Polygon left = b2MakePolygon( &hull, 0.0f );
vertices[0] = { 2.0f, 0.0f };
vertices[1] = { 0.0f, 4.0f / 3.0f };
vertices[2] = { 0.0f, 4.0f };
hull = b2ComputeHull( vertices, 3 );
b2Polygon right = b2MakePolygon( &hull, 0.0f );
b2CreatePolygonShape( m_ship1Id, &shapeDef, &left );
b2CreatePolygonShape( m_ship1Id, &shapeDef, &right );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { 15.0f, 1.0f };
m_ship2Id = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Vec2 vertices[3];
vertices[0] = { -2.0f, 0.0f };
vertices[1] = { 1.0f, 2.0f };
vertices[2] = { 0.0f, 4.0f };
b2Hull hull = b2ComputeHull( vertices, 3 );
b2Polygon left = b2MakePolygon( &hull, 0.0f );
vertices[0] = { 2.0f, 0.0f };
vertices[1] = { -1.0f, 2.0f };
vertices[2] = { 0.0f, 4.0f };
hull = b2ComputeHull( vertices, 3 );
b2Polygon right = b2MakePolygon( &hull, 0.0f );
b2CreatePolygonShape( m_ship2Id, &shapeDef, &left );
b2CreatePolygonShape( m_ship2Id, &shapeDef, &right );
}
m_drawBodyAABBs = false;
}
void Spawn()
{
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Body_GetPosition( m_table1Id );
bodyDef.rotation = b2Body_GetRotation( m_table1Id );
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeOffsetBox( 4.0f, 0.1f, { 0.0f, 3.0f }, b2Rot_identity );
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Body_GetPosition( m_table2Id );
bodyDef.rotation = b2Body_GetRotation( m_table2Id );
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeOffsetBox( 4.0f, 0.1f, { 0.0f, 3.0f }, b2Rot_identity );
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Body_GetPosition( m_ship1Id );
bodyDef.rotation = b2Body_GetRotation( m_ship1Id );
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Circle circle = { { 0.0f, 2.0f }, 0.5f };
b2CreateCircleShape( bodyId, &shapeDef, &circle );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Body_GetPosition( m_ship2Id );
bodyDef.rotation = b2Body_GetRotation( m_ship2Id );
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Circle circle = { { 0.0f, 2.0f }, 0.5f };
b2CreateCircleShape( bodyId, &shapeDef, &circle );
}
}
void UpdateUI() override
{
float height = 100.0f;
ImGui::SetNextWindowPos( ImVec2( 10.0f, g_camera.m_height - height - 50.0f ), ImGuiCond_Once );
ImGui::SetNextWindowSize( ImVec2( 180.0f, height ) );
ImGui::Begin( "Compound Shapes", nullptr, ImGuiWindowFlags_NoResize );
if ( ImGui::Button( "Intrude" ) )
{
Spawn();
}
ImGui::Checkbox( "Body AABBs", &m_drawBodyAABBs );
ImGui::End();
}
void Step( Settings& settings ) override
{
Sample::Step( settings );
if ( m_drawBodyAABBs )
{
b2AABB aabb = b2Body_ComputeAABB( m_table1Id );
g_draw.DrawAABB( aabb, b2_colorYellow );
aabb = b2Body_ComputeAABB( m_table2Id );
g_draw.DrawAABB( aabb, b2_colorYellow );
aabb = b2Body_ComputeAABB( m_ship1Id );
g_draw.DrawAABB( aabb, b2_colorYellow );
aabb = b2Body_ComputeAABB( m_ship2Id );
g_draw.DrawAABB( aabb, b2_colorYellow );
}
}
static Sample* Create( Settings& settings )
{
return new CompoundShapes( settings );
}
b2BodyId m_table1Id;
b2BodyId m_table2Id;
b2BodyId m_ship1Id;
b2BodyId m_ship2Id;
bool m_drawBodyAABBs;
};
static int sampleCompoundShape = RegisterSample( "Shapes", "Compound Shapes", CompoundShapes::Create );
class ShapeFilter : public Sample
{
public:
enum CollisionBits
{
GROUND = 0x00000001,
TEAM1 = 0x00000002,
TEAM2 = 0x00000004,
TEAM3 = 0x00000008,
ALL_BITS = ( ~0u )
};
explicit ShapeFilter( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_zoom = 25.0f * 0.5f;
g_camera.m_center = { 0.0f, 5.0f };
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2Segment segment = { { -20.0f, 0.0f }, { 20.0f, 0.0f } };
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = GROUND;
shapeDef.filter.maskBits = ALL_BITS;
b2CreateSegmentShape( groundId, &shapeDef, &segment );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { 0.0f, 2.0f };
m_player1Id = b2CreateBody( m_worldId, &bodyDef );
bodyDef.position = { 0.0f, 5.0f };
m_player2Id = b2CreateBody( m_worldId, &bodyDef );
bodyDef.position = { 0.0f, 8.0f };
m_player3Id = b2CreateBody( m_worldId, &bodyDef );
b2Polygon box = b2MakeBox( 2.0f, 1.0f );
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.filter.categoryBits = TEAM1;
shapeDef.filter.maskBits = GROUND | TEAM2 | TEAM3;
m_shape1Id = b2CreatePolygonShape( m_player1Id, &shapeDef, &box );
shapeDef.filter.categoryBits = TEAM2;
shapeDef.filter.maskBits = GROUND | TEAM1 | TEAM3;
m_shape2Id = b2CreatePolygonShape( m_player2Id, &shapeDef, &box );
shapeDef.filter.categoryBits = TEAM3;
shapeDef.filter.maskBits = GROUND | TEAM1 | TEAM2;
m_shape3Id = b2CreatePolygonShape( m_player3Id, &shapeDef, &box );
}
}
void UpdateUI() override
{
float height = 240.0f;
ImGui::SetNextWindowPos( ImVec2( 10.0f, g_camera.m_height - height - 50.0f ), ImGuiCond_Once );
ImGui::SetNextWindowSize( ImVec2( 240.0f, height ) );
ImGui::Begin( "Shape Filter", nullptr, ImGuiWindowFlags_NoResize );
ImGui::Text( "Player 1 Collides With" );
{
b2Filter filter1 = b2Shape_GetFilter( m_shape1Id );
bool team2 = ( filter1.maskBits & TEAM2 ) == TEAM2;
if ( ImGui::Checkbox( "Team 2##1", &team2 ) )
{
if ( team2 )
{
filter1.maskBits |= TEAM2;
}
else
{
filter1.maskBits &= ~TEAM2;
}
b2Shape_SetFilter( m_shape1Id, filter1 );
}
bool team3 = ( filter1.maskBits & TEAM3 ) == TEAM3;
if ( ImGui::Checkbox( "Team 3##1", &team3 ) )
{
if ( team3 )
{
filter1.maskBits |= TEAM3;
}
else
{
filter1.maskBits &= ~TEAM3;
}
b2Shape_SetFilter( m_shape1Id, filter1 );
}
}
ImGui::Separator();
ImGui::Text( "Player 2 Collides With" );
{
b2Filter filter2 = b2Shape_GetFilter( m_shape2Id );
bool team1 = ( filter2.maskBits & TEAM1 ) == TEAM1;
if ( ImGui::Checkbox( "Team 1##2", &team1 ) )
{
if ( team1 )
{
filter2.maskBits |= TEAM1;
}
else
{
filter2.maskBits &= ~TEAM1;
}
b2Shape_SetFilter( m_shape2Id, filter2 );
}
bool team3 = ( filter2.maskBits & TEAM3 ) == TEAM3;
if ( ImGui::Checkbox( "Team 3##2", &team3 ) )
{
if ( team3 )
{
filter2.maskBits |= TEAM3;
}
else
{
filter2.maskBits &= ~TEAM3;
}
b2Shape_SetFilter( m_shape2Id, filter2 );
}
}
ImGui::Separator();
ImGui::Text( "Player 3 Collides With" );
{
b2Filter filter3 = b2Shape_GetFilter( m_shape3Id );
bool team1 = ( filter3.maskBits & TEAM1 ) == TEAM1;
if ( ImGui::Checkbox( "Team 1##3", &team1 ) )
{
if ( team1 )
{
filter3.maskBits |= TEAM1;
}
else
{
filter3.maskBits &= ~TEAM1;
}
b2Shape_SetFilter( m_shape3Id, filter3 );
}
bool team2 = ( filter3.maskBits & TEAM2 ) == TEAM2;
if ( ImGui::Checkbox( "Team 2##3", &team2 ) )
{
if ( team2 )
{
filter3.maskBits |= TEAM2;
}
else
{
filter3.maskBits &= ~TEAM2;
}
b2Shape_SetFilter( m_shape3Id, filter3 );
}
}
ImGui::End();
}
void Step( Settings& settings ) override
{
Sample::Step( settings );
b2Vec2 p1 = b2Body_GetPosition( m_player1Id );
g_draw.DrawString( { p1.x - 0.5f, p1.y }, "player 1" );
b2Vec2 p2 = b2Body_GetPosition( m_player2Id );
g_draw.DrawString( { p2.x - 0.5f, p2.y }, "player 2" );
b2Vec2 p3 = b2Body_GetPosition( m_player3Id );
g_draw.DrawString( { p3.x - 0.5f, p3.y }, "player 3" );
}
static Sample* Create( Settings& settings )
{
return new ShapeFilter( settings );
}
b2BodyId m_player1Id;
b2BodyId m_player2Id;
b2BodyId m_player3Id;
b2ShapeId m_shape1Id;
b2ShapeId m_shape2Id;
b2ShapeId m_shape3Id;
};
static int sampleShapeFilter = RegisterSample( "Shapes", "Filter", ShapeFilter::Create );
class CustomFilter : public Sample
{
public:
enum
{
e_count = 10
};
explicit CustomFilter( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 0.0f, 5.0f };
g_camera.m_zoom = 10.0f;
}
b2World_SetCustomFilterCallback( m_worldId, CustomFilterStatic, this );
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2Segment segment = { { -40.0f, 0.0f }, { 40.0f, 0.0f } };
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2CreateSegmentShape( groundId, &shapeDef, &segment );
}
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeSquare( 1.0f );
float x = -e_count;
for ( int i = 0; i < e_count; ++i )
{
bodyDef.position = { x, 5.0f };
m_bodyIds[i] = b2CreateBody( m_worldId, &bodyDef );
shapeDef.userData = reinterpret_cast<void*>( intptr_t( i + 1 ) );
m_shapeIds[i] = b2CreatePolygonShape( m_bodyIds[i], &shapeDef, &box );
x += 2.0f;
}
}
void Step( Settings& settings ) override
{
g_draw.DrawString( 5, m_textLine, "Custom filter disables collision between odd and even shapes" );
m_textLine += m_textIncrement;
Sample::Step( settings );
for ( int i = 0; i < e_count; ++i )
{
b2Vec2 p = b2Body_GetPosition( m_bodyIds[i] );
g_draw.DrawString( { p.x, p.y }, "%d", i );
}
}
bool ShouldCollide( b2ShapeId shapeIdA, b2ShapeId shapeIdB )
{
void* userDataA = b2Shape_GetUserData( shapeIdA );
void* userDataB = b2Shape_GetUserData( shapeIdB );
if ( userDataA == NULL || userDataB == NULL )
{
return true;
}
int indexA = static_cast<int>( reinterpret_cast<intptr_t>( userDataA ) );
int indexB = static_cast<int>( reinterpret_cast<intptr_t>( userDataB ) );
return ( ( indexA & 1 ) + ( indexB & 1 ) ) != 1;
}
static bool CustomFilterStatic( b2ShapeId shapeIdA, b2ShapeId shapeIdB, void* context )
{
CustomFilter* customFilter = static_cast<CustomFilter*>( context );
return customFilter->ShouldCollide( shapeIdA, shapeIdB );
}
static Sample* Create( Settings& settings )
{
return new CustomFilter( settings );
}
b2BodyId m_bodyIds[e_count];
b2ShapeId m_shapeIds[e_count];
};
static int sampleCustomFilter = RegisterSample( "Shapes", "Custom Filter", CustomFilter::Create );
class Restitution : public Sample
{
public:
enum
{
e_count = 40
};
enum ShapeType
{
e_circleShape = 0,
e_boxShape
};
explicit Restitution( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 4.0f, 17.0f };
g_camera.m_zoom = 27.5f;
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
float h = 1.0f * e_count;
b2Segment segment = { { -h, 0.0f }, { h, 0.0f } };
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2CreateSegmentShape( groundId, &shapeDef, &segment );
}
for ( int i = 0; i < e_count; ++i )
{
m_bodyIds[i] = b2_nullBodyId;
}
m_shapeType = e_circleShape;
CreateBodies();
}
void CreateBodies()
{
for ( int i = 0; i < e_count; ++i )
{
if ( B2_IS_NON_NULL( m_bodyIds[i] ) )
{
b2DestroyBody( m_bodyIds[i] );
m_bodyIds[i] = b2_nullBodyId;
}
}
b2Circle circle = { 0 };
circle.radius = 0.5f;
b2Polygon box = b2MakeBox( 0.5f, 0.5f );
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.density = 1.0f;
shapeDef.restitution = 0.0f;
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
float dr = 1.0f / ( e_count > 1 ? e_count - 1 : 1 );
float x = -1.0f * ( e_count - 1 );
float dx = 2.0f;
for ( int i = 0; i < e_count; ++i )
{
bodyDef.position = { x, 40.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
m_bodyIds[i] = bodyId;
if ( m_shapeType == e_circleShape )
{
b2CreateCircleShape( bodyId, &shapeDef, &circle );
}
else
{
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
shapeDef.restitution += dr;
x += dx;
}
}
void UpdateUI() override
{
float height = 100.0f;
ImGui::SetNextWindowPos( ImVec2( 10.0f, g_camera.m_height - height - 50.0f ), ImGuiCond_Once );
ImGui::SetNextWindowSize( ImVec2( 240.0f, height ) );
ImGui::Begin( "Restitution", nullptr, ImGuiWindowFlags_NoResize );
bool changed = false;
const char* shapeTypes[] = { "Circle", "Box" };
int shapeType = int( m_shapeType );
changed = changed || ImGui::Combo( "Shape", &shapeType, shapeTypes, IM_ARRAYSIZE( shapeTypes ) );
m_shapeType = ShapeType( shapeType );
changed = changed || ImGui::Button( "Reset" );
if ( changed )
{
CreateBodies();
}
ImGui::End();
}
static Sample* Create( Settings& settings )
{
return new Restitution( settings );
}
b2BodyId m_bodyIds[e_count];
ShapeType m_shapeType;
};
static int sampleIndex = RegisterSample( "Shapes", "Restitution", Restitution::Create );
class Friction : public Sample
{
public:
explicit Friction( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 0.0f, 14.0f };
g_camera.m_zoom = 25.0f * 0.6f;
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.friction = 0.2f;
b2Segment segment = { { -40.0f, 0.0f }, { 40.0f, 0.0f } };
b2CreateSegmentShape( groundId, &shapeDef, &segment );
b2Polygon box = b2MakeOffsetBox( 13.0f, 0.25f, { -4.0f, 22.0f }, b2MakeRot(-0.25f) );
b2CreatePolygonShape( groundId, &shapeDef, &box );
box = b2MakeOffsetBox( 0.25f, 1.0f, { 10.5f, 19.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
box = b2MakeOffsetBox( 13.0f, 0.25f, { 4.0f, 14.0f }, b2MakeRot(0.25f) );
b2CreatePolygonShape( groundId, &shapeDef, &box );
box = b2MakeOffsetBox( 0.25f, 1.0f, { -10.5f, 11.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
box = b2MakeOffsetBox( 13.0f, 0.25f, { -4.0f, 6.0f }, b2MakeRot(-0.25f) );
b2CreatePolygonShape( groundId, &shapeDef, &box );
}
{
b2Polygon box = b2MakeBox( 0.5f, 0.5f );
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.density = 25.0f;
float friction[5] = { 0.75f, 0.5f, 0.35f, 0.1f, 0.0f };
for ( int i = 0; i < 5; ++i )
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { -15.0f + 4.0f * i, 28.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
shapeDef.friction = friction[i];
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
}
}
static Sample* Create( Settings& settings )
{
return new Friction( settings );
}
};
static int sampleIndex3 = RegisterSample( "Shapes", "Friction", Friction::Create );
class ModifyGeometry : public Sample
{
public:
explicit ModifyGeometry( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_zoom = 25.0f * 0.25f;
g_camera.m_center = { 0.0f, 5.0f };
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeOffsetBox( 10.0f, 1.0f, { 0.0f, -1.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position = { 0.0f, 4.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeBox( 1.0f, 1.0f );
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
{
m_shapeType = b2_circleShape;
m_scale = 1.0f;
m_circle = { { 0.0f, 0.0f }, 0.5f };
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_kinematicBody;
bodyDef.position = { 0.0f, 1.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
m_shapeId = b2CreateCircleShape( bodyId, &shapeDef, &m_circle );
}
}
void UpdateShape()
{
switch ( m_shapeType )
{
case b2_circleShape:
m_circle = { { 0.0f, 0.0f }, 0.5f * m_scale };
b2Shape_SetCircle( m_shapeId, &m_circle );
break;
case b2_capsuleShape:
m_capsule = { { -0.5f * m_scale, 0.0f }, { 0.0f, 0.5f * m_scale }, 0.5f * m_scale };
b2Shape_SetCapsule( m_shapeId, &m_capsule );
break;
case b2_segmentShape:
m_segment = { { -0.5f * m_scale, 0.0f }, { 0.75f * m_scale, 0.0f } };
b2Shape_SetSegment( m_shapeId, &m_segment );
break;
case b2_polygonShape:
m_polygon = b2MakeBox( 0.5f * m_scale, 0.75f * m_scale );
b2Shape_SetPolygon( m_shapeId, &m_polygon );
break;
default:
assert( false );
break;
}
b2BodyId bodyId = b2Shape_GetBody( m_shapeId );
b2Body_ApplyMassFromShapes( bodyId );
}
void UpdateUI() override
{
float height = 230.0f;
ImGui::SetNextWindowPos( ImVec2( 10.0f, g_camera.m_height - height - 50.0f ), ImGuiCond_Once );
ImGui::SetNextWindowSize( ImVec2( 200.0f, height ) );
ImGui::Begin( "Modify Geometry", nullptr, ImGuiWindowFlags_NoResize );
if ( ImGui::RadioButton( "Circle", m_shapeType == b2_circleShape ) )
{
m_shapeType = b2_circleShape;
UpdateShape();
}
if ( ImGui::RadioButton( "Capsule", m_shapeType == b2_capsuleShape ) )
{
m_shapeType = b2_capsuleShape;
UpdateShape();
}
if ( ImGui::RadioButton( "Segment", m_shapeType == b2_segmentShape ) )
{
m_shapeType = b2_segmentShape;
UpdateShape();
}
if ( ImGui::RadioButton( "Polygon", m_shapeType == b2_polygonShape ) )
{
m_shapeType = b2_polygonShape;
UpdateShape();
}
if ( ImGui::SliderFloat( "Scale", &m_scale, 0.1f, 10.0f, "%.2f" ) )
{
UpdateShape();
}
b2BodyId bodyId = b2Shape_GetBody( m_shapeId );
b2BodyType bodyType = b2Body_GetType( bodyId );
if ( ImGui::RadioButton( "Static", bodyType == b2_staticBody ) )
{
b2Body_SetType( bodyId, b2_staticBody );
}
if ( ImGui::RadioButton( "Kinematic", bodyType == b2_kinematicBody ) )
{
b2Body_SetType( bodyId, b2_kinematicBody );
}
if ( ImGui::RadioButton( "Dynamic", bodyType == b2_dynamicBody ) )
{
b2Body_SetType( bodyId, b2_dynamicBody );
}
ImGui::End();
}
void Step( Settings& settings ) override
{
Sample::Step( settings );
}
static Sample* Create( Settings& settings )
{
return new ModifyGeometry( settings );
}
b2ShapeId m_shapeId;
b2ShapeType m_shapeType;
float m_scale;
union
{
b2Circle m_circle;
b2Capsule m_capsule;
b2Segment m_segment;
b2Polygon m_polygon;
};
};
static int sampleModifyGeometry = RegisterSample( "Shapes", "Modify Geometry", ModifyGeometry::Create );
class ChainLink : public Sample
{
public:
explicit ChainLink( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_center = { 0.0f, 5.0f };
g_camera.m_zoom = 25.0f * 0.5f;
}
b2Vec2 points1[] = { { 40.0f, 1.0f }, { 0.0f, 0.0f }, { -40.0f, 0.0f },
{ -40.0f, -1.0f }, { 0.0f, -1.0f }, { 40.0f, -1.0f } };
b2Vec2 points2[] = { { -40.0f, -1.0f }, { 0.0f, -1.0f }, { 40.0f, -1.0f },
{ 40.0f, 0.0f }, { 0.0f, 0.0f }, { -40.0f, 0.0f } };
int count1 = std::size( points1 );
int count2 = std::size( points2 );
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
{
b2ChainDef chainDef = b2DefaultChainDef();
chainDef.points = points1;
chainDef.count = count1;
chainDef.isLoop = false;
b2CreateChain( groundId, &chainDef );
}
{
b2ChainDef chainDef = b2DefaultChainDef();
chainDef.points = points2;
chainDef.count = count2;
chainDef.isLoop = false;
b2CreateChain( groundId, &chainDef );
}
bodyDef.type = b2_dynamicBody;
b2ShapeDef shapeDef = b2DefaultShapeDef();
{
bodyDef.position = { -5.0f, 2.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2Circle circle = { { 0.0f, 0.0f }, 0.5f };
b2CreateCircleShape( bodyId, &shapeDef, &circle );
}
{
bodyDef.position = { 0.0f, 2.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2Capsule capsule = { { -0.5f, 0.0f }, { 0.5f, 0.0 }, 0.25f };
b2CreateCapsuleShape( bodyId, &shapeDef, &capsule );
}
{
bodyDef.position = { 5.0f, 2.0f };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
float h = 0.5f;
b2Polygon box = b2MakeBox( h, h );
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
}
void Step( Settings& settings ) override
{
Sample::Step( settings );
g_draw.DrawString( 5, m_textLine, "This shows how to link together two chain shapes" );
m_textLine += m_textIncrement;
}
static Sample* Create( Settings& settings )
{
return new ChainLink( settings );
}
};
static int sampleChainLink = RegisterSample( "Shapes", "Chain Link", ChainLink::Create );
class RoundedShapes : public Sample
{
public:
explicit RoundedShapes( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_zoom = 25.0f * 0.55f;
g_camera.m_center = { 2.0f, 8.0f };
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeOffsetBox( 20.0f, 1.0f, { 0.0f, -1.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
box = b2MakeOffsetBox( 1.0f, 5.0f, { 19.0f, 5.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
box = b2MakeOffsetBox( 1.0f, 5.0f, { -19.0f, 5.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
}
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.type = b2_dynamicBody;
b2ShapeDef shapeDef = b2DefaultShapeDef();
float y = 2.0f;
int xcount = 10, ycount = 10;
for ( int i = 0; i < ycount; ++i )
{
float x = -5.0f;
for ( int j = 0; j < xcount; ++j )
{
bodyDef.position = { x, y };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2Polygon poly = RandomPolygon( 0.5f );
poly.radius = RandomFloat( 0.05f, 0.25f );
b2CreatePolygonShape( bodyId, &shapeDef, &poly );
x += 1.0f;
}
y += 1.0f;
}
}
static Sample* Create( Settings& settings )
{
return new RoundedShapes( settings );
}
};
static int sampleRoundedShapes = RegisterSample( "Shapes", "Rounded", RoundedShapes::Create );
class OffsetShapes : public Sample
{
public:
explicit OffsetShapes( Settings& settings )
: Sample( settings )
{
if ( settings.restart == false )
{
g_camera.m_zoom = 25.0f * 0.55f;
g_camera.m_center = { 2.0f, 8.0f };
}
{
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.position = { -1.0f, 1.0f };
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2Polygon box = b2MakeOffsetBox( 1.0f, 1.0f, { 10.0f, -2.0f }, b2MakeRot(0.5f * b2_pi) );
b2CreatePolygonShape( groundId, &shapeDef, &box );
}
{
b2Capsule capsule = { { -5.0f, 1.0f }, { -4.0f, 1.0f }, 0.25f };
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.position = { 13.5f, -0.75f };
bodyDef.type = b2_dynamicBody;
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2CreateCapsuleShape( bodyId, &shapeDef, &capsule );
}
{
b2Polygon box = b2MakeOffsetBox( 0.75f, 0.5f, { 9.0f, 2.0f }, b2MakeRot(0.5f * b2_pi) );
b2BodyDef bodyDef = b2DefaultBodyDef();
bodyDef.position = { 0.0f, 0.0f };
bodyDef.type = b2_dynamicBody;
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );
b2ShapeDef shapeDef = b2DefaultShapeDef();
b2CreatePolygonShape( bodyId, &shapeDef, &box );
}
}
void Step( Settings& settings ) override
{
Sample::Step( settings );
g_draw.DrawTransform( b2Transform_identity );
}
static Sample* Create( Settings& settings )
{
return new OffsetShapes( settings );
}
};
static int sampleOffsetShapes = RegisterSample( "Shapes", "Offset", OffsetShapes::Create );