diff --git a/projects/kiwano-physics/kiwano-physics.vcxproj b/projects/kiwano-physics/kiwano-physics.vcxproj index d4888d5b..29ea6605 100644 --- a/projects/kiwano-physics/kiwano-physics.vcxproj +++ b/projects/kiwano-physics/kiwano-physics.vcxproj @@ -11,24 +11,25 @@ - + - + - + - + + - + {DF599AFB-744F-41E5-AF0C-2146F90575C8} diff --git a/projects/kiwano-physics/kiwano-physics.vcxproj.filters b/projects/kiwano-physics/kiwano-physics.vcxproj.filters index df3e5d6d..6638c59c 100644 --- a/projects/kiwano-physics/kiwano-physics.vcxproj.filters +++ b/projects/kiwano-physics/kiwano-physics.vcxproj.filters @@ -2,22 +2,23 @@ - - - + + + - - + + + \ No newline at end of file diff --git a/src/kiwano-physics/Body.cpp b/src/kiwano-physics/Body.cpp deleted file mode 100644 index 50f43465..00000000 --- a/src/kiwano-physics/Body.cpp +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) 2018-2019 Kiwano - Nomango -// -// 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 -#include - -namespace kiwano -{ -namespace physics -{ - -BodyPtr Body::Create(World* world, Actor* actor, Type type) -{ - BodyPtr ptr = new (std::nothrow) Body; - if (ptr) - { - if (!ptr->InitBody(world, actor)) - return nullptr; - - ptr->SetType(type); - } - return ptr; -} - -Body::Body() - : body_(nullptr) - , actor_(nullptr) - , world_(nullptr) - , category_bits_(0x0001) - , mask_bits_(0xFFFF) - , group_index_(0) -{ -} - -Body::~Body() -{ - Destroy(); -} - -bool Body::InitBody(World* world, Actor* actor) -{ - KGE_ASSERT(world); - - Destroy(); - - world_ = world; - b2BodyDef def; - b2Body* b2body = world->GetB2World()->CreateBody(&def); - - if (b2body) - { - SetB2Body(b2body); - SetActor(actor); - UpdateFromActor(); - return true; - } - return false; -} - -void Body::AddFixture(FixturePtr fixture) -{ - fixtures_.push_back(fixture); -} - -Fixture* Body::AddCircleShape(float radius, float density, float friction, float restitution, bool is_sensor) -{ - Fixture::Param param(density, friction, restitution, is_sensor); - FixturePtr fixture = Fixture::CreateCircle(this, param, radius); - AddFixture(fixture); - return fixture.Get(); -} - -Fixture* Body::AddRectShape(Vec2 const& size, float density, float friction, float restitution, bool is_sensor) -{ - Fixture::Param param(density, friction, restitution, is_sensor); - FixturePtr fixture = Fixture::CreateRect(this, param, size); - AddFixture(fixture); - return fixture.Get(); -} - -Fixture* Body::AddPolygonShape(Vector const& vertexs, float density, float friction, float restitution, - bool is_sensor) -{ - Fixture::Param param(density, friction, restitution, is_sensor); - FixturePtr fixture = Fixture::CreatePolygon(this, param, vertexs); - AddFixture(fixture); - return fixture.Get(); -} - -Fixture* Body::AddEdgeShape(Point const& p1, Point const& p2, float density, float friction, float restitution, - bool is_sensor) -{ - Fixture::Param param(density, friction, restitution, is_sensor); - FixturePtr fixture = Fixture::CreateEdge(this, param, p1, p2); - AddFixture(fixture); - return fixture.Get(); -} - -Fixture* Body::AddChainShape(Vector const& vertexs, bool loop, float density, float friction, float restitution, - bool is_sensor) -{ - Fixture::Param param(density, friction, restitution, is_sensor); - FixturePtr fixture = Fixture::CreateChain(this, param, vertexs, loop); - AddFixture(fixture); - return fixture.Get(); -} - -void Body::RemoveFixture(FixturePtr fixture) -{ - if (fixture) - { - body_->DestroyFixture(fixture->GetB2Fixture()); - - for (auto iter = fixtures_.begin(); iter != fixtures_.end();) - { - if (*iter == fixture) - iter = fixtures_.erase(iter); - else - ++iter; - } - } -} - -void Body::SetCategoryBits(uint16_t category_bits) -{ - KGE_ASSERT(body_); - - if (category_bits != category_bits_) - { - category_bits_ = category_bits; - - b2Fixture* fixture = body_->GetFixtureList(); - while (fixture) - { - UpdateFixtureFilter(fixture); - fixture = fixture->GetNext(); - } - } -} - -void Body::SetMaskBits(uint16_t mask_bits) -{ - KGE_ASSERT(body_); - - if (mask_bits != mask_bits_) - { - mask_bits_ = mask_bits; - - b2Fixture* fixture = body_->GetFixtureList(); - while (fixture) - { - UpdateFixtureFilter(fixture); - fixture = fixture->GetNext(); - } - } -} - -void Body::SetGroupIndex(int16_t index) -{ - KGE_ASSERT(body_); - - if (index != group_index_) - { - group_index_ = index; - - b2Fixture* fixture = body_->GetFixtureList(); - while (fixture) - { - UpdateFixtureFilter(fixture); - fixture = fixture->GetNext(); - } - } -} - -void Body::GetMassData(float* mass, Point* center, float* inertia) const -{ - KGE_ASSERT(body_ && world_); - - b2MassData data; - body_->GetMassData(&data); - - if (mass) - *mass = data.mass; - if (center) - *center = world_->World2Stage(data.center); - if (inertia) - *inertia = data.I; -} - -void Body::SetMassData(float mass, Point const& center, float inertia) -{ - KGE_ASSERT(body_ && world_); - - b2MassData data; - data.mass = mass; - data.center = world_->Stage2World(center); - data.I = inertia; - body_->SetMassData(&data); -} - -void Body::ResetMassData() -{ - KGE_ASSERT(body_); - body_->ResetMassData(); -} - -Point Body::GetBodyPosition() const -{ - KGE_ASSERT(body_ && world_); - return world_->World2Stage(body_->GetPosition()); -} - -void Body::SetBodyTransform(Point const& pos, float angle) -{ - KGE_ASSERT(body_ && world_); - body_->SetTransform(world_->Stage2World(pos), math::Degree2Radian(angle)); -} - -Point Body::GetLocalPoint(Point const& world) const -{ - KGE_ASSERT(body_ && world_); - return world_->World2Stage(body_->GetLocalPoint(world_->Stage2World(world))); -} - -Point Body::GetWorldPoint(Point const& local) const -{ - KGE_ASSERT(body_ && world_); - return world_->World2Stage(body_->GetWorldPoint(world_->Stage2World(local))); -} - -Point Body::GetLocalCenter() const -{ - KGE_ASSERT(body_ && world_); - return world_->World2Stage(body_->GetLocalCenter()); -} - -Point Body::GetWorldCenter() const -{ - KGE_ASSERT(body_ && world_); - return world_->World2Stage(body_->GetWorldCenter()); -} - -void Body::ApplyForce(Vec2 const& force, Point const& point, bool wake) -{ - KGE_ASSERT(body_ && world_); - body_->ApplyForce(b2Vec2(force.x, force.y), world_->Stage2World(point), wake); -} - -void Body::ApplyForceToCenter(Vec2 const& force, bool wake) -{ - KGE_ASSERT(body_ && world_); - body_->ApplyForceToCenter(b2Vec2(force.x, force.y), wake); -} - -void Body::ApplyTorque(float torque, bool wake) -{ - KGE_ASSERT(body_ && world_); - body_->ApplyTorque(torque, wake); -} - -void Body::SetB2Body(b2Body* body) -{ - body_ = body; - if (body_) - { - body_->SetUserData(this); - } -} - -void Body::Destroy() -{ - fixtures_.clear(); - - if (world_) - { - world_->RemoveBody(this); - } - - body_ = nullptr; - world_ = nullptr; - actor_ = nullptr; -} - -void Body::UpdateActor() -{ - if (actor_ && body_) - { - if (world_) - { - actor_->SetPosition(world_->World2Stage(body_->GetPosition())); - } - else - { - actor_->SetPosition(World2Stage(body_->GetPosition())); - } - actor_->SetRotation(math::Radian2Degree(body_->GetAngle())); - } -} - -void Body::UpdateFromActor() -{ - if (actor_ && body_) - { - if (world_) - { - body_->SetTransform(world_->Stage2World(actor_->GetPosition()), math::Degree2Radian(actor_->GetRotation())); - } - else - { - body_->SetTransform(Stage2World(actor_->GetPosition()), math::Degree2Radian(actor_->GetRotation())); - } - } -} - -void Body::UpdateFixtureFilter(b2Fixture* fixture) -{ - b2Filter filter; - filter.categoryBits = category_bits_; - filter.maskBits = mask_bits_; - filter.groupIndex = group_index_; - fixture->SetFilterData(filter); -} - -} // namespace physics -} // namespace kiwano diff --git a/src/kiwano-physics/Contact.cpp b/src/kiwano-physics/Contact.cpp index 072bb8c9..80e63a36 100644 --- a/src/kiwano-physics/Contact.cpp +++ b/src/kiwano-physics/Contact.cpp @@ -18,9 +18,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include +#include #include -#include +#include namespace kiwano { @@ -48,12 +48,12 @@ Fixture* Contact::GetFixtureB() const return fixture; } -Body* Contact::GetBodyA() const +PhysicBody* Contact::GetBodyA() const { return GetFixtureA()->GetBody(); } -Body* Contact::GetBodyB() const +PhysicBody* Contact::GetBodyB() const { return GetFixtureB()->GetBody(); } @@ -61,27 +61,13 @@ Body* Contact::GetBodyB() const void Contact::SetTangentSpeed(float speed) { KGE_ASSERT(contact_); - - Body* body = GetFixtureA()->GetBody(); - KGE_ASSERT(body); - - World* world = body->GetWorld(); - KGE_ASSERT(world); - - contact_->SetTangentSpeed(world->Stage2World(speed)); + contact_->SetTangentSpeed(global::ToMeters(speed)); } float Contact::GetTangentSpeed() const { KGE_ASSERT(contact_); - - const Body* body = GetFixtureA()->GetBody(); - KGE_ASSERT(body); - - const World* world = body->GetWorld(); - KGE_ASSERT(world); - - return world->World2Stage(contact_->GetTangentSpeed()); + return global::ToPixels(contact_->GetTangentSpeed()); } } // namespace physics diff --git a/src/kiwano-physics/Contact.h b/src/kiwano-physics/Contact.h index 5598cf57..41605438 100644 --- a/src/kiwano-physics/Contact.h +++ b/src/kiwano-physics/Contact.h @@ -20,13 +20,11 @@ #pragma once #include -#include namespace kiwano { namespace physics { -class Body; /** * \addtogroup Physics @@ -40,10 +38,6 @@ class KGE_API Contact public: Contact(); - /// \~chinese - /// @brief 是否有效 - bool IsValid() const; - /// \~chinese /// @brief 是否是接触 bool IsTouching() const; @@ -66,11 +60,11 @@ public: /// \~chinese /// @brief 获取物体A - Body* GetBodyA() const; + PhysicBody* GetBodyA() const; /// \~chinese /// @brief 获取物体B - Body* GetBodyB() const; + PhysicBody* GetBodyB() const; /// \~chinese /// @brief 设置摩擦力 @@ -104,8 +98,12 @@ public: /// @brief 获取切线速度 float GetTangentSpeed() const; + /// \~chinese + /// @brief 获取b2Contact b2Contact* GetB2Contact() const; + /// \~chinese + /// @brief 设置b2Contact void SetB2Contact(b2Contact* contact); bool operator==(const Contact& rhs) const; @@ -120,29 +118,33 @@ private: class ContactList { template - class IteratorImpl : public std::iterator + class IteratorImpl { - using herit = std::iterator; - public: + using iterator_category = std::forward_iterator_tag; + using value_type = _Ty; + using pointer = _Ty*; + using reference = _Ty&; + using difference_type = ptrdiff_t; + IteratorImpl(const _Ty& elem) : elem_(elem) { } - inline typename herit::reference operator*() const + inline reference operator*() const { - return const_cast(elem_); + return const_cast(elem_); } - inline typename herit::pointer operator->() const + inline pointer operator->() const { - return std::pointer_traits::pointer_to(**this); + return std::pointer_traits::pointer_to(**this); } inline IteratorImpl& operator++() { - elem_ = elem_.GetB2Contact()->GetNext(); + elem_.SetB2Contact(elem_.GetB2Contact()->GetNext()); return *this; } @@ -225,67 +227,75 @@ private: /** @} */ -inline bool Contact::IsValid() const -{ - return contact_ != nullptr; -} inline bool Contact::IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); } + inline void Contact::SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); } + inline bool Contact::IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); } + inline void Contact::SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); } + inline float Contact::GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); } + inline void Contact::ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); } + inline void Contact::SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); } + inline float Contact::GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); } + inline void Contact::ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); } + inline b2Contact* Contact::GetB2Contact() const { return contact_; } + inline void Contact::SetB2Contact(b2Contact* contact) { contact_ = contact; } + inline bool Contact::operator==(const Contact& rhs) const { return contact_ == rhs.contact_; } + inline bool Contact::operator!=(const Contact& rhs) const { return contact_ != rhs.contact_; diff --git a/src/kiwano-physics/ContactEdge.cpp b/src/kiwano-physics/ContactEdge.cpp index 9de13ff3..d75b4d04 100644 --- a/src/kiwano-physics/ContactEdge.cpp +++ b/src/kiwano-physics/ContactEdge.cpp @@ -30,10 +30,13 @@ ContactEdge::ContactEdge() { } -ContactEdge::ContactEdge(b2ContactEdge* edge) - : ContactEdge() +Contact ContactEdge::GetContact() const { - SetB2ContactEdge(edge); + KGE_ASSERT(edge_); + + Contact contact; + contact.SetB2Contact(edge_->contact); + return contact; } } // namespace physics diff --git a/src/kiwano-physics/ContactEdge.h b/src/kiwano-physics/ContactEdge.h index d43b8cbd..e62deef0 100644 --- a/src/kiwano-physics/ContactEdge.h +++ b/src/kiwano-physics/ContactEdge.h @@ -37,22 +37,20 @@ class KGE_API ContactEdge public: ContactEdge(); - ContactEdge(b2ContactEdge* edge); - - /// \~chinese - /// @brief 是否有效 - bool IsValid() const; - /// \~chinese /// @brief 获取接触物体 - Body* GetOtherBody() const; + PhysicBody* GetOtherBody() const; /// \~chinese /// @brief 获取接触 Contact GetContact() const; + /// \~chinese + /// @brief 获取b2ContactEdge b2ContactEdge* GetB2ContactEdge() const; + /// \~chinese + /// @brief 设置b2ContactEdge void SetB2ContactEdge(b2ContactEdge* edge); bool operator==(const ContactEdge& rhs) const; @@ -67,36 +65,40 @@ private: class ContactEdgeList { template - class IteratorImpl : public std::iterator + class IteratorImpl { - using herit = std::iterator; - public: + using iterator_category = std::forward_iterator_tag; + using value_type = _Ty; + using pointer = _Ty*; + using reference = _Ty&; + using difference_type = ptrdiff_t; + inline IteratorImpl(const _Ty& elem) : elem_(elem) { } - inline typename herit::reference operator*() const + inline reference operator*() const { - return const_cast(elem_); + return const_cast(elem_); } - inline typename herit::pointer operator->() const + inline pointer operator->() const { - return std::pointer_traits::pointer_to(**this); + return std::pointer_traits::pointer_to(**this); } inline IteratorImpl& operator++() { - elem_ = elem_.GetB2ContactEdge()->next; + elem_.SetB2ContactEdge(elem_.GetB2ContactEdge()->next); return *this; } inline IteratorImpl operator++(int) { IteratorImpl old = *this; - operator++(); + operator++(); return old; } @@ -153,7 +155,7 @@ public: inline iterator end() { - return iterator(nullptr); + return iterator(ContactEdge()); } inline const_iterator end() const @@ -163,7 +165,7 @@ public: inline const_iterator cend() const { - return const_iterator(nullptr); + return const_iterator(ContactEdge()); } private: @@ -172,24 +174,10 @@ private: /** @} */ -inline bool ContactEdge::IsValid() const -{ - return edge_ != nullptr; -} - -inline Body* ContactEdge::GetOtherBody() const +inline PhysicBody* ContactEdge::GetOtherBody() const { KGE_ASSERT(edge_); - return static_cast(edge_->other->GetUserData()); -} - -inline Contact ContactEdge::GetContact() const -{ - KGE_ASSERT(edge_); - - Contact contact; - contact.SetB2Contact(edge_->contact); - return contact; + return static_cast(edge_->other->GetUserData()); } inline b2ContactEdge* ContactEdge::GetB2ContactEdge() const diff --git a/src/kiwano-physics/ContactEvent.h b/src/kiwano-physics/ContactEvent.h index d19f0262..eee6a1a7 100644 --- a/src/kiwano-physics/ContactEvent.h +++ b/src/kiwano-physics/ContactEvent.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include +#include #include namespace kiwano diff --git a/src/kiwano-physics/Fixture.cpp b/src/kiwano-physics/Fixture.cpp index 51e20a2b..48d5116e 100644 --- a/src/kiwano-physics/Fixture.cpp +++ b/src/kiwano-physics/Fixture.cpp @@ -18,127 +18,111 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include +#include #include -#include +#include namespace kiwano { namespace physics { -namespace +FixturePtr Fixture::CreateCircle(Param const& param, float radius, Point const& offset) { - -FixturePtr CreateFixture(Body* body, b2Shape* shape, const Fixture::Param& param) -{ - KGE_ASSERT(body); - - b2Body* b2body = body->GetB2Body(); - KGE_ASSERT(b2body); - - b2FixtureDef fd; - fd.density = param.density; - fd.friction = param.friction; - fd.restitution = param.restitution; - fd.shape = shape; - FixturePtr ptr = new (std::nothrow) Fixture; if (ptr) { - b2Fixture* fixture = b2body->CreateFixture(&fd); - if (fixture) + auto shape = std::make_unique(); + shape->m_radius = global::ToMeters(radius); + shape->m_p = global::ToMeters(offset); + + ptr->shape_ = std::move(shape); + ptr->param_ = param; + } + return ptr; +} + +FixturePtr Fixture::CreateRect(Param const& param, Size const& size, Point const& offset, float rotation) +{ + FixturePtr ptr = new (std::nothrow) Fixture; + if (ptr) + { + b2Vec2 b2size = global::ToMeters(size); + b2Vec2 b2offset = global::ToMeters(offset); + + auto shape = std::make_unique(); + shape->SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation)); + + ptr->shape_ = std::move(shape); + ptr->param_ = param; + } + return ptr; +} + +FixturePtr Fixture::CreatePolygon(Param const& param, Vector const& vertexs) +{ + FixturePtr ptr = new (std::nothrow) Fixture; + if (ptr) + { + Vector b2vertexs; + b2vertexs.reserve(vertexs.size()); + for (const auto& v : vertexs) { - fixture->SetUserData(ptr.Get()); - ptr->SetB2Fixture(fixture); - return ptr; + b2vertexs.push_back(global::ToMeters(v)); } + + auto shape = std::make_unique(); + shape->Set(&b2vertexs[0], static_cast(b2vertexs.size())); + + ptr->shape_ = std::move(shape); + ptr->param_ = param; } - return nullptr; + return ptr; } -} // namespace - -FixturePtr Fixture::CreateCircle(Body* body, Param const& param, float radius, Point const& offset) +FixturePtr Fixture::CreateEdge(Param const& param, Point const& p1, Point const& p2) { - KGE_ASSERT(body); - World* world = body->GetWorld(); - - b2CircleShape shape; - shape.m_radius = world->Stage2World(radius); - shape.m_p = world->Stage2World(offset); - - return CreateFixture(body, &shape, param); -} - -FixturePtr Fixture::CreateRect(Body* body, Param const& param, Size const& size, Point const& offset, float rotation) -{ - KGE_ASSERT(body); - World* world = body->GetWorld(); - - b2Vec2 b2size = world->Stage2World(size); - b2Vec2 b2offset = world->Stage2World(offset); - - b2PolygonShape shape; - shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation)); - - return CreateFixture(body, &shape, param); -} - -FixturePtr Fixture::CreatePolygon(Body* body, Param const& param, Vector const& vertexs) -{ - KGE_ASSERT(body); - World* world = body->GetWorld(); - - Vector b2vertexs; - b2vertexs.reserve(vertexs.size()); - for (const auto& v : vertexs) + FixturePtr ptr = new (std::nothrow) Fixture; + if (ptr) { - b2vertexs.push_back(world->Stage2World(v)); + b2Vec2 start = global::ToMeters(p1); + b2Vec2 end = global::ToMeters(p2); + + auto shape = std::make_unique(); + shape->Set(start, end); + + ptr->shape_ = std::move(shape); + ptr->param_ = param; } - - b2PolygonShape shape; - shape.Set(&b2vertexs[0], static_cast(b2vertexs.size())); - - return CreateFixture(body, &shape, param); + return ptr; } -FixturePtr Fixture::CreateEdge(Body* body, Param const& param, Point const& p1, Point const& p2) +FixturePtr Fixture::CreateChain(Param const& param, Vector const& vertexs, bool loop) { - KGE_ASSERT(body); - World* world = body->GetWorld(); - - b2Vec2 start = world->Stage2World(p1); - b2Vec2 end = world->Stage2World(p2); - - b2EdgeShape shape; - shape.Set(start, end); - - return CreateFixture(body, &shape, param); -} - -FixturePtr Fixture::CreateChain(Body* body, Param const& param, Vector const& vertexs, bool loop) -{ - KGE_ASSERT(body); - World* world = body->GetWorld(); - - Vector b2vertexs; - b2vertexs.reserve(vertexs.size()); - for (const auto& v : vertexs) + FixturePtr ptr = new (std::nothrow) Fixture; + if (ptr) { - b2vertexs.push_back(world->Stage2World(v)); - } + Vector b2vertexs; + b2vertexs.reserve(vertexs.size()); + for (const auto& v : vertexs) + { + b2vertexs.push_back(global::ToMeters(v)); + } - b2ChainShape shape; - if (loop) - { - shape.CreateLoop(&b2vertexs[0], static_cast(b2vertexs.size())); + auto shape = std::make_unique(); + if (loop) + { + shape->CreateLoop(&b2vertexs[0], static_cast(b2vertexs.size())); + } + else + { + shape->CreateChain(&b2vertexs[0], static_cast(b2vertexs.size())); + } + + ptr->shape_ = std::move(shape); + ptr->param_ = param; } - else - { - shape.CreateChain(&b2vertexs[0], static_cast(b2vertexs.size())); - } - return CreateFixture(body, &shape, param); + return ptr; } Fixture::Fixture() @@ -148,40 +132,64 @@ Fixture::Fixture() Fixture::~Fixture() { - if (fixture_) - { - b2Body* body = fixture_->GetBody(); - if (body) - { - body->DestroyFixture(fixture_); - } - } } -Body* Fixture::GetBody() const +bool Fixture::Init(PhysicBodyPtr body) +{ + return this->Init(body.Get()); +} + +bool Fixture::Init(PhysicBody* body) +{ + KGE_ASSERT(fixture_ == nullptr); + KGE_ASSERT(body); + + if (body) + { + b2Body* b2body = body->GetB2Body(); + if (b2body == nullptr) + { + // lazy init + return true; + } + + b2FixtureDef fd; + fd.density = param_.density; + fd.friction = param_.friction; + fd.restitution = param_.restitution; + fd.isSensor = param_.is_sensor; + fd.shape = shape_.get(); + + b2Fixture* fixture = b2body->CreateFixture(&fd); + if (fixture) + { + this->SetB2Fixture(fixture); + + // Don't need shape any more, b2Fixture already has a clone + shape_.reset(); + return true; + } + } + return false; +} + +PhysicBody* Fixture::GetBody() const { - fixture_->GetShape(); KGE_ASSERT(fixture_); - return static_cast(fixture_->GetBody()->GetUserData()); + return static_cast(fixture_->GetBody()->GetUserData()); } void Fixture::GetMassData(float* mass, Point* center, float* inertia) const { KGE_ASSERT(fixture_); - const Body* body = GetBody(); - KGE_ASSERT(body); - - const World* world = body->GetWorld(); - KGE_ASSERT(world); - b2MassData data; fixture_->GetMassData(&data); if (mass) *mass = data.mass; if (center) - *center = world->World2Stage(data.center); + *center = global::ToPixels(data.center); if (inertia) *inertia = data.I; } @@ -189,14 +197,20 @@ void Fixture::GetMassData(float* mass, Point* center, float* inertia) const bool Fixture::TestPoint(const Point& p) const { KGE_ASSERT(fixture_); + return fixture_->TestPoint(global::ToMeters(p)); +} - const Body* body = GetBody(); - KGE_ASSERT(body); - - const World* world = body->GetWorld(); - KGE_ASSERT(world); - - return fixture_->TestPoint(world->Stage2World(p)); +void Fixture::Destroy() +{ + if (fixture_) + { + b2Body* body = fixture_->GetBody(); + if (body) + { + body->DestroyFixture(fixture_); + } + fixture_ = nullptr; + } } } // namespace physics diff --git a/src/kiwano-physics/Fixture.h b/src/kiwano-physics/Fixture.h index b8c261fa..9a71414e 100644 --- a/src/kiwano-physics/Fixture.h +++ b/src/kiwano-physics/Fixture.h @@ -19,13 +19,13 @@ // THE SOFTWARE. #pragma once -#include +#include +#include namespace kiwano { namespace physics { -class Body; KGE_DECLARE_SMART_PTR(Fixture); @@ -61,56 +61,55 @@ public: /// \~chinese /// @brief 创建圆形夹具 - /// @param body 添加夹具的物体 /// @param param 夹具参数 /// @param radius 圆形半径 /// @param offset 偏移量 - static FixturePtr CreateCircle(Body* body, Param const& param, float radius, Point const& offset = Point()); + static FixturePtr CreateCircle(Param const& param, float radius, Point const& offset = Point()); /// \~chinese /// @brief 创建矩形夹具 - /// @param body 添加夹具的物体 /// @param param 夹具参数 /// @param size 矩形大小 /// @param offset 偏移量 /// @param rotation 旋转角度 - static FixturePtr CreateRect(Body* body, Param const& param, Size const& size, Point const& offset = Point(), + static FixturePtr CreateRect(Param const& param, Size const& size, Point const& offset = Point(), float rotation = 0.f); /// \~chinese /// @brief 创建多边形夹具 - /// @param body 添加夹具的物体 /// @param param 夹具参数 /// @param vertexs 多边形顶点 - static FixturePtr CreatePolygon(Body* body, Param const& param, Vector const& vertexs); + static FixturePtr CreatePolygon(Param const& param, Vector const& vertexs); /// \~chinese /// @brief 创建边夹具 - /// @param body 添加夹具的物体 /// @param param 夹具参数 /// @param p1 边的起点 /// @param p2 边的终点 - static FixturePtr CreateEdge(Body* body, Param const& param, Point const& p1, Point const& p2); + static FixturePtr CreateEdge(Param const& param, Point const& p1, Point const& p2); /// \~chinese /// @brief 创建链条夹具 - /// @param body 添加夹具的物体 /// @param param 夹具参数 /// @param vertexs 链条顶点 /// @param loop 是否连接链条的起点和终点 - static FixturePtr CreateChain(Body* body, Param const& param, Vector const& vertexs, bool loop = false); + static FixturePtr CreateChain(Param const& param, Vector const& vertexs, bool loop = false); Fixture(); virtual ~Fixture(); /// \~chinese - /// @brief 是否有效 - bool IsValid() const; + /// @brief 初始化夹具 + bool Init(PhysicBodyPtr body); + + /// \~chinese + /// @brief 初始化夹具 + bool Init(PhysicBody* body); /// \~chinese /// @brief 获取夹具所在的物体 - Body* GetBody() const; + PhysicBody* GetBody() const; /// \~chinese /// @brief 是否是接触传感器 @@ -153,15 +152,25 @@ public: /// @brief 点测试 bool TestPoint(const Point& p) const; + /// \~chinese + /// @brief 销毁夹具 + void Destroy(); + + /// \~chinese + /// @brief 获取b2Fixture b2Fixture* GetB2Fixture() const; + /// \~chinese + /// @brief 设置b2Fixture void SetB2Fixture(b2Fixture* fixture); bool operator==(const Fixture& rhs) const; bool operator!=(const Fixture& rhs) const; private: - b2Fixture* fixture_; + b2Fixture* fixture_; + std::unique_ptr shape_; + Fixture::Param param_; }; /// \~chinese @@ -169,13 +178,14 @@ private: class FixtureList { template - class IteratorImpl : public std::iterator + class IteratorImpl { - using herit = std::iterator; - public: - using reference = typename herit::reference; - using pointer = typename herit::pointer; + using iterator_category = std::forward_iterator_tag; + using value_type = _Ty; + using pointer = _Ty*; + using reference = _Ty&; + using difference_type = ptrdiff_t; IteratorImpl(pointer elem) : elem_(elem) @@ -184,12 +194,12 @@ class FixtureList inline reference operator*() const { - return const_cast(*elem_); + return const_cast(*elem_); } inline pointer operator->() const { - return std::pointer_traits::pointer_to(**this); + return std::pointer_traits::pointer_to(**this); } inline IteratorImpl& operator++() @@ -203,7 +213,6 @@ class FixtureList inline IteratorImpl operator++(int) { IteratorImpl old = *this; - operator++(); return old; } @@ -224,6 +233,8 @@ class FixtureList public: using value_type = Fixture; + using reference = value_type&; + using pointer = value_type*; using iterator = IteratorImpl; using const_iterator = IteratorImpl; @@ -232,7 +243,7 @@ public: { } - inline FixtureList(value_type* first) + inline FixtureList(pointer first) : first_(first) { } @@ -278,62 +289,77 @@ public: } private: - value_type* first_; + pointer first_; }; /** @} */ inline bool Fixture::IsSensor() const { - KGE_ASSERT(fixture_); - return fixture_->IsSensor(); + return param_.is_sensor; } inline void Fixture::SetSensor(bool sensor) { - KGE_ASSERT(fixture_); - fixture_->SetSensor(sensor); + if (param_.is_sensor != sensor) + { + param_.is_sensor = sensor; + if (fixture_) + { + fixture_->SetSensor(sensor); + } + } } inline float Fixture::GetDensity() const { - KGE_ASSERT(fixture_); - return fixture_->GetDensity(); + return param_.density; } inline void Fixture::SetDensity(float density) { - KGE_ASSERT(fixture_); - fixture_->SetDensity(density); + if (param_.density != density) + { + param_.density = density; + if (fixture_) + { + fixture_->SetDensity(density); + } + } } inline float Fixture::GetFriction() const { - KGE_ASSERT(fixture_); - return fixture_->GetFriction(); + return param_.friction; } inline void Fixture::SetFriction(float friction) { - KGE_ASSERT(fixture_); - fixture_->SetFriction(friction); + if (param_.friction != friction) + { + param_.friction = friction; + if (fixture_) + { + fixture_->SetFriction(friction); + } + } } inline float Fixture::GetRestitution() const { - KGE_ASSERT(fixture_); - return fixture_->GetRestitution(); + return param_.restitution; } inline void Fixture::SetRestitution(float restitution) { - KGE_ASSERT(fixture_); - fixture_->SetRestitution(restitution); -} - -inline bool Fixture::IsValid() const -{ - return fixture_ != nullptr; + if (param_.restitution != restitution) + { + param_.restitution = restitution; + if (fixture_) + { + fixture_->SetRestitution(restitution); + } + } } inline b2Fixture* Fixture::GetB2Fixture() const @@ -344,6 +370,10 @@ inline b2Fixture* Fixture::GetB2Fixture() const inline void Fixture::SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; + if (fixture) + { + fixture->SetUserData(this); + } } inline bool Fixture::operator==(const Fixture& rhs) const diff --git a/src/kiwano-physics/helper.h b/src/kiwano-physics/Global.cpp similarity index 68% rename from src/kiwano-physics/helper.h rename to src/kiwano-physics/Global.cpp index f3be4fbf..3bc64dc6 100644 --- a/src/kiwano-physics/helper.h +++ b/src/kiwano-physics/Global.cpp @@ -19,22 +19,51 @@ // THE SOFTWARE. #pragma once -#include - -// Box2D -#include <3rd-party/Box2D/Box2D.h> +#include namespace kiwano { namespace physics { -inline b2Vec2 Stage2World(const Vec2& pos) +namespace global { - return b2Vec2(pos.x, pos.y); -} -inline Vec2 World2Stage(const b2Vec2& pos) + +namespace { - return Vec2(pos.x, pos.y); +float global_scale = 100.f; // 100 pixels per meters } + +float GetScale() +{ + return global_scale; +} + +void SetScale(float scale) +{ + global_scale = scale; +} + +float ToPixels(float value) +{ + return value * global_scale; +} + +Vec2 ToPixels(const b2Vec2& pos) +{ + return Point(ToPixels(pos.x), ToPixels(pos.y)); +} + +float ToMeters(float value) +{ + return value / global_scale; +} + +b2Vec2 ToMeters(const Vec2& pos) +{ + return b2Vec2(ToMeters(pos.x), ToMeters(pos.y)); +} + +} // namespace global + } // namespace physics } // namespace kiwano diff --git a/src/kiwano-physics/Global.h b/src/kiwano-physics/Global.h new file mode 100644 index 00000000..0fbaeffd --- /dev/null +++ b/src/kiwano-physics/Global.h @@ -0,0 +1,70 @@ +// Copyright (c) 2018-2019 Kiwano - Nomango +// +// 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 + +// Box2D +#include <3rd-party/Box2D/Box2D.h> + +namespace kiwano +{ +namespace physics +{ + +KGE_DECLARE_SMART_PTR(PhysicWorld); +KGE_DECLARE_SMART_PTR(PhysicBody); + +namespace global +{ + +/// \~chinese +/// @brief 获取全局缩放比例 +/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100 +float GetScale(); + +/// \~chinese +/// @brief 设置全局缩放比例 +/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100 +void SetScale(float scale); + +/// \~chinese +/// @brief 游戏世界单位转换为物理世界单位 +/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位 +float ToPixels(float value); + +/// \~chinese +/// @brief 游戏世界单位转换为物理世界单位 +/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位 +Vec2 ToPixels(const b2Vec2& pos); + +/// \~chinese +/// @brief 物理世界单位转换为游戏世界单位 +/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米 +float ToMeters(float value); + +/// \~chinese +/// @brief 物理世界单位转换为游戏世界单位 +/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米 +b2Vec2 ToMeters(const Vec2& pos); + +} // namespace global +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/Joint.cpp b/src/kiwano-physics/Joint.cpp index 08462be9..83a2ac25 100644 --- a/src/kiwano-physics/Joint.cpp +++ b/src/kiwano-physics/Joint.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include -#include +#include namespace kiwano { @@ -38,42 +38,46 @@ Joint::Joint() Joint::~Joint() { - Destroy(); } -bool Joint::InitJoint(World* world, b2JointDef* joint_def) +bool Joint::Init(PhysicWorld* world) { + return false; +} + +bool Joint::Init(PhysicWorld* world, b2JointDef* joint_def) +{ + KGE_ASSERT(joint_ == nullptr); KGE_ASSERT(world); Destroy(); world_ = world; - if (world_) + + b2World* b2world = world_->GetB2World(); + b2Joint* joint = b2world->CreateJoint(joint_def); + if (joint) { - world_->AddJoint(this); - - b2Joint* joint = world_->GetB2World()->CreateJoint(joint_def); SetB2Joint(joint); - - return joint != nullptr; + return true; } return false; } -BodyPtr Joint::GetBodyA() const +PhysicBodyPtr Joint::GetBodyA() const { KGE_ASSERT(joint_); b2Body* body = joint_->GetBodyA(); - return BodyPtr(static_cast(body->GetUserData())); + return PhysicBodyPtr(static_cast(body->GetUserData())); } -BodyPtr Joint::GetBodyB() const +PhysicBodyPtr Joint::GetBodyB() const { KGE_ASSERT(joint_); b2Body* body = joint_->GetBodyB(); - return BodyPtr(static_cast(body->GetUserData())); + return PhysicBodyPtr(static_cast(body->GetUserData())); } void Joint::SetB2Joint(b2Joint* joint) @@ -81,97 +85,101 @@ void Joint::SetB2Joint(b2Joint* joint) joint_ = joint; if (joint_) { + joint_->SetUserData(this); type_ = Joint::Type(joint_->GetType()); } } void Joint::Destroy() { - if (world_) + if (joint_ && world_) { - world_->RemoveJoint(this); + b2World* b2world = world_->GetB2World(); + if (b2world) + { + b2world->DestroyJoint(joint_); + } } + + joint_ = nullptr; + world_ = nullptr; } // // DistanceJoint // -DistanceJointPtr DistanceJoint::Create(World* world, Param const& param) +DistanceJointPtr DistanceJoint::Create(Param const& param) { DistanceJointPtr ptr = new (std::nothrow) DistanceJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } DistanceJoint::DistanceJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool DistanceJoint::InitJoint(World* world, DistanceJoint::Param const& param) +bool DistanceJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2DistanceJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor_a), - world->Stage2World(param.anchor_b)); - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor_a), + global::ToMeters(param_.anchor_b)); + def.frequencyHz = param_.frequency_hz; + def.dampingRatio = param_.damping_ratio; - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } void DistanceJoint::SetLength(float length) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetLength(GetWorld()->Stage2World(length)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetLength(global::ToMeters(length)); } float DistanceJoint::GetLength() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLength()); + KGE_ASSERT(raw_joint_); + return global::ToMeters(raw_joint_->GetLength()); } // // FrictionJoint // -FrictionJointPtr FrictionJoint::Create(World* world, Param const& param) +FrictionJointPtr FrictionJoint::Create(Param const& param) { FrictionJointPtr ptr = new (std::nothrow) FrictionJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } FrictionJoint::FrictionJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool FrictionJoint::InitJoint(World* world, FrictionJoint::Param const& param) +bool FrictionJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2FrictionJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); - def.maxForce = param.max_force; - def.maxTorque = world->Stage2World(param.max_torque); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor)); + def.maxForce = param_.max_force; + def.maxTorque = global::ToMeters(param_.max_torque); - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } @@ -190,47 +198,45 @@ float FrictionJoint::GetMaxForce() const void FrictionJoint::SetMaxTorque(float length) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxTorque(global::ToMeters(length)); } float FrictionJoint::GetMaxTorque() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetMaxTorque()); } // // GearJoint // -GearJointPtr GearJoint::Create(World* world, Param const& param) +GearJointPtr GearJoint::Create(Param const& param) { GearJointPtr ptr = new (std::nothrow) GearJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } GearJoint::GearJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool GearJoint::InitJoint(World* world, GearJoint::Param const& param) +bool GearJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.joint_a && param.joint_b); + KGE_ASSERT(param_.joint_a && param_.joint_b); b2GearJointDef def; - def.joint1 = param.joint_a->GetB2Joint(); - def.joint2 = param.joint_b->GetB2Joint(); - def.ratio = param.ratio; + def.joint1 = param_.joint_a->GetB2Joint(); + def.joint2 = param_.joint_b->GetB2Joint(); + def.ratio = param_.ratio; - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } @@ -251,34 +257,32 @@ float GearJoint::GetRatio() const // MotorJoint // -MotorJointPtr MotorJoint::Create(World* world, Param const& param) +MotorJointPtr MotorJoint::Create(Param const& param) { MotorJointPtr ptr = new (std::nothrow) MotorJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } MotorJoint::MotorJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool MotorJoint::InitJoint(World* world, MotorJoint::Param const& param) +bool MotorJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2MotorJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body()); - def.maxForce = param.max_force; - def.maxTorque = world->Stage2World(param.max_torque); - def.correctionFactor = param.correction_factor; + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body()); + def.maxForce = param_.max_force; + def.maxTorque = global::ToMeters(param_.max_torque); + def.correctionFactor = param_.correction_factor; - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } @@ -297,131 +301,127 @@ float MotorJoint::GetMaxForce() const void MotorJoint::SetMaxTorque(float length) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxTorque(GetWorld()->Stage2World(length)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxTorque(global::ToMeters(length)); } float MotorJoint::GetMaxTorque() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxTorque()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetMaxTorque()); } // // PrismaticJoint // -PrismaticJointPtr PrismaticJoint::Create(World* world, Param const& param) +PrismaticJointPtr PrismaticJoint::Create(Param const& param) { PrismaticJointPtr ptr = new (std::nothrow) PrismaticJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } PrismaticJoint::PrismaticJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool PrismaticJoint::InitJoint(World* world, PrismaticJoint::Param const& param) +bool PrismaticJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2PrismaticJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor), - Stage2World(param.axis)); - def.enableLimit = param.enable_limit; - def.lowerTranslation = world->Stage2World(param.lower_translation); - def.upperTranslation = world->Stage2World(param.upper_translation); - def.enableMotor = param.enable_motor; - def.maxMotorForce = param.max_motor_force; - def.motorSpeed = world->Stage2World(param.motor_speed); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor), + b2Vec2(param_.axis.x, param_.axis.y)); + def.enableLimit = param_.enable_limit; + def.lowerTranslation = global::ToMeters(param_.lower_translation); + def.upperTranslation = global::ToMeters(param_.upper_translation); + def.enableMotor = param_.enable_motor; + def.maxMotorForce = param_.max_motor_force; + def.motorSpeed = global::ToMeters(param_.motor_speed); - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } float PrismaticJoint::GetJointTranslation() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetJointTranslation()); } float PrismaticJoint::GetJointSpeed() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointSpeed()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetJointSpeed()); } float PrismaticJoint::GetLowerLimit() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLowerLimit()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetLowerLimit()); } float PrismaticJoint::GetUpperLimit() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetUpperLimit()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetUpperLimit()); } void PrismaticJoint::SetLimits(float lower, float upper) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetLimits(GetWorld()->Stage2World(lower), GetWorld()->Stage2World(upper)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetLimits(global::ToMeters(lower), global::ToMeters(upper)); } // // PulleyJoint // -PulleyJointPtr PulleyJoint::Create(World* world, Param const& param) +PulleyJointPtr PulleyJoint::Create(Param const& param) { PulleyJointPtr ptr = new (std::nothrow) PulleyJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } PulleyJoint::PulleyJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool PulleyJoint::InitJoint(World* world, PulleyJoint::Param const& param) +bool PulleyJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2PulleyJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.ground_anchor_a), - world->Stage2World(param.ground_anchor_b), world->Stage2World(param.anchor_a), - world->Stage2World(param.anchor_b), param.ratio); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.ground_anchor_a), + global::ToMeters(param_.ground_anchor_b), global::ToMeters(param_.anchor_a), + global::ToMeters(param_.anchor_b), param_.ratio); - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } Point PulleyJoint::GetGroundAnchorA() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorA()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetGroundAnchorA()); } Point PulleyJoint::GetGroundAnchorB() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetGroundAnchorB()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetGroundAnchorB()); } float PulleyJoint::GetRatio() const @@ -432,189 +432,183 @@ float PulleyJoint::GetRatio() const float PulleyJoint::GetLengthA() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLengthA()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetLengthA()); } float PulleyJoint::GetLengthB() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetLengthB()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetLengthB()); } float PulleyJoint::GetCurrentLengthA() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthA()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetCurrentLengthA()); } float PulleyJoint::GetCurrentLengthB() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetCurrentLengthB()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetCurrentLengthB()); } // // RevoluteJoint // -RevoluteJointPtr RevoluteJoint::Create(World* world, Param const& param) +RevoluteJointPtr RevoluteJoint::Create(Param const& param) { RevoluteJointPtr ptr = new (std::nothrow) RevoluteJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } RevoluteJoint::RevoluteJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool RevoluteJoint::InitJoint(World* world, RevoluteJoint::Param const& param) +bool RevoluteJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2RevoluteJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); - def.enableLimit = param.enable_limit; - def.lowerAngle = math::Degree2Radian(param.lower_angle); - def.upperAngle = math::Degree2Radian(param.upper_angle); - def.enableMotor = param.enable_motor; - def.maxMotorTorque = world->Stage2World(param.max_motor_torque); - def.motorSpeed = math::Degree2Radian(param.motor_speed); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor)); + def.enableLimit = param_.enable_limit; + def.lowerAngle = math::Degree2Radian(param_.lower_angle); + def.upperAngle = math::Degree2Radian(param_.upper_angle); + def.enableMotor = param_.enable_motor; + def.maxMotorTorque = global::ToMeters(param_.max_motor_torque); + def.motorSpeed = math::Degree2Radian(param_.motor_speed); - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } float RevoluteJoint::GetJointAngle() const { - KGE_ASSERT(raw_joint_ && GetWorld()); + KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); } float RevoluteJoint::GetJointSpeed() const { - KGE_ASSERT(raw_joint_ && GetWorld()); + KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointSpeed()); } float RevoluteJoint::GetLowerLimit() const { - KGE_ASSERT(raw_joint_ && GetWorld()); + KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetLowerLimit()); } float RevoluteJoint::GetUpperLimit() const { - KGE_ASSERT(raw_joint_ && GetWorld()); + KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetUpperLimit()); } void RevoluteJoint::SetLimits(float lower, float upper) { - KGE_ASSERT(raw_joint_ && GetWorld()); + KGE_ASSERT(raw_joint_); raw_joint_->SetLimits(math::Degree2Radian(lower), math::Degree2Radian(upper)); } void RevoluteJoint::SetMaxMotorTorque(float torque) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxMotorTorque(global::ToMeters(torque)); } float RevoluteJoint::GetMaxMotorTorque() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetMaxMotorTorque()); } // // RopeJoint // -RopeJointPtr RopeJoint::Create(World* world, Param const& param) +RopeJointPtr RopeJoint::Create(Param const& param) { RopeJointPtr ptr = new (std::nothrow) RopeJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } RopeJoint::RopeJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool RopeJoint::InitJoint(World* world, RopeJoint::Param const& param) +bool RopeJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2RopeJointDef def; - def.bodyA = param.body_a->GetB2Body(); - def.bodyB = param.body_b->GetB2Body(); - def.localAnchorA = world->Stage2World(param.local_anchor_a); - def.localAnchorB = world->Stage2World(param.local_anchor_b); - def.maxLength = world->Stage2World(param.max_length); + def.bodyA = param_.body_a->GetB2Body(); + def.bodyB = param_.body_b->GetB2Body(); + def.localAnchorA = global::ToMeters(param_.local_anchor_a); + def.localAnchorB = global::ToMeters(param_.local_anchor_b); + def.maxLength = global::ToMeters(param_.max_length); - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } void RopeJoint::SetMaxLength(float length) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxLength(GetWorld()->Stage2World(length)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxLength(global::ToMeters(length)); } float RopeJoint::GetMaxLength() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxLength()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetMaxLength()); } // // WeldJoint // -WeldJointPtr WeldJoint::Create(World* world, Param const& param) +WeldJointPtr WeldJoint::Create(Param const& param) { WeldJointPtr ptr = new (std::nothrow) WeldJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } WeldJoint::WeldJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool WeldJoint::InitJoint(World* world, WeldJoint::Param const& param) +bool WeldJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2WeldJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor)); - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor)); + def.frequencyHz = param_.frequency_hz; + def.dampingRatio = param_.damping_ratio; - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } @@ -623,99 +617,95 @@ bool WeldJoint::InitJoint(World* world, WeldJoint::Param const& param) // WheelJoint // -WheelJointPtr WheelJoint::Create(World* world, Param const& param) +WheelJointPtr WheelJoint::Create(Param const& param) { WheelJointPtr ptr = new (std::nothrow) WheelJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } WheelJoint::WheelJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool WheelJoint::InitJoint(World* world, WheelJoint::Param const& param) +bool WheelJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2WheelJointDef def; - def.Initialize(param.body_a->GetB2Body(), param.body_b->GetB2Body(), world->Stage2World(param.anchor), - Stage2World(param.axis)); - def.enableMotor = param.enable_motor; - def.maxMotorTorque = world->Stage2World(param.max_motor_torque); - def.motorSpeed = world->Stage2World(param.motor_speed); - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor), + b2Vec2(param_.axis.x, param_.axis.y)); + def.enableMotor = param_.enable_motor; + def.maxMotorTorque = global::ToMeters(param_.max_motor_torque); + def.motorSpeed = global::ToMeters(param_.motor_speed); + def.frequencyHz = param_.frequency_hz; + def.dampingRatio = param_.damping_ratio; - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } float WheelJoint::GetJointTranslation() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointTranslation()); + KGE_ASSERT(raw_joint_); + return global::ToMeters(raw_joint_->GetJointTranslation()); } float WheelJoint::GetJointLinearSpeed() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetJointLinearSpeed()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetJointLinearSpeed()); } void WheelJoint::SetMaxMotorTorque(float torque) { - KGE_ASSERT(raw_joint_ && GetWorld()); - raw_joint_->SetMaxMotorTorque(GetWorld()->Stage2World(torque)); + KGE_ASSERT(raw_joint_); + raw_joint_->SetMaxMotorTorque(global::ToMeters(torque)); } float WheelJoint::GetMaxMotorTorque() const { - KGE_ASSERT(raw_joint_ && GetWorld()); - return GetWorld()->World2Stage(raw_joint_->GetMaxMotorTorque()); + KGE_ASSERT(raw_joint_); + return global::ToPixels(raw_joint_->GetMaxMotorTorque()); } // // MouseJoint // -MouseJointPtr MouseJoint::Create(World* world, Param const& param) +MouseJointPtr MouseJoint::Create(Param const& param) { MouseJointPtr ptr = new (std::nothrow) MouseJoint; if (ptr) { - if (!ptr->InitJoint(world, param)) - return nullptr; + ptr->param_ = param; } return ptr; } MouseJoint::MouseJoint() - : Joint() - , raw_joint_(nullptr) + : raw_joint_(nullptr) { } -bool MouseJoint::InitJoint(World* world, MouseJoint::Param const& param) +bool MouseJoint::Init(PhysicWorld* world) { - KGE_ASSERT(param.body_a && param.body_b); + KGE_ASSERT(param_.body_a && param_.body_b); b2MouseJointDef def; - def.bodyA = param.body_a->GetB2Body(); - def.bodyB = param.body_b->GetB2Body(); - def.target = world->Stage2World(param.target); - def.maxForce = param.max_force; - def.frequencyHz = param.frequency_hz; - def.dampingRatio = param.damping_ratio; + def.bodyA = param_.body_a->GetB2Body(); + def.bodyB = param_.body_b->GetB2Body(); + def.target = global::ToMeters(param_.target); + def.maxForce = param_.max_force; + def.frequencyHz = param_.frequency_hz; + def.dampingRatio = param_.damping_ratio; - Joint::InitJoint(world, &def); + Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); return raw_joint_ != nullptr; } diff --git a/src/kiwano-physics/Joint.h b/src/kiwano-physics/Joint.h index 8301637d..578c02e0 100644 --- a/src/kiwano-physics/Joint.h +++ b/src/kiwano-physics/Joint.h @@ -19,8 +19,7 @@ // THE SOFTWARE. #pragma once -#include -#include +#include namespace kiwano { @@ -71,16 +70,16 @@ public: /// @brief 关节基础参数 struct ParamBase { - Body* body_a; ///< 关节连接的物体A - Body* body_b; ///< 关节连接的物体B + PhysicBody* body_a; ///< 关节连接的物体A + PhysicBody* body_b; ///< 关节连接的物体B - ParamBase(Body* body_a, Body* body_b) + ParamBase(PhysicBody* body_a, PhysicBody* body_b) : body_a(body_a) , body_b(body_b) { } - ParamBase(BodyPtr body_a, BodyPtr body_b) + ParamBase(PhysicBodyPtr body_a, PhysicBodyPtr body_b) : body_a(body_a.Get()) , body_b(body_b.Get()) { @@ -93,31 +92,40 @@ public: /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, b2JointDef* joint_def); + virtual bool Init(PhysicWorld* world); + + /// \~chinese + /// @brief 初始化关节 + bool Init(PhysicWorld* world, b2JointDef* joint_def); /// \~chinese /// @brief 获取关节连接的物体A - BodyPtr GetBodyA() const; + PhysicBodyPtr GetBodyA() const; /// \~chinese /// @brief 获取关节连接的物体B - BodyPtr GetBodyB() const; + PhysicBodyPtr GetBodyB() const; /// \~chinese /// @brief 获取物理世界 - World* GetWorld() const; + PhysicWorld* GetWorld() const; /// \~chinese /// @brief 销毁关节 void Destroy(); + /// \~chinese + /// @brief 获取b2Joint b2Joint* GetB2Joint() const; - void SetB2Joint(b2Joint* joint); + + /// \~chinese + /// @brief 设置b2Joint + void SetB2Joint(b2Joint* joint); private: - b2Joint* joint_; - World* world_; - Type type_; + b2Joint* joint_; + PhysicWorld* world_; + Type type_; }; /// \~chinese @@ -134,34 +142,31 @@ public: float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 - Param(Body* body_a, Body* body_b, Point const& anchor_a, Point const& anchor_b, float frequency_hz = 0.f, - float damping_ratio = 0.f) - : ParamBase(body_a, body_b) - , anchor_a(anchor_a) - , anchor_b(anchor_b) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) + Param() + : Param(nullptr, nullptr, Point(), Point()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor_a, Point const& anchor_b, float frequency_hz = 0.f, - float damping_ratio = 0.f) - : Param(body_a.Get(), body_b.Get(), anchor_a, anchor_b, frequency_hz, damping_ratio) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor_a, Point const& anchor_b) + : ParamBase(body_a, body_b) + , anchor_a(anchor_a) + , anchor_b(anchor_b) + , frequency_hz(0.0f) + , damping_ratio(0.0f) { } }; /// \~chinese /// @brief 创建固定距离关节 - /// @param world 物理世界 /// @param param 关节参数 - static DistanceJointPtr Create(World* world, Param const& param); + static DistanceJointPtr Create(Param const& param); DistanceJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 设置关节长度 @@ -188,6 +193,7 @@ public: float GetDampingRatio() const; private: + Param param_; b2DistanceJoint* raw_joint_; }; @@ -202,31 +208,30 @@ public: float max_force; ///< 最大摩擦力 float max_torque; ///< 最大扭力 - Param(Body* body_a, Body* body_b, Point const& anchor, float max_force = 0.f, float max_torque = 0.f) + Param() + : Param(nullptr, nullptr, Point()) + { + } + + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor, float max_force = 0.f, float max_torque = 0.f) : ParamBase(body_a, body_b) , anchor(anchor) , max_force(max_force) , max_torque(max_torque) { } - - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, float max_force = 0.f, float max_torque = 0.f) - : Param(body_a.Get(), body_b.Get(), anchor, max_force, max_torque) - { - } }; /// \~chinese /// @brief 创建摩擦关节 - /// @param world 物理世界 /// @param param 关节参数 - static FrictionJointPtr Create(World* world, Param const& param); + static FrictionJointPtr Create(Param const& param); FrictionJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 设置最大摩擦力 @@ -245,6 +250,7 @@ public: float GetMaxTorque() const; private: + Param param_; b2FrictionJoint* raw_joint_; }; @@ -261,31 +267,30 @@ public: Joint* joint_b; ///< 关节B(旋转关节/平移关节) float ratio; ///< 齿轮传动比 - Param(Joint* joint_a, Joint* joint_b, float ratio = 1.f) - : ParamBase(nullptr, nullptr) - , joint_a(joint_a) - , joint_b(joint_b) - , ratio(ratio) + Param() + : Param(nullptr, nullptr) { } Param(JointPtr joint_a, JointPtr joint_b, float ratio = 1.f) - : Param(joint_a.Get(), joint_b.Get(), ratio) + : ParamBase(nullptr, nullptr) + , joint_a(joint_a.Get()) + , joint_b(joint_b.Get()) + , ratio(ratio) { } }; /// \~chinese /// @brief 创建齿轮关节 - /// @param world 物理世界 /// @param param 关节参数 - static GearJointPtr Create(World* world, Param const& param); + static GearJointPtr Create(Param const& param); GearJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 设定齿轮传动比 @@ -296,6 +301,7 @@ public: float GetRatio() const; private: + Param param_; b2GearJoint* raw_joint_; }; @@ -312,33 +318,30 @@ public: float max_torque; ///< 最大转矩 float correction_factor; ///< 位置矫正因子(范围 0-1) - Param(Body* body_a, Body* body_b, float max_force = 1.f, float max_torque = 100.f, - float correction_factor = 0.3f) - : ParamBase(body_a, body_b) - , max_force(max_force) - , max_torque(max_torque) - , correction_factor(correction_factor) + Param() + : Param(nullptr, nullptr) { } - Param(BodyPtr body_a, BodyPtr body_b, float max_force = 0.f, float max_torque = 0.f, - float correction_factor = 0.3f) - : Param(body_a.Get(), body_b.Get(), max_force, max_torque, correction_factor) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, float max_force = 0.f, float max_torque = 0.f) + : ParamBase(body_a, body_b) + , max_force(max_force) + , max_torque(max_torque) + , correction_factor(0.3f) { } }; /// \~chinese /// @brief 创建马达关节 - /// @param world 物理世界 /// @param param 关节参数 - static MotorJointPtr Create(World* world, Param const& param); + static MotorJointPtr Create(Param const& param); MotorJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 设置最大摩擦力 @@ -357,6 +360,7 @@ public: float GetMaxTorque() const; private: + Param param_; b2MotorJoint* raw_joint_; }; @@ -369,50 +373,44 @@ public: /// @brief 平移关节参数 struct Param : public Joint::ParamBase { - Point anchor; ///< 关节位置 - Vec2 axis; ///< 物体A滑动的方向 - bool enable_limit; ///< 是否启用限制 + Point anchor; ///< 关节位置 + Vec2 axis; ///< 物体A滑动的方向 + bool enable_limit; ///< 是否启用限制 float lower_translation; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 float upper_translation; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 - bool enable_motor; ///< 是否启用马达 - float max_motor_force; ///< 最大马达力 [N] - float motor_speed; ///< 马达转速 [degree/s] + bool enable_motor; ///< 是否启用马达 + float max_motor_force; ///< 最大马达力 [N] + float motor_speed; ///< 马达转速 [degree/s] - Param(Body* body_a, Body* body_b, Point const& anchor, Vec2 const& axis, bool enable_limit = false, - float lower_translation = 0.0f, float upper_translation = 0.0f, bool enable_motor = false, - float max_motor_force = 0.0f, float motor_speed = 0.0f) - : ParamBase(body_a, body_b) - , anchor(anchor) - , axis(axis) - , enable_limit(enable_limit) - , lower_translation(lower_translation) - , upper_translation(upper_translation) - , enable_motor(enable_motor) - , max_motor_force(max_motor_force) - , motor_speed(motor_speed) + Param() + : Param(nullptr, nullptr, Point(), Vec2()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, Vec2 const& axis, bool enable_limit = false, - float lower_translation = 0.0f, float upper_translation = 0.0f, bool enable_motor = false, - float max_motor_force = 0.0f, float motor_speed = 0.0f) - : Param(body_a.Get(), body_b.Get(), anchor, axis, enable_limit, lower_translation, upper_translation, - enable_motor, max_motor_force, motor_speed) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor, Vec2 const& axis) + : ParamBase(body_a, body_b) + , anchor(anchor) + , axis(axis) + , enable_limit(false) + , lower_translation(0.0f) + , upper_translation(0.0f) + , enable_motor(false) + , max_motor_force(0.0f) + , motor_speed(0.0f) { } }; /// \~chinese /// @brief 创建平移关节 - /// @param world 物理世界 /// @param param 关节参数 - static PrismaticJointPtr Create(World* world, Param const& param); + static PrismaticJointPtr Create(Param const& param); PrismaticJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 获取参考角 @@ -471,6 +469,7 @@ public: float GetMaxMotorForce() const; private: + Param param_; b2PrismaticJoint* raw_joint_; }; @@ -489,8 +488,13 @@ public: Point ground_anchor_b; ///< 物体B对应的滑轮的位置 float ratio; ///< 滑轮比,关节传动时,滑轮上升和下降的两头的位移比例 - Param(Body* body_a, Body* body_b, Point const& anchor_a, Point const& anchor_b, Point const& ground_anchor_a, - Point const& ground_anchor_b, float ratio = 1.0f) + Param() + : Param(nullptr, nullptr, Point(), Point(), Point(), Point()) + { + } + + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor_a, Point const& anchor_b, + Point const& ground_anchor_a, Point const& ground_anchor_b, float ratio = 1.0f) : ParamBase(body_a, body_b) , anchor_a(anchor_a) , anchor_b(anchor_b) @@ -499,25 +503,18 @@ public: , ratio(ratio) { } - - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor_a, Point const& anchor_b, - Point const& ground_anchor_a, Point const& ground_anchor_b, float ratio = 1.0f) - : Param(body_a.Get(), body_b.Get(), anchor_a, anchor_b, ground_anchor_a, ground_anchor_b, ratio) - { - } }; /// \~chinese /// @brief 创建滑轮关节 - /// @param world 物理世界 /// @param param 关节参数 - static PulleyJointPtr Create(World* world, Param const& param); + static PulleyJointPtr Create(Param const& param); PulleyJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 物体A对应的滑轮的位置 @@ -548,6 +545,7 @@ public: float GetCurrentLengthB() const; private: + Param param_; b2PulleyJoint* raw_joint_; }; @@ -560,48 +558,42 @@ public: /// @brief 旋转关节参数 struct Param : public Joint::ParamBase { - Point anchor; ///< 关节位置 - bool enable_limit; ///< 是否启用限制 - float lower_angle; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 - float upper_angle; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 + Point anchor; ///< 关节位置 + bool enable_limit; ///< 是否启用限制 + float lower_angle; ///< 移动的最小限制,与方向同向为正,反向为负,启用限制后才有效果 + float upper_angle; ///< 移动的最大限制,与方向同向为正,反向为负,启用限制后才有效果 bool enable_motor; ///< 是否启用马达 float max_motor_torque; ///< 最大马达力 [N] float motor_speed; ///< 马达转速 [degree/s] - Param(Body* body_a, Body* body_b, Point const& anchor, bool enable_limit = false, float lower_angle = 0.0f, - float upper_angle = 0.0f, bool enable_motor = false, float max_motor_torque = 0.0f, - float motor_speed = 0.0f) - : ParamBase(body_a, body_b) - , anchor(anchor) - , enable_limit(enable_limit) - , lower_angle(lower_angle) - , upper_angle(upper_angle) - , enable_motor(enable_motor) - , max_motor_torque(max_motor_torque) - , motor_speed(motor_speed) + Param() + : Param(nullptr, nullptr, Point()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, bool enable_limit = false, float lower_angle = 0.0f, - float upper_angle = 0.0f, bool enable_motor = false, float max_motor_torque = 0.0f, - float motor_speed = 0.0f) - : Param(body_a.Get(), body_b.Get(), anchor, enable_limit, lower_angle, upper_angle, enable_motor, - max_motor_torque, motor_speed) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor) + : ParamBase(body_a, body_b) + , anchor(anchor) + , enable_limit(false) + , lower_angle(0.0f) + , upper_angle(0.0f) + , enable_motor(false) + , max_motor_torque(0.0f) + , motor_speed(0.0f) { } }; /// \~chinese /// @brief 创建旋转关节 - /// @param world 物理世界 /// @param param 关节参数 - static RevoluteJointPtr Create(World* world, Param const& param); + static RevoluteJointPtr Create(Param const& param); RevoluteJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 获取参考角 @@ -660,6 +652,7 @@ public: float GetMaxMotorTorque() const; private: + Param param_; b2RevoluteJoint* raw_joint_; }; @@ -676,33 +669,30 @@ public: Point local_anchor_b; ///< 关节在物体B上的连接点 float max_length; ///< 绳索最大长度 - Param(Body* body_a, Body* body_b, Point const& local_anchor_a, Point const& local_anchor_b, - float max_length = 0.f) - : ParamBase(body_a, body_b) - , local_anchor_a(local_anchor_a) - , local_anchor_b(local_anchor_b) - , max_length(max_length) + Param() + : Param(nullptr, nullptr, Point(), Point()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& local_anchor_a, Point const& local_anchor_b, - float max_length = 0.f) - : Param(body_a.Get(), body_b.Get(), local_anchor_a, local_anchor_b, max_length) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& local_anchor_a, Point const& local_anchor_b) + : ParamBase(body_a, body_b) + , local_anchor_a(local_anchor_a) + , local_anchor_b(local_anchor_b) + , max_length(0.0f) { } }; /// \~chinese /// @brief 创建绳关节 - /// @param world 物理世界 /// @param param 关节参数 - static RopeJointPtr Create(World* world, Param const& param); + static RopeJointPtr Create(Param const& param); RopeJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 设置关节最大长度 @@ -713,6 +703,7 @@ public: float GetMaxLength() const; private: + Param param_; b2RopeJoint* raw_joint_; }; @@ -729,31 +720,30 @@ public: float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 - Param(Body* body_a, Body* body_b, Point const& anchor, float frequency_hz = 0.f, float damping_ratio = 0.f) - : ParamBase(body_a, body_b) - , anchor(anchor) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) + Param() + : Param(nullptr, nullptr, Point()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, float frequency_hz = 0.f, float damping_ratio = 0.f) - : Param(body_a.Get(), body_b.Get(), anchor, frequency_hz, damping_ratio) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor) + : ParamBase(body_a, body_b) + , anchor(anchor) + , frequency_hz(0.0f) + , damping_ratio(0.0f) { } }; /// \~chinese /// @brief 创建焊接关节 - /// @param world 物理世界 /// @param param 关节参数 - static WeldJointPtr Create(World* world, Param const& param); + static WeldJointPtr Create(Param const& param); WeldJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 获取物体B相对于物体A的角度 @@ -776,6 +766,7 @@ public: float GetDampingRatio() const; private: + Param param_; b2WeldJoint* raw_joint_; }; @@ -796,40 +787,34 @@ public: float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 float damping_ratio; ///< 弹簧阻尼率,值越大关节运动阻尼越大 - Param(Body* body_a, Body* body_b, Point const& anchor, Vec2 const& axis, float frequency_hz = 2.0f, - float damping_ratio = 0.7f, bool enable_motor = false, float max_motor_torque = 0.0f, - float motor_speed = 0.0f) - : ParamBase(body_a, body_b) - , anchor(anchor) - , axis(axis) - , enable_motor(enable_motor) - , max_motor_torque(max_motor_torque) - , motor_speed(motor_speed) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) + Param() + : Param(nullptr, nullptr, Point(), Vec2()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, Vec2 const& axis, float frequency_hz = 2.0f, - float damping_ratio = 0.7f, bool enable_motor = false, float max_motor_torque = 0.0f, - float motor_speed = 0.0f) - : Param(body_a.Get(), body_b.Get(), anchor, axis, frequency_hz, damping_ratio, enable_motor, - max_motor_torque, motor_speed) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& anchor, Vec2 const& axis) + : ParamBase(body_a, body_b) + , anchor(anchor) + , axis(axis) + , enable_motor(false) + , max_motor_torque(0.0f) + , motor_speed(0.0f) + , frequency_hz(2.0f) + , damping_ratio(0.7f) { } }; /// \~chinese /// @brief 创建轮关节 - /// @param world 物理世界 /// @param param 关节参数 - static WheelJointPtr Create(World* world, Param const& param); + static WheelJointPtr Create(Param const& param); WheelJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 获取关节当前的平移距离 @@ -888,6 +873,7 @@ public: float GetSpringDampingRatio() const; private: + Param param_; b2WheelJoint* raw_joint_; }; @@ -906,34 +892,31 @@ public: float frequency_hz; ///< 响应速度,数值越高关节响应的速度越快,看上去越坚固 float damping_ratio; ///< 阻尼率,值越大关节运动阻尼越大 - Param(Body* body_a, Body* body_b, Point const& target, float max_force, float frequency_hz = 5.0f, - float damping_ratio = 0.7f) - : ParamBase(body_a, body_b) - , target(target) - , max_force(max_force) - , frequency_hz(frequency_hz) - , damping_ratio(damping_ratio) + Param() + : Param(nullptr, nullptr, Point()) { } - Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f, - float damping_ratio = 0.7f) - : Param(body_a.Get(), body_b.Get(), target, max_force, frequency_hz, damping_ratio) + Param(PhysicBodyPtr body_a, PhysicBodyPtr body_b, Point const& target) + : ParamBase(body_a, body_b) + , target(target) + , max_force(0.0f) + , frequency_hz(5.0f) + , damping_ratio(0.7f) { } }; /// \~chinese /// @brief 创建鼠标关节 - /// @param world 物理世界 /// @param param 关节参数 - static MouseJointPtr Create(World* world, Param const& param); + static MouseJointPtr Create(Param const& param); MouseJoint(); /// \~chinese /// @brief 初始化关节 - bool InitJoint(World* world, Param const& param); + bool Init(PhysicWorld* world) override; /// \~chinese /// @brief 设定最大摩擦力 [N] @@ -960,6 +943,7 @@ public: float GetDampingRatio() const; private: + Param param_; b2MouseJoint* raw_joint_; }; @@ -969,7 +953,7 @@ inline b2Joint* Joint::GetB2Joint() const { return joint_; } -inline World* Joint::GetWorld() const +inline PhysicWorld* Joint::GetWorld() const { return world_; } diff --git a/src/kiwano-physics/PhysicBody.cpp b/src/kiwano-physics/PhysicBody.cpp new file mode 100644 index 00000000..a11bd777 --- /dev/null +++ b/src/kiwano-physics/PhysicBody.cpp @@ -0,0 +1,378 @@ +// Copyright (c) 2018-2019 Kiwano - Nomango +// +// 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 +#include + +namespace kiwano +{ +namespace physics +{ + +PhysicBodyPtr PhysicBody::Create(ActorPtr actor, Type type) +{ + return PhysicBody::Create(actor.Get(), type); +} + +PhysicBodyPtr PhysicBody::Create(Actor* actor, Type type) +{ + if (!actor) + { + return nullptr; + } + + PhysicBodyPtr ptr = new (std::nothrow) PhysicBody; + if (ptr) + { + ptr->SetType(type); + actor->AddComponent(ptr); + } + return ptr; +} + +PhysicBody::PhysicBody() + : body_(nullptr) + , world_(nullptr) + , type_(Type::Static) + , category_bits_(0x0001) + , mask_bits_(0xFFFF) + , group_index_(0) +{ +} + +PhysicBody::~PhysicBody() {} + +void PhysicBody::InitComponent(Actor* actor) +{ + Component::InitComponent(actor); + UpdateFromActor(); +} + +void PhysicBody::DestroyComponent() +{ + // Detach from actor first + Component::DestroyComponent(); + + // Destruction of fixtures may cause contact end + RemoveAllFixtures(); + + if (world_) + { + world_->RemoveBody(this); + } +} + +bool PhysicBody::Init(PhysicWorldPtr world) +{ + return Init(world.Get()); +} + +bool PhysicBody::Init(PhysicWorld* world) +{ + KGE_ASSERT(body_ == nullptr); + KGE_ASSERT(world); + + world_ = world; + + b2BodyDef def; + def.type = b2BodyType(type_); + + b2Body* b2body = world->GetB2World()->CreateBody(&def); + if (b2body) + { + SetB2Body(b2body); + UpdateFromActor(); + + // lazy init fixtures + for (auto fixture : fixtures_) + { + bool success = fixture->Init(this); + KGE_ASSERT(success); + } + return true; + } + return false; +} + +void PhysicBody::AddFixture(FixturePtr fixture) +{ + if (fixture) + { + bool success = fixture->Init(this); + KGE_ASSERT(success); + + fixtures_.push_back(fixture); + } +} + +Fixture* PhysicBody::AddCircleShape(float radius, float density, float friction) +{ + FixturePtr fixture = Fixture::CreateCircle(Fixture::Param(density, friction), radius); + AddFixture(fixture); + return fixture.Get(); +} + +Fixture* PhysicBody::AddRectShape(Vec2 const& size, float density, float friction) +{ + FixturePtr fixture = Fixture::CreateRect(Fixture::Param(density, friction), size); + AddFixture(fixture); + return fixture.Get(); +} + +Fixture* PhysicBody::AddPolygonShape(Vector const& vertexs, float density, float friction) +{ + FixturePtr fixture = Fixture::CreatePolygon(Fixture::Param(density, friction), vertexs); + AddFixture(fixture); + return fixture.Get(); +} + +Fixture* PhysicBody::AddEdgeShape(Point const& p1, Point const& p2, float density, float friction) +{ + FixturePtr fixture = Fixture::CreateEdge(Fixture::Param(density, friction), p1, p2); + AddFixture(fixture); + return fixture.Get(); +} + +Fixture* PhysicBody::AddChainShape(Vector const& vertexs, bool loop, float density, float friction) +{ + FixturePtr fixture = Fixture::CreateChain(Fixture::Param(density, friction), vertexs, loop); + AddFixture(fixture); + return fixture.Get(); +} + +void PhysicBody::RemoveFixture(FixturePtr fixture) +{ + if (fixture) + { + auto iter = std::find(fixtures_.begin(), fixtures_.end(), fixture); + if (iter != fixtures_.end()) + { + fixture->Destroy(); + fixtures_.erase(iter); + } + } +} + +void PhysicBody::RemoveAllFixtures() +{ + for (auto fixture : fixtures_) + { + fixture->Destroy(); + } + fixtures_.clear(); +} + +void PhysicBody::SetCategoryBits(uint16_t category_bits) +{ + KGE_ASSERT(body_); + + if (category_bits != category_bits_) + { + category_bits_ = category_bits; + + b2Fixture* fixture = body_->GetFixtureList(); + while (fixture) + { + UpdateFixtureFilter(fixture); + fixture = fixture->GetNext(); + } + } +} + +void PhysicBody::SetMaskBits(uint16_t mask_bits) +{ + KGE_ASSERT(body_); + + if (mask_bits != mask_bits_) + { + mask_bits_ = mask_bits; + + b2Fixture* fixture = body_->GetFixtureList(); + while (fixture) + { + UpdateFixtureFilter(fixture); + fixture = fixture->GetNext(); + } + } +} + +void PhysicBody::SetGroupIndex(int16_t index) +{ + KGE_ASSERT(body_); + + if (index != group_index_) + { + group_index_ = index; + + b2Fixture* fixture = body_->GetFixtureList(); + while (fixture) + { + UpdateFixtureFilter(fixture); + fixture = fixture->GetNext(); + } + } +} + +void PhysicBody::GetMassData(float* mass, Point* center, float* inertia) const +{ + KGE_ASSERT(body_); + + b2MassData data; + body_->GetMassData(&data); + + if (mass) + *mass = data.mass; + if (center) + *center = global::ToPixels(data.center); + if (inertia) + *inertia = data.I; +} + +void PhysicBody::SetMassData(float mass, Point const& center, float inertia) +{ + KGE_ASSERT(body_); + + b2MassData data; + data.mass = mass; + data.center = global::ToMeters(center); + data.I = inertia; + body_->SetMassData(&data); +} + +void PhysicBody::ResetMassData() +{ + KGE_ASSERT(body_); + body_->ResetMassData(); +} + +Point PhysicBody::GetPosition() const +{ + KGE_ASSERT(body_); + return global::ToPixels(body_->GetPosition()); +} + +void PhysicBody::SetTransform(Point const& pos, float angle) +{ + KGE_ASSERT(body_); + body_->SetTransform(global::ToMeters(pos), math::Degree2Radian(angle)); +} + +Point PhysicBody::GetLocalPoint(Point const& world) const +{ + KGE_ASSERT(body_); + return global::ToPixels(body_->GetLocalPoint(global::ToMeters(world))); +} + +Point PhysicBody::GetWorldPoint(Point const& local) const +{ + KGE_ASSERT(body_); + return global::ToPixels(body_->GetWorldPoint(global::ToMeters(local))); +} + +Point PhysicBody::GetLocalCenter() const +{ + KGE_ASSERT(body_); + return global::ToPixels(body_->GetLocalCenter()); +} + +Point PhysicBody::GetWorldCenter() const +{ + KGE_ASSERT(body_); + return global::ToPixels(body_->GetWorldCenter()); +} + +void PhysicBody::ApplyForce(Vec2 const& force, Point const& point, bool wake) +{ + KGE_ASSERT(body_); + body_->ApplyForce(b2Vec2(force.x, force.y), global::ToMeters(point), wake); +} + +void PhysicBody::ApplyForceToCenter(Vec2 const& force, bool wake) +{ + KGE_ASSERT(body_); + body_->ApplyForceToCenter(b2Vec2(force.x, force.y), wake); +} + +void PhysicBody::ApplyTorque(float torque, bool wake) +{ + KGE_ASSERT(body_); + body_->ApplyTorque(torque, wake); +} + +void PhysicBody::SetB2Body(b2Body* body) +{ + body_ = body; + if (body_) + { + body_->SetUserData(this); + type_ = PhysicBody::Type(body_->GetType()); + } +} + +void PhysicBody::Destroy() +{ + RemoveAllFixtures(); + + if (body_ && world_) + { + b2World* b2world = world_->GetB2World(); + b2world->DestroyBody(body_); + } + + body_ = nullptr; + world_ = nullptr; + + Component::RemoveFromActor(); +} + +void PhysicBody::UpdateActor() +{ + Actor* actor = GetBoundActor(); + if (actor && body_) + { + Point position = global::ToPixels(body_->GetPosition()); + float rotation = math::Radian2Degree(body_->GetAngle()); + actor->SetPosition(position); + actor->SetRotation(rotation); + } +} + +void PhysicBody::UpdateFromActor() +{ + Actor* actor = GetBoundActor(); + if (actor && body_) + { + b2Vec2 position = global::ToMeters(actor->GetPosition()); + float angle = math::Degree2Radian(actor->GetRotation()); + body_->SetTransform(position, angle); + } +} + +void PhysicBody::UpdateFixtureFilter(b2Fixture* fixture) +{ + b2Filter filter; + filter.categoryBits = category_bits_; + filter.maskBits = mask_bits_; + filter.groupIndex = group_index_; + fixture->SetFilterData(filter); +} + +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/Body.h b/src/kiwano-physics/PhysicBody.h similarity index 70% rename from src/kiwano-physics/Body.h rename to src/kiwano-physics/PhysicBody.h index 5b46cde1..07153915 100644 --- a/src/kiwano-physics/Body.h +++ b/src/kiwano-physics/PhysicBody.h @@ -19,17 +19,13 @@ // THE SOFTWARE. #pragma once -#include #include -#include +#include namespace kiwano { namespace physics { -class World; - -KGE_DECLARE_SMART_PTR(Body); /** * \addtogroup Physics @@ -38,7 +34,7 @@ KGE_DECLARE_SMART_PTR(Body); /// \~chinese /// @brief 物体 -class KGE_API Body : public virtual ObjectBase +class KGE_API PhysicBody : public Component { public: /// \~chinese @@ -51,34 +47,30 @@ public: }; /// \~chinese - /// @brief 初始化 - /// @param[in] world 物理世界 - /// @param[in] actor 绑定的角色 - /// @param[in] type 物体类型 - static BodyPtr Create(World* world, ActorPtr actor, Type type); + /// @brief 初始化物体 + /// @param actor 绑定该物体的角色 + /// @param type 物体类型 + static PhysicBodyPtr Create(ActorPtr actor, Type type); /// \~chinese - /// @brief 初始化 - /// @param[in] world 物理世界 - /// @param[in] actor 绑定的角色 - /// @param[in] type 物体类型 - static BodyPtr Create(World* world, Actor* actor, Type type); + /// @brief 初始化物体 + /// @param actor 绑定该物体的角色 + /// @param type 物体类型 + static PhysicBodyPtr Create(Actor* actor, Type type); - Body(); + PhysicBody(); - virtual ~Body(); + virtual ~PhysicBody(); /// \~chinese - /// @brief 初始化 + /// @brief 初始化物体 /// @param[in] world 物理世界 - /// @param[in] actor 绑定的角色 - bool InitBody(World* world, ActorPtr actor); + bool Init(PhysicWorldPtr world); /// \~chinese - /// @brief 初始化 + /// @brief 初始化物体 /// @param[in] world 物理世界 - /// @param[in] actor 绑定的角色 - bool InitBody(World* world, Actor* actor); + bool Init(PhysicWorld* world); /// \~chinese /// @brief 添加夹具 @@ -88,44 +80,43 @@ public: /// @brief 添加圆形夹具 /// @param radius 圆形半径 /// @param density 物体密度 - /// @param - Fixture* AddCircleShape(float radius, float density, float friction = 0.2f, float restitution = 0.f, - bool is_sensor = false); + /// @param + Fixture* AddCircleShape(float radius, float density, float friction = 0.2f); /// \~chinese /// @brief 添加矩形夹具 /// @param size 矩形大小 /// @param density 物体密度 - Fixture* AddRectShape(Vec2 const& size, float density, float friction = 0.2f, float restitution = 0.f, - bool is_sensor = false); + Fixture* AddRectShape(Vec2 const& size, float density, float friction = 0.2f); /// \~chinese /// @brief 添加多边形夹具 /// @param vertexs 多边形端点 /// @param density 物体密度 - Fixture* AddPolygonShape(Vector const& vertexs, float density, float friction = 0.2f, - float restitution = 0.f, bool is_sensor = false); + Fixture* AddPolygonShape(Vector const& vertexs, float density, float friction = 0.2f); /// \~chinese /// @brief 添加线段形夹具 /// @param p1 线段起点 /// @param p2 线段终点 /// @param density 物体密度 - Fixture* AddEdgeShape(Point const& p1, Point const& p2, float density, float friction = 0.2f, - float restitution = 0.f, bool is_sensor = false); + Fixture* AddEdgeShape(Point const& p1, Point const& p2, float density, float friction = 0.2f); /// \~chinese /// @brief 添加链条形夹具 /// @param vertexs 链条端点 /// @param loop 是否闭合 /// @param density 物体密度 - Fixture* AddChainShape(Vector const& vertexs, bool loop, float density, float friction = 0.2f, - float restitution = 0.f, bool is_sensor = false); + Fixture* AddChainShape(Vector const& vertexs, bool loop, float density, float friction = 0.2f); /// \~chinese /// @brief 移除夹具 void RemoveFixture(FixturePtr fixture); + /// \~chinese + /// @brief 移除所有夹具 + void RemoveAllFixtures(); + /// \~chinese /// @brief 获取夹具列表 FixtureList GetFixtureList() const; @@ -160,23 +151,23 @@ public: /// \~chinese /// @brief 获取旋转角度 - float GetBodyRotation() const; + float GetRotation() const; /// \~chinese /// @brief 设置旋转角度 - void SetBodyRotation(float angle); + void SetRotation(float angle); /// \~chinese /// @brief 获取物体位置 - Point GetBodyPosition() const; + Point GetPosition() const; /// \~chinese /// @brief 设置物体位置 - void SetBodyPosition(Point const& pos); + void SetPosition(Point const& pos); /// \~chinese /// @brief 位置和旋转变换 - void SetBodyTransform(Point const& pos, float angle); + void SetTransform(Point const& pos, float angle); /// \~chinese /// @brief 获取质量 [kg] @@ -297,15 +288,7 @@ public: /// \~chinese /// @brief 获取物体所在物理世界 - World* GetWorld() const; - - /// \~chinese - /// @brief 获取物体绑定的角色 - Actor* GetActor() const; - - /// \~chinese - /// @brief 设置物体绑定的角色 - void SetActor(Actor* actor); + PhysicWorld* GetWorld() const; /// \~chinese /// @brief 将物体信息更新到角色 @@ -315,43 +298,47 @@ public: /// @brief 将角色信息更新到物体 void UpdateFromActor(); - b2Body* GetB2Body() const; - void SetB2Body(b2Body* body); - -private: - /// \~chinese - /// @brief 销毁物体 - void UpdateFixtureFilter(b2Fixture* fixture); - /// \~chinese /// @brief 销毁物体 void Destroy(); + /// \~chinese + /// @brief 获取b2Body + b2Body* GetB2Body() const; + + /// \~chinese + /// @brief 设置b2Body + void SetB2Body(b2Body* body); + +protected: + /// \~chinese + /// @brief 初始化组件 + void InitComponent(Actor* actor) override; + + /// \~chinese + /// @brief 销毁组件 + void DestroyComponent() override; + private: - Actor* actor_; - World* world_; + /// \~chinese + /// @brief 更新夹具过滤器 + void UpdateFixtureFilter(b2Fixture* fixture); + +private: + PhysicWorld* world_; b2Body* body_; - uint16_t category_bits_; - uint16_t mask_bits_; - int16_t group_index_; + uint16_t category_bits_; + uint16_t mask_bits_; + int16_t group_index_; + PhysicBody::Type type_; Vector fixtures_; }; /** @} */ -inline BodyPtr Body::Create(World* world, ActorPtr actor, Type type) -{ - return Body::Create(world, actor.Get(), type); -} - -inline bool Body::InitBody(World* world, ActorPtr actor) -{ - return InitBody(world, actor.Get()); -} - -inline FixtureList Body::GetFixtureList() const +inline FixtureList PhysicBody::GetFixtureList() const { KGE_ASSERT(body_); @@ -362,157 +349,155 @@ inline FixtureList Body::GetFixtureList() const return FixtureList(fixture); } -inline ContactEdgeList Body::GetContactList() const +inline ContactEdgeList PhysicBody::GetContactList() const { KGE_ASSERT(body_); - return ContactEdgeList(ContactEdge(body_->GetContactList())); + ContactEdge edge; + edge.SetB2ContactEdge(body_->GetContactList()); + return ContactEdgeList(edge); } -inline uint16_t Body::GetCategoryBits() const +inline uint16_t PhysicBody::GetCategoryBits() const { return category_bits_; } -inline uint16_t Body::GetMaskBits() const +inline uint16_t PhysicBody::GetMaskBits() const { return mask_bits_; } -inline int16_t Body::GetGroupIndex() const +inline int16_t PhysicBody::GetGroupIndex() const { return group_index_; } -inline float Body::GetBodyRotation() const +inline float PhysicBody::GetRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); } -inline void Body::SetBodyRotation(float angle) +inline void PhysicBody::SetRotation(float angle) { - SetBodyTransform(GetBodyPosition(), angle); + SetTransform(GetPosition(), angle); } -inline void Body::SetBodyPosition(Point const& pos) +inline void PhysicBody::SetPosition(Point const& pos) { - SetBodyTransform(pos, GetBodyRotation()); + SetTransform(pos, GetRotation()); } -inline float Body::GetMass() const +inline float PhysicBody::GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); } -inline float Body::GetInertia() const +inline float PhysicBody::GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); } -inline Body::Type Body::GetType() const +inline PhysicBody::Type PhysicBody::GetType() const { - KGE_ASSERT(body_); - return Type(body_->GetType()); + return type_; } -inline void Body::SetType(Type type) +inline void PhysicBody::SetType(Type type) { - KGE_ASSERT(body_); - body_->SetType(static_cast(type)); + if (type_ != type) + { + type_ = type; + if (body_) + { + body_->SetType(b2BodyType(type)); + } + } } -inline float Body::GetGravityScale() const +inline float PhysicBody::GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); } -inline void Body::SetGravityScale(float scale) +inline void PhysicBody::SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); } -inline bool Body::IsIgnoreRotation() const +inline bool PhysicBody::IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); } -inline void Body::SetIgnoreRotation(bool flag) +inline void PhysicBody::SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); } -inline bool Body::IsBullet() const +inline bool PhysicBody::IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); } -inline void Body::SetBullet(bool flag) +inline void PhysicBody::SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); } -inline bool Body::IsAwake() const +inline bool PhysicBody::IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); } -inline void Body::SetAwake(bool flag) +inline void PhysicBody::SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); } -inline bool Body::IsSleepingAllowed() const +inline bool PhysicBody::IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); } -inline void Body::SetSleepingAllowed(bool flag) +inline void PhysicBody::SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); } -inline bool Body::IsActive() const +inline bool PhysicBody::IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); } -inline void Body::SetActive(bool flag) +inline void PhysicBody::SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); } -inline Actor* Body::GetActor() const -{ - return actor_; -} - -inline void Body::SetActor(Actor* actor) -{ - actor_ = actor; -} - -inline b2Body* Body::GetB2Body() const +inline b2Body* PhysicBody::GetB2Body() const { return body_; } -inline World* Body::GetWorld() const +inline PhysicWorld* PhysicBody::GetWorld() const { return world_; } + } // namespace physics } // namespace kiwano diff --git a/src/kiwano-physics/PhysicWorld.cpp b/src/kiwano-physics/PhysicWorld.cpp new file mode 100644 index 00000000..fcfeadcd --- /dev/null +++ b/src/kiwano-physics/PhysicWorld.cpp @@ -0,0 +1,278 @@ +// Copyright (c) 2018-2019 Kiwano - Nomango +// +// 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 +#include + +namespace kiwano +{ +namespace physics +{ + +class DestructionListener : public b2DestructionListener +{ + Function joint_destruction_callback_; + +public: + DestructionListener(Function callback) + : joint_destruction_callback_(callback) + { + } + + void SayGoodbye(b2Joint* joint) override + { + joint_destruction_callback_(joint); + } + + void SayGoodbye(b2Fixture* fixture) override {} +}; + +class ContactListener : public b2ContactListener +{ + Function dispatcher_; + +public: + ContactListener(Function dispatcher) + : dispatcher_(dispatcher) + { + } + + void BeginContact(b2Contact* b2contact) override + { + Contact contact; + contact.SetB2Contact(b2contact); + + ContactBeginEventPtr evt = new ContactBeginEvent(contact); + dispatcher_(evt.Get()); + } + + void EndContact(b2Contact* b2contact) override + { + PhysicBody* body_a = static_cast(b2contact->GetFixtureA()->GetBody()->GetUserData()); + PhysicBody* body_b = static_cast(b2contact->GetFixtureB()->GetBody()->GetUserData()); + if (!body_a || !body_b || !body_a->GetBoundActor() || !body_b->GetBoundActor()) + { + // Don't dispatch contact event after the body has been detached + return; + } + + Contact contact; + contact.SetB2Contact(b2contact); + + ContactEndEventPtr evt = new ContactEndEvent(contact); + dispatcher_(evt.Get()); + } + + void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override + { + KGE_NOT_USED(contact); + KGE_NOT_USED(oldManifold); + } + void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) override + { + KGE_NOT_USED(contact); + KGE_NOT_USED(impulse); + } +}; + +PhysicWorldPtr PhysicWorld::Create() +{ + PhysicWorldPtr ptr = new (std::nothrow) PhysicWorld; + return ptr; +} + +PhysicWorldPtr PhysicWorld::Create(const Vec2& gravity) +{ + PhysicWorldPtr ptr = new (std::nothrow) PhysicWorld; + if (ptr) + { + ptr->SetGravity(gravity); + } + return ptr; +} + +PhysicWorld::PhysicWorld() + : world_(b2Vec2(0, 10.0f)) + , vel_iter_(6) + , pos_iter_(2) +{ + destroy_listener_ = std::make_unique(Closure(this, &PhysicWorld::JointRemoved)); + world_.SetDestructionListener(destroy_listener_.get()); + + contact_listener_ = std::make_unique(Closure(this, &PhysicWorld::DispatchEvent)); + world_.SetContactListener(contact_listener_.get()); +} + +PhysicWorld::~PhysicWorld() +{ + world_.SetDestructionListener(nullptr); + world_.SetContactListener(nullptr); + + // Make sure b2World was destroyed after b2Body + RemoveAllJoints(); + RemoveAllBodies(); +} + +void PhysicWorld::AddBody(PhysicBodyPtr body) +{ + if (body) + { + bool success = body->Init(this); + KGE_ASSERT(success); + + bodies_.push_back(body); + } +} + +void PhysicWorld::RemoveBody(PhysicBodyPtr body) +{ + if (body) + { + auto iter = std::find(bodies_.begin(), bodies_.end(), body); + if (iter != bodies_.end()) + { + body->Destroy(); + bodies_.erase(iter); + } + } +} + +void PhysicWorld::RemoveAllBodies() +{ + for (auto body : bodies_) + { + body->Destroy(); + } + bodies_.clear(); +} + +const List& PhysicWorld::GetAllBodies() const +{ + return bodies_; +} + +void PhysicWorld::AddJoint(JointPtr joint) +{ + if (joint) + { + bool success = joint->Init(this); + KGE_ASSERT(success); + + joints_.push_back(joint); + } +} + +void PhysicWorld::RemoveJoint(JointPtr joint) +{ + if (joint) + { + auto iter = std::find(joints_.begin(), joints_.end(), joint); + if (iter != joints_.end()) + { + joint->Destroy(); + joints_.erase(iter); + } + } +} + +void PhysicWorld::RemoveAllJoints() +{ + for (auto joint : joints_) + { + joint->Destroy(); + } + joints_.clear(); +} + +const List& PhysicWorld::GetAllJoints() const +{ + return joints_; +} + +b2World* PhysicWorld::GetB2World() +{ + return &world_; +} + +const b2World* PhysicWorld::GetB2World() const +{ + return &world_; +} + +Vec2 PhysicWorld::GetGravity() const +{ + b2Vec2 g = world_.GetGravity(); + return Vec2(g.x, g.y); +} + +void PhysicWorld::SetGravity(Vec2 gravity) +{ + world_.SetGravity(b2Vec2(gravity.x, gravity.y)); +} + +ContactList PhysicWorld::GetContactList() +{ + Contact contact; + contact.SetB2Contact(world_.GetContactList()); + return ContactList(contact); +} + +void PhysicWorld::OnUpdate(Duration dt) +{ + // Update bodies transform from actors + for (auto& body : bodies_) + { + body->UpdateFromActor(); + } + + world_.Step(dt.Seconds(), vel_iter_, pos_iter_); + + // Update actors transform from bodies + for (auto& body : bodies_) + { + if (body->GetType() != PhysicBody::Type::Static) + body->UpdateActor(); + } +} + +void PhysicWorld::DispatchEvent(Event* evt) +{ + Actor* actor = GetBoundActor(); + if (actor) + { + actor->DispatchEvent(evt); + } +} + +void PhysicWorld::JointRemoved(b2Joint* b2joint) +{ + Joint* joint = static_cast(b2joint->GetUserData()); + if (joint) + { + auto iter = std::find(joints_.begin(), joints_.end(), joint); + if (iter != joints_.end()) + { + joints_.erase(iter); + } + } +} + +} // namespace physics +} // namespace kiwano diff --git a/src/kiwano-physics/World.h b/src/kiwano-physics/PhysicWorld.h similarity index 50% rename from src/kiwano-physics/World.h rename to src/kiwano-physics/PhysicWorld.h index 1e635fc4..39843882 100644 --- a/src/kiwano-physics/World.h +++ b/src/kiwano-physics/PhysicWorld.h @@ -19,14 +19,13 @@ // THE SOFTWARE. #pragma once -#include +#include #include namespace kiwano { namespace physics { -KGE_DECLARE_SMART_PTR(World); /** * \~chinese @@ -42,15 +41,56 @@ KGE_DECLARE_SMART_PTR(World); * \~chinese * @brief 物理世界 */ -class KGE_API World : public Stage +class KGE_API PhysicWorld : public Component { - friend class Body; + friend class PhysicBody; friend class Joint; public: - World(); + /// \~chinese + /// @brief 创建物理世界 + static PhysicWorldPtr Create(); - virtual ~World(); + /// \~chinese + /// @brief 创建物理世界 + /// @param gravity 重力 + static PhysicWorldPtr Create(const Vec2& gravity); + + PhysicWorld(); + + virtual ~PhysicWorld(); + + /// \~chinese + /// @brief 添加物体 + void AddBody(PhysicBodyPtr body); + + /// \~chinese + /// @brief 移除物体 + void RemoveBody(PhysicBodyPtr body); + + /// \~chinese + /// @brief 移除所有物体 + void RemoveAllBodies(); + + /// \~chinese + /// @brief 获取所有物体 + const List& GetAllBodies() const; + + /// \~chinese + /// @brief 添加关节 + void AddJoint(JointPtr joint); + + /// \~chinese + /// @brief 移除关节 + void RemoveJoint(JointPtr joint); + + /// \~chinese + /// @brief 移除所有关节 + void RemoveAllJoints(); + + /// \~chinese + /// @brief 获取所有关节 + const List& GetAllJoints() const; /// \~chinese /// @brief 获取重力 [N] @@ -64,36 +104,6 @@ public: /// @brief 获取物理接触列表 ContactList GetContactList(); - /// \~chinese - /// @brief 获取全局缩放比例 - /// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100 - float GetGlobalScale() const; - - /// \~chinese - /// @brief 设置全局缩放比例 - /// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例,默认比例为1:100 - void SetGlobalScale(float scale); - - /// \~chinese - /// @brief 游戏世界单位转换为物理世界单位 - /// @details 根据全局缩放比例将物理世界的单位米转换为像素单位 - float World2Stage(float value) const; - - /// \~chinese - /// @brief 游戏世界单位转换为物理世界单位 - /// @details 根据全局缩放比例将物理世界的单位米转换为像素单位 - Vec2 World2Stage(const b2Vec2& pos) const; - - /// \~chinese - /// @brief 物理世界单位转换为游戏世界单位 - /// @details 根据全局缩放比例将像素单位转换为物理世界的单位米 - float Stage2World(float value) const; - - /// \~chinese - /// @brief 物理世界单位转换为游戏世界单位 - /// @details 根据全局缩放比例将像素单位转换为物理世界的单位米 - b2Vec2 Stage2World(const Vec2& pos) const; - /// \~chinese /// @brief 设置速度迭代次数, 默认为 6 void SetVelocityIterations(int vel_iter); @@ -102,96 +112,44 @@ public: /// @brief 设置位置迭代次数, 默认为 2 void SetPositionIterations(int pos_iter); + /// \~chinese + /// @brief 获取b2World b2World* GetB2World(); + /// \~chinese + /// @brief 获取b2World const b2World* GetB2World() const; -private: - /// \~chinese - /// @brief 移除物体 - void RemoveBody(Body* body); - - /// \~chinese - /// @brief 移除所有物体 - void RemoveAllBodies(); - - /// \~chinese - /// @brief 添加关节 - void AddJoint(Joint* joint); - - /// \~chinese - /// @brief 移除关节 - void RemoveJoint(Joint* joint); - - /// \~chinese - /// @brief 移除所有关节 - void RemoveAllJoints(); - - /// \~chinese - /// @brief 关节被移除 - void JointRemoved(b2Joint* joint); - protected: - void Update(Duration dt) override; + void OnUpdate(Duration dt) override; + + void DispatchEvent(Event* evt); + + void JointRemoved(b2Joint* b2joint); private: b2World world_; int vel_iter_; int pos_iter_; - float global_scale_; - class DestructionListener; - friend DestructionListener; - DestructionListener* destruction_listener_; + List bodies_; + List joints_; - class ContactListener; - friend ContactListener; - ContactListener* contact_listener_; - - bool removing_joint_; - Vector joints_; + std::unique_ptr destroy_listener_; + std::unique_ptr contact_listener_; }; /** @} */ -inline float World::GetGlobalScale() const -{ - return global_scale_; -} - -inline void World::SetGlobalScale(float scale) -{ - global_scale_ = scale; -} - -inline float World::World2Stage(float value) const -{ - return value * GetGlobalScale(); -} - -inline Vec2 World::World2Stage(const b2Vec2& pos) const -{ - return Point(World2Stage(pos.x), World2Stage(pos.y)); -} - -inline float World::Stage2World(float value) const -{ - return value / GetGlobalScale(); -} - -inline b2Vec2 World::Stage2World(const Vec2& pos) const -{ - return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); -} - -inline void World::SetVelocityIterations(int vel_iter) +inline void PhysicWorld::SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; } -inline void World::SetPositionIterations(int pos_iter) +inline void PhysicWorld::SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; } + } // namespace physics } // namespace kiwano diff --git a/src/kiwano-physics/World.cpp b/src/kiwano-physics/World.cpp deleted file mode 100644 index 0f7d8a2a..00000000 --- a/src/kiwano-physics/World.cpp +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) 2018-2019 Kiwano - Nomango -// -// 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 "World.h" - -#include - -namespace kiwano -{ -namespace physics -{ -namespace -{ -const float default_global_scale = 100.f; // 100 pixels per meters -} - -class World::DestructionListener : public b2DestructionListener -{ - World* world_; - -public: - DestructionListener(World* world) - : world_(world) - { - } - - void SayGoodbye(b2Joint* joint) override - { - if (world_) - { - world_->JointRemoved(joint); - } - } - - void SayGoodbye(b2Fixture* fixture) override {} -}; - -class World::ContactListener : public b2ContactListener -{ - World* world_; - -public: - ContactListener(World* world) - : world_(world) - { - } - - void BeginContact(b2Contact* b2contact) override - { - Contact contact; - contact.SetB2Contact(b2contact); - - ContactBeginEventPtr evt = new ContactBeginEvent(contact); - world_->DispatchEvent(evt.Get()); - } - - void EndContact(b2Contact* b2contact) override - { - Contact contact; - contact.SetB2Contact(b2contact); - - ContactEndEventPtr evt = new ContactEndEvent(contact); - world_->DispatchEvent(evt.Get()); - } - - void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override - { - KGE_NOT_USED(contact); - KGE_NOT_USED(oldManifold); - } - void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) override - { - KGE_NOT_USED(contact); - KGE_NOT_USED(impulse); - } -}; - -World::World() - : world_(b2Vec2(0, 10.0f)) - , vel_iter_(6) - , pos_iter_(2) - , global_scale_(default_global_scale) - , destruction_listener_(nullptr) - , contact_listener_(nullptr) - , removing_joint_(false) -{ - destruction_listener_ = new DestructionListener(this); - world_.SetDestructionListener(destruction_listener_); - - contact_listener_ = new ContactListener(this); - world_.SetContactListener(contact_listener_); -} - -World::~World() -{ - world_.SetDestructionListener(nullptr); - if (destruction_listener_) - { - delete destruction_listener_; - destruction_listener_ = nullptr; - } - - world_.SetContactListener(nullptr); - if (contact_listener_) - { - delete contact_listener_; - contact_listener_ = nullptr; - } - - // Make sure b2World was destroyed after b2Body - RemoveAllChildren(); - RemoveAllBodies(); - RemoveAllJoints(); -} - -void World::RemoveBody(Body* body) -{ - if (body && body->GetB2Body()) - { - world_.DestroyBody(body->GetB2Body()); - } -} - -void World::RemoveAllBodies() -{ - if (world_.GetBodyCount()) - { - b2Body* body = world_.GetBodyList(); - while (body) - { - b2Body* next = body->GetNext(); - world_.DestroyBody(body); - body = next; - } - } -} - -void World::AddJoint(Joint* joint) -{ - if (joint) - { - joints_.push_back(joint); - } -} - -void World::RemoveJoint(Joint* joint) -{ - if (joint) - { - auto iter = std::find(joints_.begin(), joints_.end(), joint); - if (iter != joints_.end()) - { - joints_.erase(iter); - - if (joint->GetB2Joint()) - { - removing_joint_ = true; - world_.DestroyJoint(joint->GetB2Joint()); - removing_joint_ = false; - } - } - } -} - -void World::RemoveAllJoints() -{ - if (world_.GetJointCount()) - { - removing_joint_ = true; - { - b2Joint* joint = world_.GetJointList(); - while (joint) - { - b2Joint* next = joint->GetNext(); - world_.DestroyJoint(joint); - joint = next; - } - } - removing_joint_ = false; - } - joints_.clear(); -} - -void World::JointRemoved(b2Joint* joint) -{ - if (!removing_joint_ && joint) - { - auto iter = std::find_if(joints_.begin(), joints_.end(), - [joint](Joint* j) -> bool { return j->GetB2Joint() == joint; }); - - if (iter != joints_.end()) - { - joints_.erase(iter); - } - } -} - -b2World* World::GetB2World() -{ - return &world_; -} - -const b2World* World::GetB2World() const -{ - return &world_; -} - -Vec2 World::GetGravity() const -{ - b2Vec2 g = world_.GetGravity(); - return Vec2(g.x, g.y); -} - -void World::SetGravity(Vec2 gravity) -{ - world_.SetGravity(b2Vec2(gravity.x, gravity.y)); -} - -ContactList World::GetContactList() -{ - Contact contact; - contact.SetB2Contact(world_.GetContactList()); - return ContactList(contact); -} - -void World::Update(Duration dt) -{ - - b2Body* b2body = world_.GetBodyList(); - while (b2body) - { - Body* body = static_cast(b2body->GetUserData()); - if (body && body->GetType() != Body::Type::Static) - { - body->UpdateFromActor(); - } - - b2body = b2body->GetNext(); - } - - world_.Step(dt.Seconds(), vel_iter_, pos_iter_); - - b2body = world_.GetBodyList(); - while (b2body) - { - Body* body = static_cast(b2body->GetUserData()); - if (body && body->GetType() != Body::Type::Static) - { - body->UpdateActor(); - } - - b2body = b2body->GetNext(); - } - - Stage::Update(dt); -} - -} // namespace physics -} // namespace kiwano diff --git a/src/kiwano-physics/kiwano-physics.h b/src/kiwano-physics/kiwano-physics.h index b0e92e43..ebbec21f 100644 --- a/src/kiwano-physics/kiwano-physics.h +++ b/src/kiwano-physics/kiwano-physics.h @@ -20,9 +20,9 @@ #pragma once -#include +#include #include #include #include #include -#include +#include diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 82624667..5e6a53cf 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -68,11 +68,16 @@ Actor::Actor() { } -Actor::~Actor() {} +Actor::~Actor() +{ + RemoveAllComponents(); + RemoveAllChildren(); +} void Actor::Update(Duration dt) { UpdateActions(this, dt); + UpdateComponents(dt); UpdateTimers(dt); if (!update_pausing_) @@ -159,7 +164,7 @@ void Actor::RenderBorder(RenderContext& ctx) for (auto& child : children_) { - child.RenderBorder(ctx); + child->RenderBorder(ctx); } } @@ -221,7 +226,10 @@ bool Actor::HandleEvent(Event* evt) { next = component->GetNext(); - component->HandleEvent(evt); + if (component->IsEnable()) + { + component->HandleEvent(evt); + } } } @@ -273,6 +281,23 @@ bool Actor::HandleEvent(Event* evt) return true; } +void Actor::UpdateComponents(Duration dt) +{ + if (!components_.IsEmpty()) + { + ComponentPtr next; + for (auto component = components_.GetFirst(); component; component = next) + { + next = component->GetNext(); + + if (component->IsEnable()) + { + component->OnUpdate(dt); + } + } + } +} + const Matrix3x2& Actor::GetTransformMatrix() const { UpdateTransform(); @@ -318,7 +343,7 @@ void Actor::UpdateTransform() const // update children's transform for (const auto& child : children_) - child.dirty_transform_ = true; + child->dirty_transform_ = true; } void Actor::UpdateOpacity() @@ -334,7 +359,7 @@ void Actor::UpdateOpacity() for (auto& child : children_) { - child.UpdateOpacity(); + child->UpdateOpacity(); } } @@ -345,7 +370,7 @@ void Actor::SetStage(Stage* stage) stage_ = stage; for (auto& child : children_) { - child.stage_ = stage; + child->stage_ = stage; } } } @@ -356,7 +381,7 @@ void Actor::Reorder() { ActorPtr me = this; - parent_->children_.Remove(me.Get()); + parent_->children_.Remove(me); ActorPtr sibling = parent_->children_.GetLast(); @@ -373,11 +398,11 @@ void Actor::Reorder() if (sibling) { - parent_->children_.InsertAfter(me.Get(), sibling); + parent_->children_.InsertAfter(me, sibling); } else { - parent_->children_.PushFront(me.Get()); + parent_->children_.PushFront(me); } } } @@ -487,7 +512,7 @@ void Actor::SetRotation(float angle) is_fast_transform_ = false; } -void Actor::AddChild(Actor* child, int zorder) +void Actor::AddChild(ActorPtr child, int zorder) { KGE_ASSERT(child && "Actor::AddChild failed, NULL pointer exception"); @@ -519,11 +544,6 @@ void Actor::AddChild(Actor* child, int zorder) } } -void Actor::AddChild(ActorPtr child, int zorder) -{ - AddChild(child.Get()); -} - void Actor::AddChildren(Vector const& children) { for (const auto& actor : children) @@ -549,9 +569,9 @@ Vector Actor::GetChildren(String const& name) const for (const auto& child : children_) { - if (child.hash_name_ == hash_code && child.IsName(name)) + if (child->hash_name_ == hash_code && child->IsName(name)) { - children.push_back(const_cast(&child)); + children.push_back(child); } } return children; @@ -563,9 +583,9 @@ ActorPtr Actor::GetChild(String const& name) const for (const auto& child : children_) { - if (child.hash_name_ == hash_code && child.IsName(name)) + if (child->hash_name_ == hash_code && child->IsName(name)) { - return const_cast(&child); + return child; } } return nullptr; @@ -590,19 +610,15 @@ void Actor::RemoveFromParent() } Component* Actor::AddComponent(ComponentPtr component) -{ - return this->AddComponent(component.Get()); -} - -Component* Actor::AddComponent(Component* component) { KGE_ASSERT(component && "AddComponent failed, NULL pointer exception"); if (component) { + component->InitComponent(this); components_.PushBack(component); } - return component; + return component.Get(); } ComponentList& Actor::GetAllComponents() @@ -615,6 +631,16 @@ const ComponentList& Actor::GetAllComponents() const return components_; } +void Actor::RemoveComponent(ComponentPtr component) +{ + auto iter = std::find(components_.begin(), components_.end(), component); + if (iter != components_.end()) + { + component->DestroyComponent(); + components_.Remove(component); + } +} + void Actor::RemoveComponents(String const& name) { if (!components_.IsEmpty()) @@ -626,6 +652,7 @@ void Actor::RemoveComponents(String const& name) if (component->IsName(name)) { + component->DestroyComponent(); components_.Remove(component); } } @@ -634,15 +661,21 @@ void Actor::RemoveComponents(String const& name) void Actor::RemoveAllComponents() { + // Destroy all components + if (!components_.IsEmpty()) + { + ComponentPtr next; + for (auto component = components_.GetFirst(); component; component = next) + { + next = component->GetNext(); + + component->DestroyComponent(); + } + } components_.Clear(); } void Actor::RemoveChild(ActorPtr child) -{ - RemoveChild(child.Get()); -} - -void Actor::RemoveChild(Actor* child) { KGE_ASSERT(child && "Actor::RemoveChild failed, NULL pointer exception"); diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index 045fc1e0..95f08b40 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -326,10 +326,6 @@ public: /// @brief 添加子角色 void AddChild(ActorPtr child, int zorder = 0); - /// \~chinese - /// @brief 添加子角色 - void AddChild(Actor* child, int zorder = 0); - /// \~chinese /// @brief 添加多个子角色 void AddChildren(Vector const& children); @@ -354,10 +350,6 @@ public: /// @brief 移除子角色 void RemoveChild(ActorPtr child); - /// \~chinese - /// @brief 移除子角色 - void RemoveChild(Actor* child); - /// \~chinese /// @brief 移除所有名称相同的子角色 void RemoveChildren(String const& child_name); @@ -375,11 +367,6 @@ public: /// @param component 组件 Component* AddComponent(ComponentPtr component); - /// \~chinese - /// @brief 添加组件 - /// @param component 组件 - Component* AddComponent(Component* component); - /// \~chinese /// @brief 获取所有组件 ComponentList& GetAllComponents(); @@ -388,6 +375,10 @@ public: /// @brief 获取所有组件 const ComponentList& GetAllComponents() const; + /// \~chinese + /// @brief 移除组件 + void RemoveComponent(ComponentPtr component); + /// \~chinese /// @brief 移除组件 /// @param name 组件名称 @@ -476,6 +467,10 @@ protected: /// @brief 处理事件 bool HandleEvent(Event* evt); + /// \~chinese + /// @brief 更新组件 + void UpdateComponents(Duration dt); + private: bool visible_; bool update_pausing_; diff --git a/src/kiwano/2d/Button.cpp b/src/kiwano/2d/Button.cpp index bcb10afb..6e44f0d0 100644 --- a/src/kiwano/2d/Button.cpp +++ b/src/kiwano/2d/Button.cpp @@ -25,18 +25,17 @@ namespace kiwano { -ButtonPtr Button::Create(ActorPtr actor, Callback const& click) +ButtonPtr Button::Create(Callback const& click) { - return Button::Create(actor, click, nullptr, nullptr, nullptr); + return Button::Create(click, nullptr, nullptr, nullptr); } -ButtonPtr Button::Create(ActorPtr actor, Callback const& click, Callback const& pressed, Callback const& mouse_over, +ButtonPtr Button::Create(Callback const& click, Callback const& pressed, Callback const& mouse_over, Callback const& mouse_out) { ButtonPtr ptr = new (std::nothrow) Button; if (ptr) { - ptr->BindActor(actor); ptr->SetClickCallback(click); ptr->SetPressedCallback(pressed); ptr->SetMouseOverCallback(mouse_over); @@ -46,52 +45,12 @@ ButtonPtr Button::Create(ActorPtr actor, Callback const& click, Callback const& } Button::Button() - : enabled_(true) - , status_(Status::Normal) + : status_(Status::Normal) { } Button::~Button() { - Unbind(); -} - -bool Button::IsEnable() const -{ - return enabled_; -} - -void Button::SetEnabled(bool enabled) -{ - if (enabled_ != enabled) - { - enabled_ = enabled; - } -} - -void Button::SetClickCallback(const Callback& func) -{ - click_callback_ = func; -} - -void Button::SetPressedCallback(const Callback& func) -{ - pressed_callback_ = func; -} - -void Button::SetMouseOverCallback(const Callback& func) -{ - mouse_over_callback_ = func; -} - -void Button::SetMouseOutCallback(const Callback& func) -{ - mouse_out_callback_ = func; -} - -Button::Status Button::GetStatus() const -{ - return status_; } void Button::SetStatus(Status status) @@ -105,7 +64,7 @@ void Button::SetStatus(Status status) Application::GetInstance().GetMainWindow()->SetCursor(CursorType::Arrow); if (mouse_out_callback_) - mouse_out_callback_(this, actor_); + mouse_out_callback_(this, GetBoundActor()); } else if (status == Status::Hover) { @@ -114,24 +73,35 @@ void Button::SetStatus(Status status) if (old_status != Status::Pressed) { if (mouse_over_callback_) - mouse_over_callback_(this, actor_); + mouse_over_callback_(this, GetBoundActor()); } } else if (status == Status::Pressed) { if (pressed_callback_) - pressed_callback_(this, actor_); + pressed_callback_(this, GetBoundActor()); } status_ = status; } } +void Button::InitComponent(Actor* actor) +{ + Component::InitComponent(actor); + if (actor) + { + actor->SetResponsible(true); + } +} + +void Button::DestroyComponent() +{ + Component::DestroyComponent(); +} + void Button::HandleEvent(Event* evt) { - if (!enabled_) - return; - if (evt->IsType()) { SetStatus(Status::Hover); @@ -151,16 +121,7 @@ void Button::HandleEvent(Event* evt) else if (evt->IsType()) { if (click_callback_) - click_callback_(this, actor_); - } -} - -void Button::BindActor(Actor* actor) -{ - Component::BindActor(actor); - if (actor) - { - actor->SetResponsible(true); + click_callback_(this, GetBoundActor()); } } diff --git a/src/kiwano/2d/Button.h b/src/kiwano/2d/Button.h index de41c305..39a4a6b3 100644 --- a/src/kiwano/2d/Button.h +++ b/src/kiwano/2d/Button.h @@ -39,32 +39,22 @@ public: /// \~chinese /// @brief 创建按钮 - /// @param actor 绑定的角色 /// @param click 按钮点击回调函数 - static ButtonPtr Create(ActorPtr actor, Callback const& click); + static ButtonPtr Create(Callback const& click); /// \~chinese /// @brief 创建按钮 - /// @param actor 绑定的角色 /// @param click 按钮点击回调函数 /// @param pressed 按钮按下回调函数 /// @param mouse_over 按钮移入回调函数 /// @param mouse_out 按钮移出回调函数 - static ButtonPtr Create(ActorPtr actor, Callback const& click, Callback const& pressed, Callback const& mouse_over, + static ButtonPtr Create(Callback const& click, Callback const& pressed, Callback const& mouse_over, Callback const& mouse_out); Button(); virtual ~Button(); - /// \~chinese - /// @brief 获取按钮状态是启用还是禁用 - bool IsEnable() const; - - /// \~chinese - /// @brief 设置按钮启用或禁用 - void SetEnabled(bool enabled); - /// \~chinese /// @brief 设置按钮点击后的回调函数 void SetClickCallback(const Callback& func); @@ -81,14 +71,6 @@ public: /// @brief 设置鼠标移出按钮时的回调函数 void SetMouseOutCallback(const Callback& func); - /// \~chinese - /// @brief 绑定到角色 - void BindActor(ActorPtr actor); - - /// \~chinese - /// @brief 绑定到角色 - void BindActor(Actor* actor) override; - protected: /// \~chinese /// @brief 按钮状态 @@ -107,12 +89,19 @@ protected: /// @brief 设置按钮状态 void SetStatus(Status status); + /// \~chinese + /// @brief 初始化组件 + void InitComponent(Actor* actor) override; + + /// \~chinese + /// @brief 销毁组件 + void DestroyComponent() override; + /// \~chinese /// @brief 处理角色事件 void HandleEvent(Event* evt) override; private: - bool enabled_; Status status_; Callback click_callback_; Callback pressed_callback_; @@ -120,9 +109,29 @@ private: Callback mouse_out_callback_; }; -inline void Button::BindActor(ActorPtr actor) +inline void Button::SetClickCallback(const Callback& func) { - this->BindActor(actor.Get()); + click_callback_ = func; +} + +inline void Button::SetPressedCallback(const Callback& func) +{ + pressed_callback_ = func; +} + +inline void Button::SetMouseOverCallback(const Callback& func) +{ + mouse_over_callback_ = func; +} + +inline void Button::SetMouseOutCallback(const Callback& func) +{ + mouse_out_callback_ = func; +} + +inline Button::Status Button::GetStatus() const +{ + return status_; } } // namespace kiwano diff --git a/src/kiwano/2d/Component.cpp b/src/kiwano/2d/Component.cpp index 5af4f3f9..a22a9c22 100644 --- a/src/kiwano/2d/Component.cpp +++ b/src/kiwano/2d/Component.cpp @@ -19,32 +19,36 @@ // THE SOFTWARE. #include +#include namespace kiwano { Component::Component() - : actor_(nullptr) + : enabled_(true) + , actor_(nullptr) { } -Component::~Component() -{ - Unbind(); -} +Component::~Component() {} -void Component::BindActor(Actor* actor) +void Component::InitComponent(Actor* actor) { - if (actor_) - { - Unbind(); - } actor_ = actor; } -void Component::Unbind() +void Component::DestroyComponent() { actor_ = nullptr; } +void Component::RemoveFromActor() +{ + if (actor_) + { + actor_->RemoveComponent(this); + actor_ = nullptr; + } +} + } // namespace kiwano diff --git a/src/kiwano/2d/Component.h b/src/kiwano/2d/Component.h index 6c9045e0..3fb2f6b0 100644 --- a/src/kiwano/2d/Component.h +++ b/src/kiwano/2d/Component.h @@ -19,6 +19,7 @@ // THE SOFTWARE. #pragma once +#include #include #include @@ -47,35 +48,67 @@ class KGE_API Component public: /// \~chinese - /// @brief 绑定到角色 - virtual void BindActor(Actor* actor); + /// @brief 是否启用组件 + bool IsEnable() const; /// \~chinese - /// @brief 取消绑定到角色 - virtual void Unbind(); + /// @brief 设置组件启用或禁用 + void SetEnabled(bool enabled); /// \~chinese /// @brief 获取绑定的角色 Actor* GetBoundActor() const; + /// \~chinese + /// @brief 从角色中移除 + void RemoveFromActor(); + protected: Component(); virtual ~Component(); + /// \~chinese + /// @brief 初始化组件 + virtual void InitComponent(Actor* actor); + + /// \~chinese + /// @brief 销毁组件 + virtual void DestroyComponent(); + + /// \~chinese + /// @brief 更新组件 + virtual void OnUpdate(Duration dt); + /// \~chinese /// @brief 处理角色事件 virtual void HandleEvent(Event* evt); -protected: +private: + bool enabled_; Actor* actor_; }; +inline bool Component::IsEnable() const +{ + return enabled_; +} + +inline void Component::SetEnabled(bool enabled) +{ + enabled_ = enabled; +} + inline Actor* Component::GetBoundActor() const { return actor_; } +inline void Component::OnUpdate(Duration dt) +{ + KGE_NOT_USED(dt); +} + inline void Component::HandleEvent(Event* event) { KGE_NOT_USED(event); diff --git a/src/kiwano/2d/TextActor.cpp b/src/kiwano/2d/TextActor.cpp index 5a8e2169..63f6e00f 100644 --- a/src/kiwano/2d/TextActor.cpp +++ b/src/kiwano/2d/TextActor.cpp @@ -27,12 +27,7 @@ namespace kiwano TextActorPtr TextActor::Create(const String& text) { - TextActorPtr ptr = new (std::nothrow) TextActor; - if (ptr) - { - ptr->SetText(text); - } - return ptr; + return TextActor::Create(text, TextStyle()); } TextActorPtr TextActor::Create(const String& text, const TextStyle& style) @@ -48,7 +43,6 @@ TextActorPtr TextActor::Create(const String& text, const TextStyle& style) TextActor::TextActor() { - layout_ = TextLayout::Create(); } TextActor::~TextActor() {} @@ -69,13 +63,18 @@ Size TextActor::GetSize() const void TextActor::SetText(String const& text) { + if (!layout_) + { + layout_ = TextLayout::Create(); + } layout_->Reset(text, style_); } void TextActor::SetStyle(const TextStyle& style) { style_ = style; - layout_->Reset(style); + if (layout_) + layout_->Reset(style); } void TextActor::SetFont(FontPtr font) @@ -83,7 +82,8 @@ void TextActor::SetFont(FontPtr font) if (style_.font != font) { style_.font = font; - layout_->SetFont(font, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetFont(font, { 0, layout_->GetContentLength() }); } } @@ -92,7 +92,8 @@ void TextActor::SetFontFamily(String const& family) if (style_.font_family != family) { style_.font_family = family; - layout_->SetFontFamily(family, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetFontFamily(family, { 0, layout_->GetContentLength() }); } } @@ -101,7 +102,8 @@ void TextActor::SetFontSize(float size) if (style_.font_size != size) { style_.font_size = size; - layout_->SetFontSize(size, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetFontSize(size, { 0, layout_->GetContentLength() }); } } @@ -110,7 +112,8 @@ void TextActor::SetFontWeight(uint32_t weight) if (style_.font_weight != weight) { style_.font_weight = weight; - layout_->SetFontWeight(weight, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetFontWeight(weight, { 0, layout_->GetContentLength() }); } } @@ -119,7 +122,8 @@ void TextActor::SetItalic(bool italic) if (style_.italic != italic) { style_.italic = italic; - layout_->SetItalic(italic, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetItalic(italic, { 0, layout_->GetContentLength() }); } } @@ -128,7 +132,8 @@ void TextActor::SetUnderline(bool enable) if (style_.show_underline != enable) { style_.show_underline = enable; - layout_->SetUnderline(enable, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetUnderline(enable, { 0, layout_->GetContentLength() }); } } @@ -137,7 +142,8 @@ void TextActor::SetStrikethrough(bool enable) if (style_.show_strikethrough != enable) { style_.show_strikethrough = enable; - layout_->SetStrikethrough(enable, { 0, layout_->GetContentLength() }); + if (layout_) + layout_->SetStrikethrough(enable, { 0, layout_->GetContentLength() }); } } @@ -146,7 +152,8 @@ void TextActor::SetWrapWidth(float wrap_width) if (style_.wrap_width != wrap_width) { style_.wrap_width = wrap_width; - layout_->SetWrapWidth(wrap_width); + if (layout_) + layout_->SetWrapWidth(wrap_width); } } @@ -155,7 +162,8 @@ void TextActor::SetLineSpacing(float line_spacing) if (style_.line_spacing != line_spacing) { style_.line_spacing = line_spacing; - layout_->SetLineSpacing(line_spacing); + if (layout_) + layout_->SetLineSpacing(line_spacing); } } @@ -164,7 +172,8 @@ void TextActor::SetAlignment(TextAlign align) if (style_.alignment != align) { style_.alignment = align; - layout_->SetAlignment(align); + if (layout_) + layout_->SetAlignment(align); } } @@ -173,7 +182,8 @@ void TextActor::SetFillBrush(BrushPtr brush) if (style_.fill_brush != brush) { style_.fill_brush = brush; - layout_->SetDefaultFillBrush(brush); + if (layout_) + layout_->SetDefaultFillBrush(brush); } } @@ -182,7 +192,8 @@ void TextActor::SetOutlineBrush(BrushPtr brush) if (style_.outline_brush != brush) { style_.outline_brush = brush; - layout_->SetDefaultOutlineBrush(brush); + if (layout_) + layout_->SetDefaultOutlineBrush(brush); } } @@ -191,7 +202,8 @@ void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke) if (style_.outline_stroke != stroke) { style_.outline_stroke = stroke; - layout_->SetDefaultOutlineStrokeStyle(stroke); + if (layout_) + layout_->SetDefaultOutlineStrokeStyle(stroke); } } @@ -221,8 +233,6 @@ void TextActor::SetOutlineColor(Color const& outline_color) void TextActor::SetTextLayout(TextLayoutPtr layout) { - KGE_ASSERT(layout && "TextLayout must not be nullptr"); - if (layout_ != layout) { layout_ = layout; @@ -243,8 +253,7 @@ bool TextActor::CheckVisibility(RenderContext& ctx) const void TextActor::UpdateDirtyLayout() { - KGE_ASSERT(layout_); - if (layout_->UpdateWhenDirty()) + if (layout_ && layout_->UpdateWhenDirty()) { ForceUpdateLayout(); } @@ -252,10 +261,15 @@ void TextActor::UpdateDirtyLayout() void TextActor::ForceUpdateLayout() { - KGE_ASSERT(layout_); - - layout_->UpdateWhenDirty(); - SetSize(layout_->GetSize()); + if (layout_) + { + layout_->UpdateWhenDirty(); + SetSize(layout_->GetSize()); + } + else + { + SetSize(Size()); + } } } // namespace kiwano diff --git a/src/kiwano/2d/TextActor.h b/src/kiwano/2d/TextActor.h index 00d85277..62517df3 100644 --- a/src/kiwano/2d/TextActor.h +++ b/src/kiwano/2d/TextActor.h @@ -56,11 +56,11 @@ public: /// \~chinese /// @brief 获取文本 - const String& GetText() const; + String GetText() const; /// \~chinese /// @brief 获取文本样式 - const TextStyle& GetStyle() const; + TextStyle GetStyle() const; /// \~chinese /// @brief 获取文本布局 @@ -182,10 +182,13 @@ private: /** @} */ -inline const String& TextActor::GetText() const +inline String TextActor::GetText() const { - KGE_ASSERT(layout_); - return layout_->GetContent(); + if (layout_) + { + return layout_->GetContent(); + } + return String(); } inline FontPtr TextActor::GetFont() const @@ -193,7 +196,7 @@ inline FontPtr TextActor::GetFont() const return style_.font; } -inline const TextStyle& TextActor::GetStyle() const +inline TextStyle TextActor::GetStyle() const { return style_; } diff --git a/src/kiwano/2d/action/ActionManager.cpp b/src/kiwano/2d/action/ActionManager.cpp index 52ec1acd..a23e5818 100644 --- a/src/kiwano/2d/action/ActionManager.cpp +++ b/src/kiwano/2d/action/ActionManager.cpp @@ -43,11 +43,6 @@ void ActionManager::UpdateActions(Actor* target, Duration dt) } Action* ActionManager::AddAction(ActionPtr action) -{ - return AddAction(action.Get()); -} - -Action* ActionManager::AddAction(Action* action) { KGE_ASSERT(action && "AddAction failed, NULL pointer exception"); @@ -55,7 +50,7 @@ Action* ActionManager::AddAction(Action* action) { actions_.PushBack(action); } - return action; + return action.Get(); } void ActionManager::ResumeAllActions() @@ -65,7 +60,7 @@ void ActionManager::ResumeAllActions() for (auto& action : actions_) { - action.Resume(); + action->Resume(); } } @@ -76,7 +71,7 @@ void ActionManager::PauseAllActions() for (auto& action : actions_) { - action.Pause(); + action->Pause(); } } @@ -87,7 +82,7 @@ void ActionManager::StopAllActions() for (auto& action : actions_) { - action.Stop(); + action->Stop(); } } @@ -97,9 +92,8 @@ ActionPtr ActionManager::GetAction(String const& name) return nullptr; for (auto& action : actions_) - if (action.IsName(name)) - return &action; - + if (action->IsName(name)) + return action; return nullptr; } diff --git a/src/kiwano/2d/action/ActionManager.h b/src/kiwano/2d/action/ActionManager.h index 2334bd2e..0ffcf412 100644 --- a/src/kiwano/2d/action/ActionManager.h +++ b/src/kiwano/2d/action/ActionManager.h @@ -39,10 +39,6 @@ public: /// @brief 添加动画 Action* AddAction(ActionPtr action); - /// \~chinese - /// @brief 添加动画 - Action* AddAction(Action* action); - /// \~chinese /// @brief 继续所有暂停动画 void ResumeAllActions(); diff --git a/src/kiwano/core/EventDispatcher.cpp b/src/kiwano/core/EventDispatcher.cpp index 286ca092..8904ecf7 100644 --- a/src/kiwano/core/EventDispatcher.cpp +++ b/src/kiwano/core/EventDispatcher.cpp @@ -46,11 +46,6 @@ bool EventDispatcher::DispatchEvent(Event* evt) } EventListener* EventDispatcher::AddListener(EventListenerPtr listener) -{ - return AddListener(listener.Get()); -} - -EventListener* EventDispatcher::AddListener(EventListener* listener) { KGE_ASSERT(listener && "AddListener failed, NULL pointer exception"); @@ -58,7 +53,7 @@ EventListener* EventDispatcher::AddListener(EventListener* listener) { listeners_.PushBack(listener); } - return listener; + return listener.Get(); } EventListener* EventDispatcher::AddListener(String const& name, EventType type, EventListener::Callback callback) @@ -77,9 +72,9 @@ void EventDispatcher::StartListeners(String const& name) { for (auto& listener : listeners_) { - if (listener.IsName(name)) + if (listener->IsName(name)) { - listener.Start(); + listener->Start(); } } } @@ -88,9 +83,9 @@ void EventDispatcher::StopListeners(String const& name) { for (auto& listener : listeners_) { - if (listener.IsName(name)) + if (listener->IsName(name)) { - listener.Stop(); + listener->Stop(); } } } @@ -99,9 +94,9 @@ void EventDispatcher::RemoveListeners(String const& name) { for (auto& listener : listeners_) { - if (listener.IsName(name)) + if (listener->IsName(name)) { - listener.Remove(); + listener->Remove(); } } } @@ -110,9 +105,9 @@ void EventDispatcher::StartListeners(const EventType& type) { for (auto& listener : listeners_) { - if (listener.GetEventType() == type) + if (listener->GetEventType() == type) { - listener.Start(); + listener->Start(); } } } @@ -121,9 +116,9 @@ void EventDispatcher::StopListeners(const EventType& type) { for (auto& listener : listeners_) { - if (listener.GetEventType() == type) + if (listener->GetEventType() == type) { - listener.Stop(); + listener->Stop(); } } } @@ -132,9 +127,9 @@ void EventDispatcher::RemoveListeners(const EventType& type) { for (auto& listener : listeners_) { - if (listener.GetEventType() == type) + if (listener->GetEventType() == type) { - listener.Remove(); + listener->Remove(); } } } @@ -143,7 +138,7 @@ void EventDispatcher::StartAllListeners() { for (auto& listener : listeners_) { - listener.Start(); + listener->Start(); } } @@ -151,7 +146,7 @@ void EventDispatcher::StopAllListeners() { for (auto& listener : listeners_) { - listener.Stop(); + listener->Stop(); } } @@ -159,7 +154,7 @@ void EventDispatcher::RemoveAllListeners() { for (auto& listener : listeners_) { - listener.Remove(); + listener->Remove(); } } diff --git a/src/kiwano/core/EventDispatcher.h b/src/kiwano/core/EventDispatcher.h index 741e8d4d..9876071e 100644 --- a/src/kiwano/core/EventDispatcher.h +++ b/src/kiwano/core/EventDispatcher.h @@ -34,10 +34,6 @@ public: /// @brief 添加监听器 EventListener* AddListener(EventListenerPtr listener); - /// \~chinese - /// @brief 添加监听器 - EventListener* AddListener(EventListener* listener); - /// \~chinese /// @brief 添加监听器 /// @param type 监听的事件类型 diff --git a/src/kiwano/core/IntrusiveList.h b/src/kiwano/core/IntrusiveList.h index 04e73dff..5e14170c 100644 --- a/src/kiwano/core/IntrusiveList.h +++ b/src/kiwano/core/IntrusiveList.h @@ -33,8 +33,8 @@ template class IntrusiveList { public: - using value_type = typename std::pointer_traits<_PtrTy>::element_type; - using pointer = typename std::pointer_traits<_PtrTy>::pointer; + using value_type = typename std::pointer_traits<_PtrTy>::pointer; + using pointer = value_type*; using reference = value_type&; IntrusiveList() @@ -50,28 +50,28 @@ public: /// \~chinese /// @brief 获取首元素 - const pointer GetFirst() const + const value_type& GetFirst() const { return first_; } /// \~chinese /// @brief 获取首元素 - pointer GetFirst() + value_type& GetFirst() { return first_; } /// \~chinese /// @brief 获取尾元素 - const pointer GetLast() const + const value_type& GetLast() const { return last_; } /// \~chinese /// @brief 获取尾元素 - pointer GetLast() + value_type& GetLast() { return last_; } @@ -85,7 +85,7 @@ public: /// \~chinese /// @brief 在链表尾部添加对象 - void PushBack(pointer child) + void PushBack(reference child) { if (child->prev_) child->prev_->next_ = child->next_; @@ -109,7 +109,7 @@ public: /// \~chinese /// @brief 在链表头部添加对象 - void PushFront(pointer child) + void PushFront(reference child) { if (child->prev_) child->prev_->next_ = child->next_; @@ -133,7 +133,7 @@ public: /// \~chinese /// @brief 在链表的对象前插入新对象 - void InsertBefore(pointer child, pointer before) + void InsertBefore(reference child, reference before) { if (child->prev_) child->prev_->next_ = child->next_; @@ -152,7 +152,7 @@ public: /// \~chinese /// @brief 在链表的对象后插入新对象 - void InsertAfter(pointer child, pointer after) + void InsertAfter(reference child, reference after) { if (child->prev_) child->prev_->next_ = child->next_; @@ -171,7 +171,7 @@ public: /// \~chinese /// @brief 移除对象 - void Remove(pointer child) + void Remove(reference child) { if (child->next_) { @@ -199,10 +199,10 @@ public: /// @brief 清空所有对象 void Clear() { - pointer p = first_; + value_type p = first_; while (p) { - pointer tmp = p; + value_type tmp = p; p = p->next_; if (tmp) { @@ -222,8 +222,9 @@ public: return true; int pos = 0; - pointer p = first_; - pointer tmp = p; + + value_type p = first_; + value_type tmp = p; do { tmp = p; @@ -245,42 +246,36 @@ public: } public: - template + template struct Iterator { using iterator_category = std::bidirectional_iterator_tag; - using pointer = _PTy; - using reference = typename IntrusiveList::reference; + using value_type = _PtrTy; + using pointer = _PtrTy*; + using reference = _PtrTy&; using difference_type = ptrdiff_t; - inline Iterator(pointer ptr = nullptr, bool is_end = false) + inline Iterator(value_type ptr = nullptr, bool is_end = false) : base_(ptr) , is_end_(is_end) { } - inline pointer Get() const - { - KGE_ASSERT(!is_end_); - return const_cast(base_); - } - inline reference operator*() const { KGE_ASSERT(base_ && !is_end_); - return const_cast(*base_); + return const_cast(base_); } inline pointer operator->() const { - KGE_ASSERT(base_ && !is_end_); - return const_cast(base_); + return std::pointer_traits::pointer_to(**this); } inline Iterator& operator++() { KGE_ASSERT(base_ && !is_end_); - pointer next = base_->GetNext(); + value_type next = base_->GetNext(); if (next) base_ = next; else @@ -330,12 +325,12 @@ public: private: bool is_end_; - typename IntrusiveList::pointer base_; + typename std::remove_const::type base_; }; public: - using iterator = Iterator; - using const_iterator = Iterator; + using iterator = Iterator; + using const_iterator = Iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; @@ -399,28 +394,28 @@ public: return rend(); } - inline pointer front() + inline value_type& front() { if (IsEmpty()) throw std::out_of_range("front() called on empty list"); return first_; } - inline const pointer front() const + inline const value_type& front() const { if (IsEmpty()) throw std::out_of_range("front() called on empty list"); return first_; } - inline pointer back() + inline value_type& back() { if (IsEmpty()) throw std::out_of_range("back() called on empty list"); return last_; } - inline const pointer back() const + inline const value_type& back() const { if (IsEmpty()) throw std::out_of_range("back() called on empty list"); @@ -428,8 +423,8 @@ public: } private: - pointer first_; - pointer last_; + value_type first_; + value_type last_; }; @@ -439,7 +434,9 @@ template class IntrusiveListValue { public: - using pointer = typename std::pointer_traits<_PtrTy>::pointer; + using value_type = typename std::pointer_traits<_PtrTy>::pointer; + using reference = value_type&; + using pointer = value_type*; IntrusiveListValue() : prev_(nullptr) @@ -447,7 +444,7 @@ public: { } - IntrusiveListValue(pointer rhs) + IntrusiveListValue(value_type rhs) : prev_(nullptr) , next_(nullptr) { @@ -460,35 +457,35 @@ public: /// \~chinese /// @brief 获取前一元素 - const pointer GetPrev() const + const value_type& GetPrev() const { return prev_; } /// \~chinese /// @brief 获取前一元素 - pointer GetPrev() + value_type& GetPrev() { return prev_; } /// \~chinese /// @brief 获取下一元素 - const pointer GetNext() const + const value_type& GetNext() const { return next_; } /// \~chinese /// @brief 获取下一元素 - pointer GetNext() + value_type& GetNext() { return next_; } private: - pointer prev_; - pointer next_; + value_type prev_; + value_type next_; friend class IntrusiveList<_PtrTy>; }; diff --git a/src/kiwano/core/TimerManager.cpp b/src/kiwano/core/TimerManager.cpp index 44d747b9..b3d05a9c 100644 --- a/src/kiwano/core/TimerManager.cpp +++ b/src/kiwano/core/TimerManager.cpp @@ -71,9 +71,9 @@ void TimerManager::StopTimers(String const& name) for (auto& timer : timers_) { - if (timer.IsName(name)) + if (timer->IsName(name)) { - timer.Stop(); + timer->Stop(); } } } @@ -85,9 +85,9 @@ void TimerManager::StartTimers(String const& name) for (auto& timer : timers_) { - if (timer.IsName(name)) + if (timer->IsName(name)) { - timer.Start(); + timer->Start(); } } } @@ -99,9 +99,9 @@ void TimerManager::RemoveTimers(String const& name) for (auto& timer : timers_) { - if (timer.IsName(name)) + if (timer->IsName(name)) { - timer.Remove(); + timer->Remove(); } } } @@ -113,7 +113,7 @@ void TimerManager::StopAllTimers() for (auto& timer : timers_) { - timer.Stop(); + timer->Stop(); } } @@ -124,7 +124,7 @@ void TimerManager::StartAllTimers() for (auto& timer : timers_) { - timer.Start(); + timer->Start(); } } diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 5ad04f40..ca29f4d4 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -63,17 +63,17 @@ void Application::Run(RunnerPtr runner, bool debug) } // Everything is ready - runner->OnReady(); - runner->SetLastUpdateTime(Time::Now()); + runner->Ready(); quiting_ = false; while (!quiting_) { - quiting_ = !runner->MainLoop(); + if (!runner->MainLoop()) + quiting_ = true; } // Destroy all resources - runner->OnDestroy(); + runner->Destroy(); this->Destroy(); } diff --git a/src/kiwano/platform/Runner.cpp b/src/kiwano/platform/Runner.cpp index 55a3fdfe..ec915ba0 100644 --- a/src/kiwano/platform/Runner.cpp +++ b/src/kiwano/platform/Runner.cpp @@ -58,7 +58,7 @@ RunnerPtr Runner::Create(WindowPtr main_window, Function on_ready, Funct SmartPtr ptr = new (std::nothrow) CallbackRunner; if (ptr) { - ptr->on_ready = on_ready; + ptr->on_ready = on_ready; ptr->on_destroy = on_destroy; ptr->SetMainWindow(main_window); } @@ -97,4 +97,21 @@ bool Runner::MainLoop() return true; } +void Runner::Ready() +{ + OnReady(); + last_update_time_ = Time::Now(); +} + +void Runner::Destroy() +{ + OnDestroy(); + + if (main_window_) + { + main_window_->Destroy(); + main_window_.Reset(); + } +} + } // namespace kiwano diff --git a/src/kiwano/platform/Runner.h b/src/kiwano/platform/Runner.h index 7f4d5f51..6b22016f 100644 --- a/src/kiwano/platform/Runner.h +++ b/src/kiwano/platform/Runner.h @@ -26,6 +26,8 @@ namespace kiwano { +class Application; + KGE_DECLARE_SMART_PTR(Runner); /** @@ -34,6 +36,8 @@ KGE_DECLARE_SMART_PTR(Runner); */ class KGE_API Runner : public virtual ObjectBase { + friend class Application; + public: /// \~chinese /// @brief 创建程序运行器 @@ -85,9 +89,10 @@ public: /// @brief 获取上一次更新时间 Time GetLastUpdateTime() const; - /// \~chinese - /// @brief 设置上一次更新时间 - void SetLastUpdateTime(Time time); +private: + void Ready(); + + void Destroy(); private: WindowPtr main_window_; @@ -118,9 +123,4 @@ inline Time Runner::GetLastUpdateTime() const return last_update_time_; } -inline void Runner::SetLastUpdateTime(Time time) -{ - last_update_time_ = time; -} - } // namespace kiwano diff --git a/src/kiwano/platform/Window.cpp b/src/kiwano/platform/Window.cpp index 35ccc97e..e784c7cb 100644 --- a/src/kiwano/platform/Window.cpp +++ b/src/kiwano/platform/Window.cpp @@ -33,7 +33,6 @@ Window::Window() Window::~Window() { - Destroy(); } EventPtr Window::PollEvent()