Browse Source

Merge pull request #1856 from eugeneko/master

Improve Box2D integration
Eugene Kozlov 8 years ago
parent
commit
cd6f76f26e

+ 32 - 0
Source/Urho3D/Urho2D/PhysicsEvents2D.h

@@ -31,6 +31,21 @@
 namespace Urho3D
 {
 
+/// Physics update contact. Global event sent by PhysicsWorld2D.
+URHO3D_EVENT(E_PHYSICSUPDATECONTACT2D, PhysicsUpdateContact2D)
+{
+    URHO3D_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
+    URHO3D_PARAM(P_BODYA, BodyA);                  // RigidBody2D pointer
+    URHO3D_PARAM(P_BODYB, BodyB);                  // RigidBody2D pointer
+    URHO3D_PARAM(P_NODEA, NodeA);                  // Node pointer
+    URHO3D_PARAM(P_NODEB, NodeB);                  // Node pointer
+    URHO3D_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+    URHO3D_PARAM(P_CONTACTPOINTS, ContactPoints);  // Buffer containing position (Vector2), normal (Vector2), negative overlap distance (float). Normal is the same for all points.
+    URHO3D_PARAM(P_SHAPEA, ShapeA);                // CollisionShape2D pointer
+    URHO3D_PARAM(P_SHAPEB, ShapeB);                // CollisionShape2D pointer
+    URHO3D_PARAM(P_ENABLED, Enabled);              // bool [in/out]
+}
+
 /// Physics begin contact. Global event sent by PhysicsWorld2D.
 URHO3D_EVENT(E_PHYSICSBEGINCONTACT2D, PhysicsBeginContact2D)
 {
@@ -40,6 +55,7 @@ URHO3D_EVENT(E_PHYSICSBEGINCONTACT2D, PhysicsBeginContact2D)
     URHO3D_PARAM(P_NODEA, NodeA);                  // Node pointer
     URHO3D_PARAM(P_NODEB, NodeB);                  // Node pointer
     URHO3D_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+    URHO3D_PARAM(P_CONTACTPOINTS, ContactPoints);  // Buffer containing position (Vector2), normal (Vector2), negative overlap distance (float). Normal is the same for all points.
     URHO3D_PARAM(P_SHAPEA, ShapeA);                // CollisionShape2D pointer
     URHO3D_PARAM(P_SHAPEB, ShapeB);                // CollisionShape2D pointer
 }
@@ -53,10 +69,24 @@ URHO3D_EVENT(E_PHYSICSENDCONTACT2D, PhysicsEndContact2D)
     URHO3D_PARAM(P_NODEA, NodeA);                  // Node pointer
     URHO3D_PARAM(P_NODEB, NodeB);                  // Node pointer
     URHO3D_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+    URHO3D_PARAM(P_CONTACTPOINTS, ContactPoints);  // Buffer containing position (Vector2), normal (Vector2), negative overlap distance (float). Normal is the same for all points.
     URHO3D_PARAM(P_SHAPEA, ShapeA);                // CollisionShape2D pointer
     URHO3D_PARAM(P_SHAPEB, ShapeB);                // CollisionShape2D pointer
 }
 
+/// Node update contact. Sent by scene nodes participating in a collision.
+URHO3D_EVENT(E_NODEUPDATECONTACT2D, NodeUpdateContact2D)
+{
+    URHO3D_PARAM(P_BODY, Body);                    // RigidBody2D pointer
+    URHO3D_PARAM(P_OTHERNODE, OtherNode);          // Node pointer
+    URHO3D_PARAM(P_OTHERBODY, OtherBody);          // RigidBody2D pointer
+    URHO3D_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+    URHO3D_PARAM(P_CONTACTPOINTS, ContactPoints);  // Buffer containing position (Vector2), normal (Vector2), negative overlap distance (float). Normal is the same for all points.
+    URHO3D_PARAM(P_SHAPE, Shape);                  // CollisionShape2D pointer
+    URHO3D_PARAM(P_OTHERSHAPE, OtherShape);        // CollisionShape2D pointer
+    URHO3D_PARAM(P_ENABLED, Enabled);              // bool [in/out]
+}
+
 /// Node begin contact. Sent by scene nodes participating in a collision.
 URHO3D_EVENT(E_NODEBEGINCONTACT2D, NodeBeginContact2D)
 {
@@ -64,6 +94,7 @@ URHO3D_EVENT(E_NODEBEGINCONTACT2D, NodeBeginContact2D)
     URHO3D_PARAM(P_OTHERNODE, OtherNode);          // Node pointer
     URHO3D_PARAM(P_OTHERBODY, OtherBody);          // RigidBody2D pointer
     URHO3D_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+    URHO3D_PARAM(P_CONTACTPOINTS, ContactPoints);  // Buffer containing position (Vector2), normal (Vector2), negative overlap distance (float). Normal is the same for all points.
     URHO3D_PARAM(P_SHAPE, Shape);                  // CollisionShape2D pointer
     URHO3D_PARAM(P_OTHERSHAPE, OtherShape);        // CollisionShape2D pointer
 }
@@ -75,6 +106,7 @@ URHO3D_EVENT(E_NODEENDCONTACT2D, NodeEndContact2D)
     URHO3D_PARAM(P_OTHERNODE, OtherNode);          // Node pointer
     URHO3D_PARAM(P_OTHERBODY, OtherBody);          // RigidBody2D pointer
     URHO3D_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+    URHO3D_PARAM(P_CONTACTPOINTS, ContactPoints);  // Buffer containing position (Vector2), normal (Vector2), negative overlap distance (float). Normal is the same for all points.
     URHO3D_PARAM(P_SHAPE, Shape);                  // CollisionShape2D pointer
     URHO3D_PARAM(P_OTHERSHAPE, OtherShape);        // CollisionShape2D pointer
 }

+ 80 - 4
Source/Urho3D/Urho2D/PhysicsWorld2D.cpp

@@ -46,6 +46,21 @@ static const Vector2 DEFAULT_GRAVITY(0.0f, -9.81f);
 static const int DEFAULT_VELOCITY_ITERATIONS = 8;
 static const int DEFAULT_POSITION_ITERATIONS = 3;
 
+// Helper function to write contact info into buffer.
+const PODVector<unsigned char>& WriteContactInfo(VectorBuffer& buffer, b2Contact* contact)
+{
+    buffer.Clear();
+    b2WorldManifold worldManifold;
+    contact->GetWorldManifold(&worldManifold);
+    for (int i = 0; i < contact->GetManifold()->pointCount; ++i)
+    {
+        buffer.WriteVector2(Vector2(worldManifold.points[i].x, worldManifold.points[i].y));
+        buffer.WriteVector2(Vector2(worldManifold.normal.x, worldManifold.normal.y));
+        buffer.WriteFloat(worldManifold.separations[i]);
+    }
+    return buffer.GetBuffer();
+}
+
 PhysicsWorld2D::PhysicsWorld2D(Context* context) :
     Component(context),
     gravity_(DEFAULT_GRAVITY),
@@ -135,6 +150,63 @@ void PhysicsWorld2D::EndContact(b2Contact* contact)
     endContactInfos_.Push(ContactInfo(contact));
 }
 
+void PhysicsWorld2D::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
+{
+    b2Fixture* fixtureA = contact->GetFixtureA();
+    b2Fixture* fixtureB = contact->GetFixtureB();
+    if (!fixtureA || !fixtureB)
+        return;
+
+    ContactInfo contactInfo(contact);
+
+    // Send global event
+    VariantMap& eventData = GetEventDataMap();
+    eventData[PhysicsUpdateContact2D::P_WORLD] = this;
+    eventData[PhysicsUpdateContact2D::P_ENABLED] = contact->IsEnabled();
+
+    eventData[PhysicsUpdateContact2D::P_BODYA] = contactInfo.bodyA_.Get();
+    eventData[PhysicsUpdateContact2D::P_BODYB] = contactInfo.bodyB_.Get();
+    eventData[PhysicsUpdateContact2D::P_NODEA] = contactInfo.nodeA_.Get();
+    eventData[PhysicsUpdateContact2D::P_NODEB] = contactInfo.nodeB_.Get();
+    eventData[PhysicsUpdateContact2D::P_CONTACT] = (void*)contactInfo.contact_;
+    eventData[PhysicsUpdateContact2D::P_CONTACTPOINTS] = WriteContactInfo(contacts_, contactInfo.contact_);
+    eventData[PhysicsUpdateContact2D::P_SHAPEA] = contactInfo.shapeA_.Get();
+    eventData[PhysicsUpdateContact2D::P_SHAPEB] = contactInfo.shapeB_.Get();
+
+    SendEvent(E_PHYSICSUPDATECONTACT2D, eventData);
+    contact->SetEnabled(eventData[PhysicsUpdateContact2D::P_ENABLED].GetBool());
+    eventData.Clear();
+
+    // Send node event
+    eventData[NodeUpdateContact2D::P_ENABLED] = contact->IsEnabled();
+    eventData[NodeUpdateContact2D::P_CONTACT] = (void*)contactInfo.contact_;
+    eventData[NodeUpdateContact2D::P_CONTACTPOINTS] = WriteContactInfo(contacts_, contactInfo.contact_);
+
+    if (contactInfo.nodeA_)
+    {
+        eventData[NodeUpdateContact2D::P_BODY] = contactInfo.bodyA_.Get();
+        eventData[NodeUpdateContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
+        eventData[NodeUpdateContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
+        eventData[NodeUpdateContact2D::P_SHAPE] = contactInfo.shapeA_.Get();
+        eventData[NodeUpdateContact2D::P_OTHERSHAPE] = contactInfo.shapeB_.Get();
+
+        contactInfo.nodeA_->SendEvent(E_NODEUPDATECONTACT2D, eventData);
+    }
+
+    if (contactInfo.nodeB_)
+    {
+        eventData[NodeUpdateContact2D::P_BODY] = contactInfo.bodyB_.Get();
+        eventData[NodeUpdateContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
+        eventData[NodeUpdateContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
+        eventData[NodeUpdateContact2D::P_SHAPE] = contactInfo.shapeB_.Get();
+        eventData[NodeUpdateContact2D::P_OTHERSHAPE] = contactInfo.shapeA_.Get();
+
+        contactInfo.nodeB_->SendEvent(E_NODEUPDATECONTACT2D, eventData);
+    }
+
+    contact->SetEnabled(eventData[NodeUpdateContact2D::P_ENABLED].GetBool());
+}
+
 void PhysicsWorld2D::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
 {
     if (!debugRenderer_)
@@ -687,12 +759,14 @@ void PhysicsWorld2D::SendBeginContactEvents()
         eventData[P_NODEA] = contactInfo.nodeA_.Get();
         eventData[P_NODEB] = contactInfo.nodeB_.Get();
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
+        eventData[P_CONTACTPOINTS] = WriteContactInfo(contacts_, contactInfo.contact_);
         eventData[P_SHAPEA] = contactInfo.shapeA_.Get();
         eventData[P_SHAPEB] = contactInfo.shapeB_.Get();
 
         SendEvent(E_PHYSICSBEGINCONTACT2D, eventData);
 
         nodeEventData[NodeBeginContact2D::P_CONTACT] = (void*)contactInfo.contact_;
+        nodeEventData[NodeBeginContact2D::P_CONTACTPOINTS] = WriteContactInfo(contacts_, contactInfo.contact_);
 
         if (contactInfo.nodeA_)
         {
@@ -738,20 +812,22 @@ void PhysicsWorld2D::SendEndContactEvents()
         eventData[P_NODEA] = contactInfo.nodeA_.Get();
         eventData[P_NODEB] = contactInfo.nodeB_.Get();
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
+        eventData[P_CONTACTPOINTS] = WriteContactInfo(contacts_, contactInfo.contact_);
         eventData[P_SHAPEA] = contactInfo.shapeA_.Get();
         eventData[P_SHAPEB] = contactInfo.shapeB_.Get();
 
         SendEvent(E_PHYSICSENDCONTACT2D, eventData);
 
         nodeEventData[NodeEndContact2D::P_CONTACT] = (void*)contactInfo.contact_;
+        nodeEventData[NodeEndContact2D::P_CONTACTPOINTS] = WriteContactInfo(contacts_, contactInfo.contact_);
 
         if (contactInfo.nodeA_)
         {
             nodeEventData[NodeEndContact2D::P_BODY] = contactInfo.bodyA_.Get();
             nodeEventData[NodeEndContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
             nodeEventData[NodeEndContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
-            nodeEventData[NodeBeginContact2D::P_SHAPE] = contactInfo.shapeA_.Get();
-            nodeEventData[NodeBeginContact2D::P_OTHERSHAPE] = contactInfo.shapeB_.Get();
+            nodeEventData[NodeEndContact2D::P_SHAPE] = contactInfo.shapeA_.Get();
+            nodeEventData[NodeEndContact2D::P_OTHERSHAPE] = contactInfo.shapeB_.Get();
 
             contactInfo.nodeA_->SendEvent(E_NODEENDCONTACT2D, nodeEventData);
         }
@@ -761,8 +837,8 @@ void PhysicsWorld2D::SendEndContactEvents()
             nodeEventData[NodeEndContact2D::P_BODY] = contactInfo.bodyB_.Get();
             nodeEventData[NodeEndContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
             nodeEventData[NodeEndContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
-            nodeEventData[NodeBeginContact2D::P_SHAPE] = contactInfo.shapeB_.Get();
-            nodeEventData[NodeBeginContact2D::P_OTHERSHAPE] = contactInfo.shapeA_.Get();
+            nodeEventData[NodeEndContact2D::P_SHAPE] = contactInfo.shapeB_.Get();
+            nodeEventData[NodeEndContact2D::P_OTHERSHAPE] = contactInfo.shapeA_.Get();
 
             contactInfo.nodeB_->SendEvent(E_NODEENDCONTACT2D, nodeEventData);
         }

+ 5 - 0
Source/Urho3D/Urho2D/PhysicsWorld2D.h

@@ -23,6 +23,7 @@
 #pragma once
 
 #include "../Scene/Component.h"
+#include "../IO/VectorBuffer.h"
 
 #include <Box2D/Box2D.h>
 
@@ -92,6 +93,8 @@ public:
     virtual void BeginContact(b2Contact* contact);
     /// Called when two fixtures cease to touch.
     virtual void EndContact(b2Contact* contact);
+    /// Called when contact is updated.
+    virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
 
     // Implement b2Draw
     /// Draw a closed polygon provided in CCW order.
@@ -275,6 +278,8 @@ protected:
     Vector<ContactInfo> beginContactInfos_;
     /// End contact infos.
     Vector<ContactInfo> endContactInfos_;
+    /// Temporary buffer with contact data.
+    VectorBuffer contacts_;
 };
 
 }