Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,8 @@ B2_API b2Vec2 b2World_GetGravity( b2WorldId worldId );

/// Apply a radial explosion
/// @param worldId The world id
/// @param position The center of the explosion
/// @param radius The radius of the explosion
/// @param impulse The impulse of the explosion, typically in kg * m / s or N * s.
B2_API void b2World_Explode( b2WorldId worldId, b2Vec2 position, float radius, float impulse );
/// @param explosionDef The explosion definition
B2_API void b2World_Explode( b2WorldId worldId, const b2ExplosionDef* explosionDef );

/// Adjust contact tuning parameters
/// @param worldId The world id
Expand Down Expand Up @@ -1006,6 +1004,12 @@ B2_API float b2RevoluteJoint_GetMaxMotorTorque( b2JointId jointId );
/// @see b2WeldJointDef for details
B2_API b2JointId b2CreateWeldJoint( b2WorldId worldId, const b2WeldJointDef* def );

/// Get the weld joint reference angle in radians
B2_API float b2WeldJoint_GetReferenceAngle( b2JointId jointId );

/// Set the weld joint reference angle in radians, must be in [-pi,pi].
B2_API void b2WeldJoint_SetReferenceAngle( b2JointId jointId, float angleInRadians );

/// Set the weld joint linear stiffness in Hertz. 0 is rigid.
B2_API void b2WeldJoint_SetLinearHertz( b2JointId jointId, float hertz );

Expand Down
35 changes: 34 additions & 1 deletion include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
#include <stdbool.h>
#include <stdint.h>

/// Task interface
#define B2_DEFAULT_CATEGORY_BITS 0x0001ULL
#define B2_DEFAULT_MASK_BITS UINT64_MAX

/// Task interface
/// This is prototype for a Box2D task. Your task system is expected to invoke the Box2D task with these arguments.
/// The task spans a range of the parallel-for: [startIndex, endIndex)
/// The worker index must correctly identify each worker in the user thread pool, expected in [0, workerCount).
Expand Down Expand Up @@ -391,6 +394,9 @@ typedef struct b2ChainDef
/// Contact filtering data.
b2Filter filter;

/// Custom debug draw color.
uint32_t customColor;

/// Indicates a closed chain formed by connecting the first and last points
bool isLoop;

Expand Down Expand Up @@ -865,6 +871,33 @@ typedef struct b2WheelJointDef
/// @ingroup wheel_joint
B2_API b2WheelJointDef b2DefaultWheelJointDef( void );

/// The explosion definition is used to configure options for explosions. Explosions
/// consider shape geometry when computing the impulse.
/// @ingroup world
typedef struct b2ExplosionDef
{
/// Mask bits to filter shapes
uint64_t maskBits;

/// The center of the explosion in world space
b2Vec2 position;

/// The radius of the explosion
float radius;

/// The falloff distance beyond the radius. Impulse is reduced to zero at this distance.
float falloff;

/// Impulse per unit length. This applies an impulse according to the shape perimeter that
/// is facing the explosion. Explosions only apply to circles, capsules, and polygons. This
/// may be negative for implosions.
float impulsePerLength;
} b2ExplosionDef;

/// Use this to initialize your explosion definition
/// @ingroup world
B2_API b2ExplosionDef b2DefaultExplosionDef( void );

/**
* @defgroup events Events
* World event types.
Expand Down
7 changes: 6 additions & 1 deletion samples/sample_bodies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,12 @@ class Weeble : public Sample

if ( ImGui::Button( "Explode" ) )
{
b2World_Explode( m_worldId, m_explosionPosition, m_explosionRadius, m_explosionMagnitude );
b2ExplosionDef def = b2DefaultExplosionDef();
def.position = m_explosionPosition;
def.radius = m_explosionRadius;
def.falloff = 0.1f;
def.impulsePerLength = m_explosionMagnitude;
b2World_Explode( m_worldId, &def );
}
ImGui::PushItemWidth( 100.0f );

Expand Down
11 changes: 8 additions & 3 deletions samples/sample_events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ class BodyMove : public Sample

m_explosionPosition = { 0.0f, -5.0f };
m_explosionRadius = 10.0f;
m_explosionMagnitude = 6.0f;
m_explosionMagnitude = 10.0f;
}

void CreateBodies()
Expand Down Expand Up @@ -1046,10 +1046,15 @@ class BodyMove : public Sample

if ( ImGui::Button( "Explode" ) )
{
b2World_Explode( m_worldId, m_explosionPosition, m_explosionRadius, m_explosionMagnitude );
b2ExplosionDef def = b2DefaultExplosionDef();
def.position = m_explosionPosition;
def.radius = m_explosionRadius;
def.falloff = 0.1f;
def.impulsePerLength = m_explosionMagnitude;
b2World_Explode( m_worldId, &def );
}

ImGui::SliderFloat( "Magnitude", &m_explosionMagnitude, -8.0f, 8.0f, "%.1f" );
ImGui::SliderFloat( "Magnitude", &m_explosionMagnitude, -20.0f, 20.0f, "%.1f" );

ImGui::End();
}
Expand Down
116 changes: 116 additions & 0 deletions samples/sample_shapes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class ChainShape : public Sample
b2ChainDef chainDef = b2DefaultChainDef();
chainDef.points = points;
chainDef.count = count;
chainDef.customColor = b2_colorSteelBlue;
chainDef.isLoop = true;
chainDef.friction = 0.2f;

Expand Down Expand Up @@ -1302,3 +1303,118 @@ class OffsetShapes : public Sample
};

static int sampleOffsetShapes = RegisterSample( "Shapes", "Offset", OffsetShapes::Create );

// This shows how to use explosions and demonstrates the projected perimeter
class Explosion : public Sample
{
public:

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

b2BodyDef bodyDef = b2DefaultBodyDef();
b2BodyId groundId = b2CreateBody( m_worldId, &bodyDef );

bodyDef.type = b2_dynamicBody;
bodyDef.gravityScale = 0.0f;
b2ShapeDef shapeDef = b2DefaultShapeDef();

m_referenceAngle = 0.0f;

b2WeldJointDef weldDef = b2DefaultWeldJointDef();
weldDef.referenceAngle = m_referenceAngle;
weldDef.angularHertz = 0.5f;
weldDef.angularDampingRatio = 0.7f;
weldDef.linearHertz = 0.5f;
weldDef.linearDampingRatio = 0.7f;
weldDef.bodyIdA = groundId;
weldDef.localAnchorB = b2Vec2_zero;

float r = 8.0f;
for (float angle = 0.0f; angle < 360.0f; angle += 30.0f)
{
b2CosSin cosSin = b2ComputeCosSin( angle * b2_pi / 180.0f );
bodyDef.position = { r * cosSin.cosine, r * cosSin.sine };
b2BodyId bodyId = b2CreateBody( m_worldId, &bodyDef );

b2Polygon box = b2MakeBox( 1.0f, 0.1f );
b2CreatePolygonShape( bodyId, &shapeDef, &box );

weldDef.localAnchorA = bodyDef.position;
weldDef.bodyIdB = bodyId;
b2JointId jointId = b2CreateWeldJoint( m_worldId, &weldDef );
m_jointIds.push_back( jointId );
}

m_radius = 7.0f;
m_falloff = 3.0f;
m_impulse = 10.0f;
}

void UpdateUI() override
{
float height = 160.0f;
ImGui::SetNextWindowPos( ImVec2( 10.0f, g_camera.m_height - height - 50.0f ), ImGuiCond_Once );
ImGui::SetNextWindowSize( ImVec2( 240.0f, height ) );

ImGui::Begin( "Explosion", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize );

if ( ImGui::Button( "Explode" ) )
{
b2ExplosionDef def = b2DefaultExplosionDef();
def.position = b2Vec2_zero;
def.radius = m_radius;
def.falloff = m_falloff;
def.impulsePerLength = m_impulse;
b2World_Explode( m_worldId, &def );
}

ImGui::SliderFloat( "radius", &m_radius, 0.0f, 20.0f, "%.1f" );
ImGui::SliderFloat( "falloff", &m_falloff, 0.0f, 20.0f, "%.1f" );
ImGui::SliderFloat( "impulse", &m_impulse, -20.0f, 20.0f, "%.1f" );

ImGui::End();
}

void Step( Settings& settings ) override
{
if (settings.pause == false || settings.singleStep == true)
{
m_referenceAngle += settings.hertz > 0.0f ? 60.0f * b2_pi / 180.0f / settings.hertz : 0.0f;
m_referenceAngle = b2UnwindAngle( m_referenceAngle );

int count = m_jointIds.size();
for (int i = 0; i < count; ++i)
{
b2WeldJoint_SetReferenceAngle( m_jointIds[i], m_referenceAngle );
}
}

Sample::Step( settings );

g_draw.DrawString( 5, m_textLine, "reference angle = %g", m_referenceAngle );
m_textLine += m_textIncrement;

g_draw.DrawCircle( b2Vec2_zero, m_radius + m_falloff, b2_colorBox2DBlue );
g_draw.DrawCircle( b2Vec2_zero, m_radius, b2_colorBox2DYellow );
}

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

std::vector<b2JointId> m_jointIds;
float m_radius;
float m_falloff;
float m_impulse;
float m_referenceAngle;
};

static int sampleBodyMove = RegisterSample( "Shapes", "Explosion", Explosion::Create );
9 changes: 8 additions & 1 deletion samples/sample_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,14 @@ class LargeWorld : public Sample
if ( ( m_stepCount & 0x1 ) == 0x1 && m_explode )
{
m_explosionPosition.x = ( 0.5f + m_cycleIndex ) * m_period - span;
b2World_Explode( m_worldId, m_explosionPosition, radius, 1.0f );

b2ExplosionDef def = b2DefaultExplosionDef();
def.position = m_explosionPosition;
def.radius = radius;
def.falloff = 0.1f;
def.impulsePerLength = 1.0f;
b2World_Explode( m_worldId, &def );

m_cycleIndex = ( m_cycleIndex + 1 ) % m_cycleCount;
}

Expand Down
7 changes: 7 additions & 0 deletions src/joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ b2WheelJointDef b2DefaultWheelJointDef( void )
return def;
}

b2ExplosionDef b2DefaultExplosionDef(void)
{
b2ExplosionDef def = { 0 };
def.maskBits = B2_DEFAULT_MASK_BITS;
return def;
}

static b2Joint* b2GetJointFullId( b2World* world, b2JointId jointId )
{
int id = jointId.index1 - 1;
Expand Down
1 change: 1 addition & 0 deletions src/prismatic_joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ void b2PreparePrismaticJoint( b2JointSim* base, b2StepContext* context )
joint->axisA = b2RotateVector( qA, joint->localAxisA );
joint->deltaCenter = b2Sub( bodySimB->center, bodySimA->center );
joint->deltaAngle = b2RelativeAngle( qB, qA ) - joint->referenceAngle;
joint->deltaAngle = b2UnwindAngle( joint->deltaAngle );

b2Vec2 rA = joint->anchorA;
b2Vec2 rB = joint->anchorB;
Expand Down
53 changes: 53 additions & 0 deletions src/shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ b2ChainId b2CreateChain( b2BodyId bodyId, const b2ChainDef* def )
shapeDef.restitution = def->restitution;
shapeDef.friction = def->friction;
shapeDef.filter = def->filter;
shapeDef.customColor = def->customColor;
shapeDef.enableContactEvents = false;
shapeDef.enableHitEvents = false;
shapeDef.enableSensorEvents = false;
Expand Down Expand Up @@ -546,6 +547,58 @@ float b2GetShapePerimeter( const b2Shape* shape )
}
}

// This projects the the shape perimeter onto an infinite line
float b2GetShapeProjectedPerimeter( const b2Shape* shape, b2Vec2 line )
{
switch ( shape->type )
{
case b2_capsuleShape:
{
b2Vec2 axis = b2Sub( shape->capsule.center2, shape->capsule.center1 );
float projectedLength = b2AbsFloat( b2Dot( axis, line ) );
return projectedLength + 2.0f * shape->capsule.radius;
}

case b2_circleShape:
return 2.0f * shape->circle.radius;

case b2_polygonShape:
{
const b2Vec2* points = shape->polygon.vertices;
int count = shape->polygon.count;
B2_ASSERT( count > 0 );
float value = b2Dot( points[0], line );
float lower = value;
float upper = value;
for ( int i = 1; i < count; ++i )
{
value = b2Dot( points[i], line );
lower = b2MinFloat( lower, value );
upper = b2MaxFloat( upper, value );
}

return (upper - lower) + 2.0f * shape->polygon.radius;
}

case b2_segmentShape:
{
float value1 = b2Dot( shape->segment.point1, line );
float value2 = b2Dot( shape->segment.point2, line );
return b2AbsFloat( value2 - value1 );
}

case b2_chainSegmentShape:
{
float value1 = b2Dot( shape->chainSegment.segment.point1, line );
float value2 = b2Dot( shape->chainSegment.segment.point2, line );
return b2AbsFloat( value2 - value1 );
}

default:
return 0.0f;
}
}

b2MassData b2ComputeShapeMass( const b2Shape* shape )
{
switch ( shape->type )
Expand Down
1 change: 1 addition & 0 deletions src/shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ b2ShapeExtent b2ComputeShapeExtent( const b2Shape* shape, b2Vec2 localCenter );
b2AABB b2ComputeShapeAABB( const b2Shape* shape, b2Transform transform );
b2Vec2 b2GetShapeCentroid( const b2Shape* shape );
float b2GetShapePerimeter( const b2Shape* shape );
float b2GetShapeProjectedPerimeter( const b2Shape* shape, b2Vec2 line );

b2DistanceProxy b2MakeShapeDistanceProxy( const b2Shape* shape );

Expand Down
4 changes: 2 additions & 2 deletions src/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ b2BodyDef b2DefaultBodyDef( void )

b2Filter b2DefaultFilter( void )
{
b2Filter filter = { 0x0001ULL, UINT64_MAX, 0 };
b2Filter filter = { B2_DEFAULT_CATEGORY_BITS, B2_DEFAULT_MASK_BITS, 0 };
return filter;
}

b2QueryFilter b2DefaultQueryFilter( void )
{
b2QueryFilter filter = { 0x0001ULL, UINT64_MAX };
b2QueryFilter filter = { B2_DEFAULT_CATEGORY_BITS, B2_DEFAULT_MASK_BITS };
return filter;
}

Expand Down
Loading