From 2a4192a1aef3e20653e0e528c2860e67e6190624 Mon Sep 17 00:00:00 2001 From: Erin Catto Date: Tue, 28 May 2024 21:33:48 -0700 Subject: [PATCH] sample for custom filter --- samples/car.cpp | 6 +-- samples/draw.cpp | 4 +- samples/sample_continuous.cpp | 13 ++--- samples/sample_events.cpp | 2 +- samples/sample_shapes.cpp | 95 +++++++++++++++++++++++++++++++++++ samples/sample_world.cpp | 2 +- 6 files changed, 109 insertions(+), 13 deletions(-) diff --git a/samples/car.cpp b/samples/car.cpp index c68c146c..9bf8fcf6 100644 --- a/samples/car.cpp +++ b/samples/car.cpp @@ -33,12 +33,12 @@ void Car::Spawn(b2WorldId worldId, b2Vec2 position, float scale, float hertz, for (int i = 0; i < 6; ++i) { - vertices[i].x *= scale; - vertices[i].y *= scale; + vertices[i].x *= 0.85f * scale; + vertices[i].y *= 0.85f * scale; } b2Hull hull = b2ComputeHull(vertices, 6); - b2Polygon chassis = b2MakePolygon(&hull, 0.0f); + b2Polygon chassis = b2MakePolygon(&hull, 0.15f * scale); b2ShapeDef shapeDef = b2DefaultShapeDef(); shapeDef.density = 1.0f / scale; diff --git a/samples/draw.cpp b/samples/draw.cpp index 0c53de72..b27d2179 100644 --- a/samples/draw.cpp +++ b/samples/draw.cpp @@ -1451,9 +1451,9 @@ void Draw::DrawString(int x, int y, const char* string, ...) va_end(arg); } -void Draw::DrawString(b2Vec2 pw, const char* string, ...) +void Draw::DrawString(b2Vec2 p, const char* string, ...) { - b2Vec2 ps = g_camera.ConvertWorldToScreen(pw); + b2Vec2 ps = g_camera.ConvertWorldToScreen(p); va_list arg; va_start(arg, string); diff --git a/samples/sample_continuous.cpp b/samples/sample_continuous.cpp index 893c20b4..a4948df8 100644 --- a/samples/sample_continuous.cpp +++ b/samples/sample_continuous.cpp @@ -669,11 +669,12 @@ class GhostCollision : public Sample static int sampleGhostCollision = RegisterSample("Continuous", "Ghost Collision", GhostCollision::Create); -// Speculative collision failure case suggested by Dirk Gregorius -class SpeculativeFail : public Sample +// Speculative collision failure case suggested by Dirk Gregorius. This uses +// a simple fallback scheme to prevent tunneling. +class SpeculativeFallback : public Sample { public: - explicit SpeculativeFail(Settings& settings) + explicit SpeculativeFallback(Settings& settings) : Sample(settings) { if (settings.restart == false) @@ -701,7 +702,7 @@ class SpeculativeFail : public Sample float offset = 8.0f; b2BodyDef bodyDef = b2DefaultBodyDef(); bodyDef.type = b2_dynamicBody; - bodyDef.position = {offset, 8.0f}; + bodyDef.position = {offset, 12.0f}; bodyDef.linearVelocity = {0.0f, -100.0f}; b2BodyId bodyId = b2CreateBody(m_worldId, &bodyDef); @@ -713,11 +714,11 @@ class SpeculativeFail : public Sample static Sample* Create(Settings& settings) { - return new SpeculativeFail(settings); + return new SpeculativeFallback(settings); } }; -static int sampleSpeculativeFail = RegisterSample("Continuous", "Speculative Fail", SpeculativeFail::Create); +static int sampleSpeculativeFallback = RegisterSample("Continuous", "Speculative Fallback", SpeculativeFallback::Create); // This shows a fast moving body that uses continuous collision versus static and dynamic bodies. // This is achieved by setting the ball body as a *bullet*. diff --git a/samples/sample_events.cpp b/samples/sample_events.cpp index 65f99b9b..ffbb45b8 100644 --- a/samples/sample_events.cpp +++ b/samples/sample_events.cpp @@ -366,6 +366,7 @@ class ContactEvent : public Sample bodyDef.gravityScale = 0.0f; bodyDef.linearDamping = 0.5f; bodyDef.angularDamping = 0.5f; + bodyDef.isBullet = true; m_playerId = b2CreateBody(m_worldId, &bodyDef); b2Circle circle = {{0.0f, 0.0f}, 1.0f}; @@ -1012,7 +1013,6 @@ class BodyMove : public Sample ImGui::End(); } - void Step(Settings& settings) override { if (settings.pause == false && (m_stepCount & 15) == 15 && m_count < e_count) diff --git a/samples/sample_shapes.cpp b/samples/sample_shapes.cpp index 3662d7c4..fac6a049 100644 --- a/samples/sample_shapes.cpp +++ b/samples/sample_shapes.cpp @@ -643,6 +643,101 @@ class ShapeFilter : public Sample static int sampleShapeFilter = RegisterSample("Shapes", "Filter", ShapeFilter::Create); +// This shows how to use custom filtering +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; + } + + // Register custom filter + 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(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 = reinterpret_cast(userDataA); + int indexB = reinterpret_cast(userDataB); + + return ((indexA & 1) + (indexB & 1)) != 1; + } + + static bool CustomFilterStatic(b2ShapeId shapeIdA, b2ShapeId shapeIdB, void* context) + { + CustomFilter* customFilter = static_cast(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); + // Restitution is approximate since Box2D uses speculative collision class Restitution : public Sample { diff --git a/samples/sample_world.cpp b/samples/sample_world.cpp index e582d88a..14323d51 100644 --- a/samples/sample_world.cpp +++ b/samples/sample_world.cpp @@ -130,7 +130,7 @@ class LargeWorld : public Sample for (int i = 0; i < 5; ++i) { Donut donut; - donut.Spawn(m_worldId, position, 0.75f, donutIndex + 1, NULL); + donut.Spawn(m_worldId, position, 0.75f, 0, NULL); donutIndex += 1; position.x += 2.0f; }