Selaa lähdekoodia

Apply node transform to collision shape, add CollisionCircle2D.[ci skip]

aster2013 11 vuotta sitten
vanhempi
sitoutus
b9940bdac1

+ 31 - 5
Source/Engine/Urho2D/CollisionBox2D.cpp

@@ -35,9 +35,12 @@ static const Vector2 DEFAULT_BOX_SIZE(0.01f, 0.01f);
 
 CollisionBox2D::CollisionBox2D(Context* context) : CollisionShape2D(context),
     size_(DEFAULT_BOX_SIZE),
-    center_(Vector2::ZERO)
+    center_(Vector2::ZERO),
+    angle_(0.0f)
 {
-    boxShape_.SetAsBox(size_.x_ * 0.5f, size_.y_ * 0.5f);
+    float halfWidth = size_.x_ * 0.5f * cachedWorldScale_.x_;
+    float halfHeight = size_.y_ * 0.5f * cachedWorldScale_.y_;
+    boxShape_.SetAsBox(halfWidth, halfHeight);
     fixtureDef_.shape = &boxShape_;
 }
 
@@ -52,6 +55,7 @@ void CollisionBox2D::RegisterObject(Context* context)
 
     REF_ACCESSOR_ATTRIBUTE(CollisionBox2D, VAR_VECTOR2, "Size", GetSize, SetSize, Vector2, DEFAULT_BOX_SIZE, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(CollisionBox2D, VAR_VECTOR2, "Center", GetCenter, SetCenter, Vector2, Vector2::ZERO, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(CollisionBox2D, VAR_FLOAT, "Angle", GetAngle, SetAngle, float, 0.0f, AM_DEFAULT);
 
     COPY_BASE_ATTRIBUTES(CollisionBox2D, CollisionShape2D);
 }
@@ -88,14 +92,36 @@ void CollisionBox2D::SetCenter(float x, float y)
     SetCenter(Vector2(x, y));
 }
 
+void CollisionBox2D::SetAngle(float angle)
+{
+    if (angle == angle_)
+        return;
+
+    angle_ = angle;
+
+    MarkNetworkUpdate();
+    RecreateFixture();
+}
+
+void CollisionBox2D::ApplyNodeWorldScale()
+{
+    RecreateFixture();
+}
+
 void CollisionBox2D::RecreateFixture()
 {
     ReleaseFixture();
 
-    if (center_ == Vector2::ZERO)
-        boxShape_.SetAsBox(size_.x_ * 0.5f, size_.y_ * 0.5f);
+    float worlsScaleX = cachedWorldScale_.x_;
+    float worldScaleY = cachedWorldScale_.y_;
+    float halfWidth = size_.x_ * 0.5f * worlsScaleX;
+    float halfHeight = size_.y_ * 0.5f * worldScaleY;
+    Vector2 scaledCenter = center_ * Vector2(worlsScaleX, worldScaleY);
+
+    if (scaledCenter == Vector2::ZERO && angle_ == 0.0f)
+        boxShape_.SetAsBox(halfWidth, halfHeight);
     else
-        boxShape_.SetAsBox(size_.x_ * 0.5f, size_.y_ * 0.5f, ToB2Vec2(center_), 0.0f);
+        boxShape_.SetAsBox(halfWidth, halfHeight, ToB2Vec2(scaledCenter), angle_);
 
     CreateFixture();
 }

+ 8 - 0
Source/Engine/Urho2D/CollisionBox2D.h

@@ -48,13 +48,19 @@ public:
     void SetCenter(const Vector2& center);
     /// Set center.
     void SetCenter(float x, float y);
+    /// Set angle.
+    void SetAngle(float angle);
 
     /// Return size.
     const Vector2& GetSize() const { return size_; }
     /// Return center.
     const Vector2& GetCenter() const { return center_; }
+    /// Return angle.
+    float GetAngle() const { return angle_; }
 
 private:
+    /// Apply node world scale.
+    virtual void ApplyNodeWorldScale();
     /// Recreate fixture.
     void RecreateFixture();
 
@@ -64,6 +70,8 @@ private:
     Vector2 size_;
     /// Center
     Vector2 center_;
+    /// Angle.
+    float angle_;
 };
 
 }

+ 101 - 0
Source/Engine/Urho2D/CollisionCircle2D.cpp

@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "CollisionCircle2D.h"
+#include "PhysicsUtils2D.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+extern const char* URHO2D_CATEGORY;
+static const float DEFAULT_CLRCLE_RADIUS(0.01f);
+
+CollisionCircle2D::CollisionCircle2D(Context* context) : CollisionShape2D(context),
+    center_(0.0f, 0.0f)
+{
+    circleShape_.m_radius = DEFAULT_CLRCLE_RADIUS * cachedWorldScale_.x_;
+    fixtureDef_.shape = &circleShape_;
+}
+
+CollisionCircle2D::~CollisionCircle2D()
+{
+
+}
+
+void CollisionCircle2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<CollisionCircle2D>(URHO2D_CATEGORY);
+
+    ACCESSOR_ATTRIBUTE(CollisionCircle2D, VAR_FLOAT, "Radius", GetRadius, SetRadius, float, DEFAULT_CLRCLE_RADIUS, AM_DEFAULT);
+    REF_ACCESSOR_ATTRIBUTE(CollisionCircle2D, VAR_VECTOR2, "Center", GetCenter, SetCenter, Vector2, Vector2::ZERO, AM_DEFAULT);
+    COPY_BASE_ATTRIBUTES(CollisionCircle2D, CollisionShape2D);
+}
+
+void CollisionCircle2D::SetRadius(float radius)
+{
+    if (radius == radius_)
+        return;
+
+    radius_ = radius;
+
+    RecreateFixture();
+    MarkNetworkUpdate();
+}
+
+void CollisionCircle2D::SetCenter(const Vector2& center)
+{
+    if (center == center_)
+        return;
+
+    center_ = center;
+
+    RecreateFixture();
+    MarkNetworkUpdate();
+}
+
+void CollisionCircle2D::SetCenter(float x, float y)
+{
+    SetCenter(Vector2(x, y));
+}
+
+void CollisionCircle2D::ApplyNodeWorldScale()
+{
+    RecreateFixture();
+}
+
+void CollisionCircle2D::RecreateFixture()
+{
+    ReleaseFixture();
+    
+    // Only use scale in x axis for circle
+    float worldScale = cachedWorldScale_.x_;
+    circleShape_.m_radius = radius_* worldScale;
+    circleShape_.m_p = ToB2Vec2(center_ * worldScale);
+
+    CreateFixture();
+}
+
+}

+ 69 - 0
Source/Engine/Urho2D/CollisionCircle2D.h

@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "CollisionShape2D.h"
+
+namespace Urho3D
+{
+
+/// 2D circle collision component.
+class URHO3D_API CollisionCircle2D : public CollisionShape2D
+{
+    OBJECT(CollisionCircle2D);
+
+public:
+    /// Construct.
+    CollisionCircle2D(Context* scontext);
+    /// Destruct.
+    virtual ~CollisionCircle2D();
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+
+    /// Set radius.
+    void SetRadius(float radius);
+    /// Set center.
+    void SetCenter(const Vector2& center);
+    /// Set center.
+    void SetCenter(float x, float y);
+
+    /// Return radius.
+    float GetRadius() const { return radius_; }
+    /// Return center.
+    const Vector2& GetCenter() const { return center_; }
+
+private:
+    /// Apply node world scale.
+    virtual void ApplyNodeWorldScale();
+    /// Recreate fixture.
+    void RecreateFixture();
+
+    /// Circle shape.
+    b2CircleShape circleShape_;
+    /// Radius.
+    float radius_;
+    /// Center.
+    Vector2 center_;
+};
+
+}

+ 25 - 1
Source/Engine/Urho2D/CollisionShape2D.cpp

@@ -27,6 +27,7 @@
 #include "Node.h"
 #include "PhysicsUtils2D.h"
 #include "RigidBody2D.h"
+#include "Scene.h"
 
 #include "DebugNew.h"
 
@@ -36,7 +37,8 @@ namespace Urho3D
 extern const char* URHO2D_CATEGORY;
 
 CollisionShape2D::CollisionShape2D(Context* context) : Component(context), 
-    fixture_(0)
+    fixture_(0),
+    cachedWorldScale_(Vector3::ONE)
 {
 
 }
@@ -286,4 +288,26 @@ void CollisionShape2D::OnNodeSet(Node* node)
     }
 }
 
+void CollisionShape2D::OnMarkedDirty(Node* node)
+{
+    Vector3 newWorldScale = node_->GetWorldScale();
+
+    Vector3 delta = newWorldScale - cachedWorldScale_;
+    if (delta.DotProduct(delta) < 0.01f)
+        return;
+
+    // Physics operations are not safe from worker threads
+    Scene* scene = GetScene();
+    if (scene && scene->IsThreadedUpdate())
+    {
+        scene->DelayedMarkedDirty(this);
+        return;
+    }
+    
+    cachedWorldScale_ = newWorldScale;
+
+    if (fixture_)
+        ApplyNodeWorldScale();
+}
+
 }

+ 6 - 0
Source/Engine/Urho2D/CollisionShape2D.h

@@ -93,6 +93,10 @@ public:
 protected:
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
+    /// Handle node transform being dirtied.
+    virtual void OnMarkedDirty(Node* node);
+    /// Apply Node world scale.
+    virtual void ApplyNodeWorldScale() = 0;
     
     /// Rigid body.
     WeakPtr<RigidBody2D> rigidBody_;
@@ -100,6 +104,8 @@ protected:
     b2FixtureDef fixtureDef_;
     /// Box2D fixture.
     b2Fixture* fixture_;
+    /// Cached world scale.
+    Vector3 cachedWorldScale_;
 };
 
 }

+ 4 - 7
Source/Engine/Urho2D/PhysicsWorld2D.cpp

@@ -48,7 +48,6 @@ PhysicsWorld2D::PhysicsWorld2D(Context* context) : Component(context),
     applyingTransforms_(false)
 {
     // Set default debug draw flags
-    // m_drawFlags = e_shapeBit | e_jointBit | e_centerOfMassBit;
     m_drawFlags = e_shapeBit;
 
     // Create Box2D world
@@ -178,9 +177,9 @@ void PhysicsWorld2D::DrawCircle(const b2Vec2& center, float32 radius, const b2Co
 
     Vector3 p = ToVector3(center);
     Color c = ToColor(color);
-    for (unsigned i = 0; i < 360; i += 45)
+    for (unsigned i = 0; i < 360; i += 30)
     {
-        unsigned j = i + 45;
+        unsigned j = i + 30;
         float x1 = radius * Cos((float)i);
         float y1 = radius * Sin((float)i);
         float x2 = radius * Cos((float)j);
@@ -198,9 +197,9 @@ void PhysicsWorld2D::DrawSolidCircle(const b2Vec2& center, float32 radius, const
     Vector3 p = ToVector3(center);
     Color c(color.r, color.g, color.b, 0.5f);
 
-    for (unsigned i = 0; i < 360; i += 45)
+    for (unsigned i = 0; i < 360; i += 30)
     {
-        unsigned j = i + 45;
+        unsigned j = i + 30;
         float x1 = radius * Cos((float)i);
         float y1 = radius * Sin((float)i);
         float x2 = radius * Cos((float)j);
@@ -409,8 +408,6 @@ void PhysicsWorld2D::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap
 {
     using namespace SceneSubsystemUpdate;
     Update(eventData[P_TIMESTEP].GetFloat());
-
-    DrawDebugGeometry();
 }
 
 }

+ 4 - 2
Source/Engine/Urho2D/RigidBody2D.cpp

@@ -447,11 +447,13 @@ void RigidBody2D::OnMarkedDirty(Node* node)
 
     // Check if transform has changed from the last one set in ApplyWorldTransform()
     b2Vec2 newPosition = ToB2Vec2(node_->GetWorldPosition());
-    if (bodyDef_.position != newPosition)
+    float newAngle = node->GetWorldRotation().RollAngle() * M_DEGTORAD;
+    if (newPosition != bodyDef_.position || newAngle != bodyDef_.angle)
     {
         bodyDef_.position = newPosition;
+        bodyDef_.angle = newAngle;
         if (body_)
-            body_->SetTransform(newPosition, 0.0f);
+            body_->SetTransform(newPosition, newAngle);
     }
 }
 

+ 2 - 0
Source/Engine/Urho2D/Urho2D.cpp

@@ -24,6 +24,7 @@
 #include "AnimatedSprite2D.h"
 #include "Animation2D.h"
 #include "CollisionBox2D.h"
+#include "CollisionCircle2D.h"
 #include "CollisionShape2D.h"
 #include "Drawable2D.h"
 #include "ParticleEmitter2D.h"
@@ -57,6 +58,7 @@ void RegisterUrho2DLibrary(Context* context)
     RigidBody2D::RegisterObject(context);
     CollisionShape2D::RegisterObject(context);
     CollisionBox2D::RegisterObject(context);
+    CollisionCircle2D::RegisterObject(context);
 }
 
 }

+ 59 - 36
Source/Samples/27_Urho2DPhysics/Urho2DPhysics.cpp

@@ -22,8 +22,10 @@
 
 #include "Camera.h"
 #include "CollisionBox2D.h"
+#include "CollisionCircle2D.h"
 #include "CoreEvents.h"
 #include "DebugRenderer.h"
+#include "Drawable2D.h"
 #include "Engine.h"
 #include "Font.h"
 #include "Graphics.h"
@@ -31,21 +33,19 @@
 #include "Octree.h"
 #include "PhysicsWorld2D.h"
 #include "Renderer.h"
-#include "ResourceCache.h"
 #include "RigidBody2D.h"
 #include "Scene.h"
-#include "Sprite2D.h"
-#include "StaticSprite2D.h"
+#include "SceneEvents.h"
 #include "Text.h"
 #include "Urho2DPhysics.h"
-#include "Zone.h"
 
 #include "DebugNew.h"
 
 DEFINE_APPLICATION_MAIN(Urho2DPhysics)
 
-Urho2DPhysics::Urho2DPhysics(Context* context) :
-Sample(context)
+static const unsigned NUM_OBJECT = 100;
+
+Urho2DPhysics::Urho2DPhysics(Context* context) : Sample(context)
 {    
 }
 
@@ -76,7 +76,7 @@ void Urho2DPhysics::CreateScene()
     cameraNode_ = scene_->CreateChild("Camera");
     // Set camera's position
     cameraNode_->SetPosition(Vector3(0.0f, 0.0f, -10.0f));
-
+    
     Camera* camera = cameraNode_->CreateComponent<Camera>();
     camera->SetOrthographic(true);
 
@@ -85,47 +85,61 @@ void Urho2DPhysics::CreateScene()
     float height = (float)graphics->GetHeight();
     camera->SetOrthoSize(Vector2(width, height) * PIXEL_SIZE);
 
+    // Create 2D physics world component
     PhysicsWorld2D* physicsWorld = scene_->CreateComponent<PhysicsWorld2D>();
     // Define the gravity vector.
     physicsWorld->SetGravity(Vector2(0.0f, -10.0f));
-    
-
-    ResourceCache* cache = GetSubsystem<ResourceCache>();
-    // Get sprite
-    Sprite2D* sprite = cache->GetResource<Sprite2D>("Urho2D/Box.png");
-    if (!sprite)
-        return;
 
     // Create ground.
     Node* groundNode = scene_->CreateChild("Ground");
     groundNode->SetPosition(Vector3(0.0f, -3.0f, 0.0f));
+    groundNode->SetScale(Vector3(200.0f, 1.0f, 0.0f));
+    
+    // Create 2D rigid body for gound
     RigidBody2D* groundBody = groundNode->CreateComponent<RigidBody2D>();
-
+    
+    // Create box collider for ground
     CollisionBox2D* groundShape = groundNode->CreateComponent<CollisionBox2D>();
-    groundShape->SetSize(Vector2(20.0f, 0.1f));
+    // Set box size
+    groundShape->SetSize(Vector2(0.1f, 0.1f));
+    // Set friction
     groundShape->SetFriction(0.5f);
 
-    for (unsigned i = 0; i < 100; ++i)
+    for (unsigned i = 0; i < NUM_OBJECT; ++i)
     {
-        // Create a box.
-        Node* boxNode  = scene_->CreateChild("Box");
-        boxNode->SetPosition(Vector3(Random(-0.1f, 0.1f), 5.0f + i * 0.4f, 0.0f));
-
-        RigidBody2D* boxBody = boxNode->CreateComponent<RigidBody2D>();
-        boxBody->SetBodyType(BT_DYNAMIC);
-
-        CollisionBox2D* boxShape = boxNode->CreateComponent<CollisionBox2D>();
-        boxShape->SetSize(Vector2(0.32f, 0.32f));
-        // Set the box density to be non-zero, so it will be dynamic.
-        boxShape->SetDensity(1.0f);
-        // Override the default friction.
-        boxShape->SetFriction(0.5f);
-        boxShape->SetRestitution(0.1f);
-
-        // Create static sprite.
-        StaticSprite2D* staticSprite = boxNode->CreateComponent<StaticSprite2D>();
-        // Set sprite
-        staticSprite->SetSprite(sprite);
+        Node* node  = scene_->CreateChild("RigidBody");
+        node->SetPosition(Vector3(Random(-0.1f, 0.1f), 5.0f + i * 0.4f, 0.0f));
+
+        // Create rigid body
+        RigidBody2D* body = node->CreateComponent<RigidBody2D>();
+        body->SetBodyType(BT_DYNAMIC);
+
+        if (i % 2 == 0)
+        {
+            // Create box
+            CollisionBox2D* box = node->CreateComponent<CollisionBox2D>();
+            // Set size
+            box->SetSize(Vector2(0.32f, 0.32f));
+            // Set density
+            box->SetDensity(1.0f);
+            // Set friction
+            box->SetFriction(0.5f);
+            // Set restitution
+            box->SetRestitution(0.1f);
+        }
+        else
+        {
+            // Create circle
+            CollisionCircle2D* circle = node->CreateComponent<CollisionCircle2D>();
+            // Set radius
+            circle->SetRadius(0.16f);
+            // Set density
+            circle->SetDensity(1.0f);
+            // Set friction.
+            circle->SetFriction(0.5f);
+            // Set restitution
+            circle->SetRestitution(0.1f);
+        }
     }
 }
 
@@ -194,6 +208,8 @@ void Urho2DPhysics::SubscribeToEvents()
 {
     // Subscribe HandleUpdate() function for processing update events
     SubscribeToEvent(E_UPDATE, HANDLER(Urho2DPhysics, HandleUpdate));
+
+    SubscribeToEvent(E_SCENEPOSTUPDATE, HANDLER(Urho2DPhysics, HandleScenePostUpdate));
 }
 
 void Urho2DPhysics::HandleUpdate(StringHash eventType, VariantMap& eventData)
@@ -206,3 +222,10 @@ void Urho2DPhysics::HandleUpdate(StringHash eventType, VariantMap& eventData)
     // Move the camera, scale movement with time step
     MoveCamera(timeStep);
 }
+
+void Urho2DPhysics::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
+{
+    PhysicsWorld2D* physicWorld = scene_->GetComponent<PhysicsWorld2D>();
+    physicWorld->DrawDebugGeometry();
+}
+

+ 5 - 0
Source/Samples/27_Urho2DPhysics/Urho2DPhysics.h

@@ -31,6 +31,9 @@ namespace Urho3D
 }
 
 /// Urho2D physics sample.
+/// This sample demonstrates:
+///     - Creating both static and moving 2D physics objects to a scene
+///     - Displaying physics debug geometry
 class Urho2DPhysics : public Sample
 {
     OBJECT(Urho2DPhysics);
@@ -55,6 +58,8 @@ private:
     void SubscribeToEvents();
     /// Handle the logic update event.
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
+    /// Handle scene post update event.
+    void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
 
     /// Scene.
     SharedPtr<Scene> scene_;