Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Character movement round 1 #881

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions benchmark/main.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-FileCopyrightText: 2024 Erin Catto
// SPDX-License-Identifier: MIT

#if defined( _MSC_VER ) && !defined( _CRT_SECURE_NO_WARNINGS )
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "TaskScheduler_c.h"
#include "benchmarks.h"
Expand Down
4 changes: 4 additions & 0 deletions docs/simulation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,10 @@ Sensor events should be processed after the world step and before other game log
help you avoid processing stale data.

### Contact Events

todo discuss the expected number of events and how this can change with the time step.
see https://www.iforce2d.net/b2dtut/collision-anatomy

Contact events are available after each world step. Like sensor events these should be
retrieved and processed before performing other game logic. Otherwise
you may be accessing orphaned/invalid data.
Expand Down
3 changes: 2 additions & 1 deletion include/box2d/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ B2_API uint64_t b2GetTicks( void );
/// Get the milliseconds passed from an initial tick value.
B2_API float b2GetMilliseconds( uint64_t ticks );

/// Get the milliseconds passed from an initial tick value.
/// Get the milliseconds passed from an initial tick value. Resets the passed in
/// value to the current tick value.
B2_API float b2GetMillisecondsAndReset( uint64_t* ticks );

/// Yield to be used in a busy loop.
Expand Down
41 changes: 27 additions & 14 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,23 @@ B2_API b2ContactEvents b2World_GetContactEvents( b2WorldId worldId );

/// Overlap test for all shapes that *potentially* overlap the provided AABB
B2_API b2TreeStats b2World_OverlapAABB( b2WorldId worldId, b2AABB aabb, b2QueryFilter filter, b2OverlapResultFcn* fcn,
void* context );
void* context );

/// Overlap test for for all shapes that overlap the provided point.
B2_API b2TreeStats b2World_OverlapPoint( b2WorldId worldId, b2Vec2 point, b2Transform transform,
b2QueryFilter filter, b2OverlapResultFcn* fcn, void* context );
B2_API b2TreeStats b2World_OverlapPoint( b2WorldId worldId, b2Vec2 point, b2Transform transform, b2QueryFilter filter,
b2OverlapResultFcn* fcn, void* context );

/// Overlap test for for all shapes that overlap the provided circle. A zero radius may be used for a point query.
B2_API b2TreeStats b2World_OverlapCircle( b2WorldId worldId, const b2Circle* circle, b2Transform transform,
b2QueryFilter filter, b2OverlapResultFcn* fcn, void* context );
B2_API b2TreeStats b2World_OverlapCircle( b2WorldId worldId, const b2Circle* circle, b2Transform transform, b2QueryFilter filter,
b2OverlapResultFcn* fcn, void* context );

/// Overlap test for all shapes that overlap the provided capsule
B2_API b2TreeStats b2World_OverlapCapsule( b2WorldId worldId, const b2Capsule* capsule, b2Transform transform,
b2QueryFilter filter, b2OverlapResultFcn* fcn, void* context );
b2QueryFilter filter, b2OverlapResultFcn* fcn, void* context );

/// Overlap test for all shapes that overlap the provided polygon
B2_API b2TreeStats b2World_OverlapPolygon( b2WorldId worldId, const b2Polygon* polygon, b2Transform transform,
b2QueryFilter filter, b2OverlapResultFcn* fcn, void* context );
b2QueryFilter filter, b2OverlapResultFcn* fcn, void* context );

/// Cast a ray into the world to collect shapes in the path of the ray.
/// Your callback function controls whether you get the closest point, any point, or n-points.
Expand All @@ -82,26 +82,32 @@ B2_API b2TreeStats b2World_OverlapPolygon( b2WorldId worldId, const b2Polygon* p
/// @param context A user context that is passed along to the callback function
/// @return traversal performance counters
B2_API b2TreeStats b2World_CastRay( b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter,
b2CastResultFcn* fcn, void* context );
b2CastResultFcn* fcn, void* context );

/// Cast a ray into the world to collect the closest hit. This is a convenience function.
/// This is less general than b2World_CastRay() and does not allow for custom filtering.
B2_API b2RayResult b2World_CastRayClosest( b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter );

/// Cast a circle through the world. Similar to a cast ray except that a circle is cast instead of a point.
/// @see b2World_CastRay
B2_API b2TreeStats b2World_CastCircle( b2WorldId worldId, const b2Circle* circle, b2Transform originTransform,
b2Vec2 translation, b2QueryFilter filter, b2CastResultFcn* fcn, void* context );
B2_API b2TreeStats b2World_CastCircle( b2WorldId worldId, const b2Circle* circle, b2Transform originTransform, b2Vec2 translation,
b2QueryFilter filter, b2CastResultFcn* fcn, void* context );

/// Cast a capsule through the world. Similar to a cast ray except that a capsule is cast instead of a point.
/// @see b2World_CastRay
B2_API b2TreeStats b2World_CastCapsule( b2WorldId worldId, const b2Capsule* capsule, b2Transform originTransform,
b2Vec2 translation, b2QueryFilter filter, b2CastResultFcn* fcn, void* context );
b2Vec2 translation, b2QueryFilter filter, b2CastResultFcn* fcn, void* context );

/// Cast a polygon through the world. Similar to a cast ray except that a polygon is cast instead of a point.
/// @see b2World_CastRay
B2_API b2TreeStats b2World_CastPolygon( b2WorldId worldId, const b2Polygon* polygon, b2Transform originTransform,
b2Vec2 translation, b2QueryFilter filter, b2CastResultFcn* fcn, void* context );
b2Vec2 translation, b2QueryFilter filter, b2CastResultFcn* fcn, void* context );

/// Cast a character through the world. This resolves initial overlap then attempts to reach the target. The character can be
/// an arbitrary rounded polygon. It is recommended to use a capsule. The minimum radius is 0.02m (2 centimeters).
/// Returns the final position.
B2_API b2Vec2 b2World_MoveCharacter( b2WorldId worldId, const b2ShapeProxy* shapeProxy, b2Transform originTransform,
b2Vec2 translation, b2QueryFilter filter );

/// Enable/disable sleep. If your application does not need sleeping, you can gain some performance
/// by disabling sleep completely at the world level.
Expand Down Expand Up @@ -177,7 +183,7 @@ B2_API void b2World_SetMaximumLinearSpeed( b2WorldId worldId, float maximumLinea
B2_API float b2World_GetMaximumLinearSpeed( b2WorldId worldId );

/// Enable/disable constraint warm starting. Advanced feature for testing. Disabling
/// sleeping greatly reduces stability and provides no performance gain.
/// warm starting greatly reduces stability and provides no performance gain.
B2_API void b2World_EnableWarmStarting( b2WorldId worldId, bool flag );

/// Is constraint warm starting enabled?
Expand Down Expand Up @@ -562,7 +568,7 @@ B2_API float b2Shape_GetRestitution( b2ShapeId shapeId );
/// @see b2ShapeDef::material
B2_API void b2Shape_SetMaterial( b2ShapeId shapeId, int material );

/// Get the shape material identifier
/// Get the shape material identifier
B2_API int b2Shape_GetMaterial( b2ShapeId shapeId );

/// Get the shape filter
Expand All @@ -574,6 +580,13 @@ B2_API b2Filter b2Shape_GetFilter( b2ShapeId shapeId );
/// @see b2ShapeDef::filter
B2_API void b2Shape_SetFilter( b2ShapeId shapeId, b2Filter filter );

/// Enable sensor events for this shape.
/// @see b2ShapeDef::enableSensorEvents
B2_API void b2Shape_EnableSensorEvents( b2ShapeId shapeId, bool flag );

/// Returns true if sensor events are enabled.
B2_API bool b2Shape_AreSensorEventsEnabled( b2ShapeId shapeId );

/// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
/// @see b2ShapeDef::enableContactEvents
/// @warning changing this at run-time may lead to lost begin/end events
Expand Down
27 changes: 12 additions & 15 deletions include/box2d/collision.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,22 +382,21 @@ typedef struct b2DistanceInput
/// Output for b2ShapeDistance
typedef struct b2DistanceOutput
{
b2Vec2 pointA; ///< Closest point on shapeA
b2Vec2 pointB; ///< Closest point on shapeB
// todo_erin implement this
// b2Vec2 normal; ///< Normal vector that points from A to B
float distance; ///< The final distance, zero if overlapped
b2Vec2 pointA; ///< Closest point on shapeA
b2Vec2 pointB; ///< Closest point on shapeB
b2Vec2 normal; ///< Normal vector that points from A to B
float distance; ///< The final distance, zero if overlapped
int iterations; ///< Number of GJK iterations used
int simplexCount; ///< The number of simplexes stored in the simplex array
} b2DistanceOutput;

/// Simplex vertex for debugging the GJK algorithm
typedef struct b2SimplexVertex
{
b2Vec2 wA; ///< support point in proxyA
b2Vec2 wB; ///< support point in proxyB
b2Vec2 w; ///< wB - wA
float a; ///< barycentric coordinate for closest point
b2Vec2 wA; ///< support point in proxyA
b2Vec2 wB; ///< support point in proxyB
b2Vec2 w; ///< wB - wA
float a; ///< barycentric coordinate for closest point
int indexA; ///< wA index
int indexB; ///< wB index
} b2SimplexVertex;
Expand All @@ -406,7 +405,7 @@ typedef struct b2SimplexVertex
typedef struct b2Simplex
{
b2SimplexVertex v1, v2, v3; ///< vertices
int count; ///< number of valid vertices
int count; ///< number of valid vertices
} b2Simplex;

/// Compute the closest points between two shapes represented as point clouds.
Expand Down Expand Up @@ -491,7 +490,7 @@ B2_API b2TOIOutput b2TimeOfImpact( const b2TOIInput* input );
/// A manifold point is a contact point belonging to a contact manifold.
/// It holds details related to the geometry and dynamics of the contact points.
/// Box2D uses speculative collision so some contact points may be separated.
/// You may use the maxNormalImpulse to determine if there was an interaction during
/// You may use the totalNormalImpulse to determine if there was an interaction during
/// the time step.
typedef struct b2ManifoldPoint
{
Expand All @@ -516,9 +515,9 @@ typedef struct b2ManifoldPoint
/// The friction impulse
float tangentImpulse;

/// The maximum normal impulse applied during sub-stepping. This is important
/// The total normal impulse applied across sub-stepping and restitution. This is important
/// to identify speculative contact points that had an interaction in the time step.
float maxNormalImpulse;
float totalNormalImpulse;

/// Relative normal velocity pre-solve. Used for hit events. If the normal impulse is
/// zero then there was no hit. Negative means shapes are approaching.
Expand Down Expand Up @@ -760,6 +759,4 @@ B2_API void b2DynamicTree_Validate( const b2DynamicTree* tree );
/// Validate this tree has no enlarged AABBs. For testing.
B2_API void b2DynamicTree_ValidateNoEnlarged( const b2DynamicTree* tree );



/**@}*/
44 changes: 29 additions & 15 deletions include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ typedef struct b2WorldDef
/// This parameter controls how fast overlap is resolved and usually has units of meters per second. This only
/// puts a cap on the resolution speed. The resolution speed is increased by increasing the hertz and/or
/// decreasing the damping ratio.
float contactPushMaxSpeed;
float maxContactPushSpeed;

/// Joint stiffness. Cycles per second.
float jointHertz;
Expand Down Expand Up @@ -365,14 +365,19 @@ typedef struct b2ShapeDef
uint32_t customColor;

/// A sensor shape generates overlap events but never generates a collision response.
/// Sensors do not collide with other sensors and do not have continuous collision.
/// Instead, use a ray or shape cast for those scenarios.
/// Sensors do not have continuous collision. Instead, use a ray or shape cast for those scenarios.
/// Sensors still contribute to the body mass if they have non-zero density.
/// @note Sensor events are disabled by default.
/// @see enableSensorEvents
bool isSensor;

/// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
/// Enable sensor events for this shape. This applies to sensors and non-sensors. False by default, even for sensors.
bool enableSensorEvents;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to rename the new enableSensorEvents flag to detectedBySensors because at first I thought I had to enable this in the sensor itself, but rather it must be enabled in all the other shapes that could be detected by a sensor.


/// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default.
bool enableContactEvents;

/// Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors.
/// Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default.
bool enableHitEvents;

/// Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive
Expand Down Expand Up @@ -464,6 +469,9 @@ typedef struct b2ChainDef
/// Indicates a closed chain formed by connecting the first and last points
bool isLoop;

/// Enable sensors to detect this chain. False by default.
bool enableSensorEvents;

/// Used internally to detect a valid definition. DO NOT SET.
int internalValue;
} b2ChainDef;
Expand Down Expand Up @@ -1377,32 +1385,32 @@ typedef enum b2HexColor
typedef struct b2DebugDraw
{
/// Draw a closed polygon provided in CCW order.
void ( *DrawPolygon )( const b2Vec2* vertices, int vertexCount, b2HexColor color, void* context );
void ( *DrawPolygonFcn )( const b2Vec2* vertices, int vertexCount, b2HexColor color, void* context );

/// Draw a solid closed polygon provided in CCW order.
void ( *DrawSolidPolygon )( b2Transform transform, const b2Vec2* vertices, int vertexCount, float radius, b2HexColor color,
void ( *DrawSolidPolygonFcn )( b2Transform transform, const b2Vec2* vertices, int vertexCount, float radius, b2HexColor color,
void* context );

/// Draw a circle.
void ( *DrawCircle )( b2Vec2 center, float radius, b2HexColor color, void* context );
void ( *DrawCircleFcn )( b2Vec2 center, float radius, b2HexColor color, void* context );

/// Draw a solid circle.
void ( *DrawSolidCircle )( b2Transform transform, float radius, b2HexColor color, void* context );
void ( *DrawSolidCircleFcn )( b2Transform transform, float radius, b2HexColor color, void* context );

/// Draw a solid capsule.
void ( *DrawSolidCapsule )( b2Vec2 p1, b2Vec2 p2, float radius, b2HexColor color, void* context );
void ( *DrawSolidCapsuleFcn )( b2Vec2 p1, b2Vec2 p2, float radius, b2HexColor color, void* context );

/// Draw a line segment.
void ( *DrawSegment )( b2Vec2 p1, b2Vec2 p2, b2HexColor color, void* context );
void ( *DrawSegmentFcn )( b2Vec2 p1, b2Vec2 p2, b2HexColor color, void* context );

/// Draw a transform. Choose your own length scale.
void ( *DrawTransform )( b2Transform transform, void* context );
void ( *DrawTransformFcn )( b2Transform transform, void* context );

/// Draw a point.
void ( *DrawPoint )( b2Vec2 p, float size, b2HexColor color, void* context );
void ( *DrawPointFcn )( b2Vec2 p, float size, b2HexColor color, void* context );

/// Draw a string in world space
void ( *DrawString )( b2Vec2 p, const char* s, b2HexColor color, void* context );
void ( *DrawStringFcn )( b2Vec2 p, const char* s, b2HexColor color, void* context );

/// Bounds to use if restricting drawing to a rectangular region
b2AABB drawingBounds;
Expand All @@ -1420,7 +1428,7 @@ typedef struct b2DebugDraw
bool drawJointExtras;

/// Option to draw the bounding boxes for shapes
bool drawAABBs;
bool drawBounds;

/// Option to draw the mass and center of mass of dynamic bodies
bool drawMass;
Expand All @@ -1440,9 +1448,15 @@ typedef struct b2DebugDraw
/// Option to draw contact normal impulses
bool drawContactImpulses;

/// Option to draw contact feature ids
bool drawContactFeatures;

/// Option to draw contact friction impulses
bool drawFrictionImpulses;

/// Option to draw islands as bounding boxes
bool drawIslands;

/// User context that is passed as an argument to drawing callback functions
void* context;
} b2DebugDraw;
Expand Down
6 changes: 3 additions & 3 deletions samples/donut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Donut::Donut()
m_isSpawned = false;
}

void Donut::Spawn( b2WorldId worldId, b2Vec2 position, float scale, int groupIndex, void* userData )
void Donut::Create( b2WorldId worldId, b2Vec2 position, float scale, int groupIndex, bool enableSensorEvents, void* userData )
{
assert( m_isSpawned == false );

Expand All @@ -42,7 +42,7 @@ void Donut::Spawn( b2WorldId worldId, b2Vec2 position, float scale, int groupInd
bodyDef.userData = userData;

b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.density = 1.0f;
shapeDef.enableSensorEvents = enableSensorEvents;
shapeDef.filter.groupIndex = -groupIndex;
shapeDef.friction = 0.3f;

Expand Down Expand Up @@ -81,7 +81,7 @@ void Donut::Spawn( b2WorldId worldId, b2Vec2 position, float scale, int groupInd
m_isSpawned = true;
}

void Donut::Despawn()
void Donut::Destroy()
{
assert( m_isSpawned == true );

Expand Down
4 changes: 2 additions & 2 deletions samples/donut.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class Donut
public:
Donut();

void Spawn( b2WorldId worldId, b2Vec2 position, float scale, int groupIndex, void* userData );
void Despawn();
void Create( b2WorldId worldId, b2Vec2 position, float scale, int groupIndex, bool enableSensorEvents, void* userData );
void Destroy();

b2BodyId m_bodyIds[e_sides];
b2JointId m_jointIds[e_sides];
Expand Down
Loading
Loading