1111#include < GLFW/glfw3.h>
1212#include < imgui.h>
1313
14- // This tests continuous collision robustness and also demonstrates the speed limits imposed
15- // by b2_maxTranslation and b2_maxRotation.
16- struct HitEvent
17- {
18- b2Vec2 point;
19- float speed;
20- int stepIndex;
21- };
2214
2315class BounceHouse : public Sample
2416{
@@ -30,6 +22,13 @@ class BounceHouse : public Sample
3022 e_boxShape
3123 };
3224
25+ struct HitEvent
26+ {
27+ b2Vec2 point;
28+ float speed;
29+ int stepIndex;
30+ };
31+
3332 explicit BounceHouse ( Settings& settings )
3433 : Sample( settings )
3534 {
@@ -389,64 +388,8 @@ class SkinnyBox : public Sample
389388
390389static int sampleSkinnyBox = RegisterSample( " Continuous" , " Skinny Box" , SkinnyBox::Create );
391390
392- class SpeculativeBug : public Sample
393- {
394- public:
395- explicit SpeculativeBug ( Settings& settings )
396- : Sample( settings )
397- {
398- if ( settings.restart == false )
399- {
400- g_camera.m_center = { 1 .0f , 5 .0f };
401- g_camera.m_zoom = 25 .0f * 0 .25f ;
402- }
403-
404- {
405- b2BodyDef bodyDef = b2DefaultBodyDef ();
406- b2BodyId groundId = b2CreateBody ( m_worldId, &bodyDef );
407-
408- b2Segment segment = { { -10 .0f , 0 .0f }, { 10 .0f , 0 .0f } };
409- b2ShapeDef shapeDef = b2DefaultShapeDef ();
410- b2CreateSegmentShape ( groundId, &shapeDef, &segment );
411-
412- shapeDef.friction = 0 .0f ;
413- b2Polygon box = b2MakeOffsetBox ( 0 .05f , 1 .0f , { 0 .0f , 1 .0f }, b2Rot_identity );
414- b2CreatePolygonShape ( groundId, &shapeDef, &box );
415- }
416-
417- b2BodyDef bodyDef = b2DefaultBodyDef ();
418- bodyDef.type = b2_dynamicBody;
419- for (int i = 0 ; i < 2 ; ++i)
420- {
421- if (i == 0 )
422- {
423- bodyDef.position = { -0 .8f , 0 .25f };
424- bodyDef.isAwake = false ;
425- }
426- else
427- {
428- bodyDef.position = { 0 .8f , 2 .0f };
429- bodyDef.isAwake = true ;
430- }
431-
432- b2BodyId bodyId = b2CreateBody ( m_worldId, &bodyDef );
433-
434- b2ShapeDef shapeDef = b2DefaultShapeDef ();
435- b2Capsule capsule = { { -0 .5f , 0 .0f }, { 0 .5f , 0 .0f }, 0 .25f };
436- b2CreateCapsuleShape ( bodyId, &shapeDef, &capsule );
437- }
438- }
439-
440- static Sample* Create ( Settings& settings )
441- {
442- return new SpeculativeBug ( settings );
443- }
444- };
445-
446- static int sampleSpeculativeBug = RegisterSample( " Continuous" , " Speculative Bug" , SpeculativeBug::Create );
447-
448- // This sample shows ghost collisions
449- class GhostCollision : public Sample
391+ // This sample shows ghost bumps
392+ class GhostBumps : public Sample
450393{
451394public:
452395 enum ShapeType
@@ -456,7 +399,7 @@ class GhostCollision : public Sample
456399 e_boxShape
457400 };
458401
459- explicit GhostCollision ( Settings& settings )
402+ explicit GhostBumps ( Settings& settings )
460403 : Sample( settings )
461404 {
462405 if ( settings.restart == false )
@@ -671,7 +614,7 @@ class GhostCollision : public Sample
671614 ImGui::SetNextWindowPos ( ImVec2 ( 10 .0f , g_camera.m_height - height - 50 .0f ), ImGuiCond_Once );
672615 ImGui::SetNextWindowSize ( ImVec2 ( 180 .0f , height ) );
673616
674- ImGui::Begin ( " Ghost Collision " , nullptr , ImGuiWindowFlags_NoResize );
617+ ImGui::Begin ( " Ghost Bumps " , nullptr , ImGuiWindowFlags_NoResize );
675618 ImGui::PushItemWidth ( 100 .0f );
676619
677620 if ( ImGui::Checkbox ( " Chain" , &m_useChain ) )
@@ -720,7 +663,7 @@ class GhostCollision : public Sample
720663
721664 static Sample* Create ( Settings& settings )
722665 {
723- return new GhostCollision ( settings );
666+ return new GhostBumps ( settings );
724667 }
725668
726669 b2BodyId m_groundId;
@@ -733,7 +676,7 @@ class GhostCollision : public Sample
733676 bool m_useChain;
734677};
735678
736- static int sampleGhostCollision = RegisterSample( " Continuous" , " Ghost Collision" , GhostCollision ::Create );
679+ static int sampleGhostCollision = RegisterSample( " Continuous" , " Ghost Collision" , GhostBumps ::Create );
737680
738681// Speculative collision failure case suggested by Dirk Gregorius. This uses
739682// a simple fallback scheme to prevent tunneling.
@@ -786,6 +729,55 @@ class SpeculativeFallback : public Sample
786729
787730static int sampleSpeculativeFallback = RegisterSample( " Continuous" , " Speculative Fallback" , SpeculativeFallback::Create );
788731
732+ // This shows that while Box2D uses speculative collision, it does not lead to speculative ghost collisions at small distances
733+ class SpeculativeGhost : public Sample
734+ {
735+ public:
736+ explicit SpeculativeGhost ( Settings& settings )
737+ : Sample( settings )
738+ {
739+ if ( settings.restart == false )
740+ {
741+ g_camera.m_center = { 0 .0f , 1 .75f };
742+ g_camera.m_zoom = 2 .0f ;
743+ }
744+
745+ {
746+ b2BodyDef bodyDef = b2DefaultBodyDef ();
747+ b2BodyId groundId = b2CreateBody ( m_worldId, &bodyDef );
748+
749+ b2ShapeDef shapeDef = b2DefaultShapeDef ();
750+ b2Segment segment = { { -10 .0f , 0 .0f }, { 10 .0f , 0 .0f } };
751+ b2CreateSegmentShape ( groundId, &shapeDef, &segment );
752+
753+ b2Polygon box = b2MakeOffsetBox ( 1 .0f , 0 .1f , { 0 .0f , 0 .9f }, b2Rot_identity );
754+ b2CreatePolygonShape ( groundId, &shapeDef, &box );
755+ }
756+
757+ {
758+ b2BodyDef bodyDef = b2DefaultBodyDef ();
759+ bodyDef.type = b2_dynamicBody;
760+
761+ // The speculative distance is 0.02 meters, so this avoid it
762+ bodyDef.position = { 0 .015f , 2 .515f };
763+ bodyDef.linearVelocity = { 0 .1f * 1 .25f * settings.hertz , -0 .1f * 1 .25f * settings.hertz };
764+ bodyDef.gravityScale = 0 .0f ;
765+ b2BodyId bodyId = b2CreateBody ( m_worldId, &bodyDef );
766+
767+ b2ShapeDef shapeDef = b2DefaultShapeDef ();
768+ b2Polygon box = b2MakeSquare ( 0 .25f );
769+ b2CreatePolygonShape ( bodyId, &shapeDef, &box );
770+ }
771+ }
772+
773+ static Sample* Create ( Settings& settings )
774+ {
775+ return new SpeculativeGhost ( settings );
776+ }
777+ };
778+
779+ static int sampleSpeculativeGhost = RegisterSample( " Continuous" , " Speculative Ghost" , SpeculativeGhost::Create );
780+
789781// This shows a fast moving body that uses continuous collision versus static and dynamic bodies.
790782// This is achieved by setting the ball body as a *bullet*.
791783class Pinball : public Sample
0 commit comments