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

This commit is contained in:
aster2013 2014-03-13 22:03:38 +08:00
parent f9ff9550bd
commit b9940bdac1
11 changed files with 312 additions and 49 deletions

View File

@ -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();
}

View File

@ -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_;
};
}

View File

@ -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();
}
}

View File

@ -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_;
};
}

View File

@ -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();
}
}

View File

@ -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_;
};
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
Node* node = scene_->CreateChild("RigidBody");
node->SetPosition(Vector3(Random(-0.1f, 0.1f), 5.0f + i * 0.4f, 0.0f));
RigidBody2D* boxBody = boxNode->CreateComponent<RigidBody2D>();
boxBody->SetBodyType(BT_DYNAMIC);
// Create rigid body
RigidBody2D* body = node->CreateComponent<RigidBody2D>();
body->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);
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();
}

View File

@ -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_;