Add Button, PhysicWorld, PhysicBody components

This commit is contained in:
Nomango 2020-02-19 11:50:05 +08:00
parent 9077c55b9c
commit fcc55bac81
38 changed files with 1907 additions and 1774 deletions

View File

@ -11,24 +11,25 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\kiwano-physics\Body.h" />
<ClInclude Include="..\..\src\kiwano-physics\PhysicBody.h" />
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEdge.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEvent.h" />
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
<ClInclude Include="..\..\src\kiwano-physics\helper.h" />
<ClInclude Include="..\..\src\kiwano-physics\Global.h" />
<ClInclude Include="..\..\src\kiwano-physics\Joint.h" />
<ClInclude Include="..\..\src\kiwano-physics\kiwano-physics.h" />
<ClInclude Include="..\..\src\kiwano-physics\World.h" />
<ClInclude Include="..\..\src\kiwano-physics\PhysicWorld.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\PhysicBody.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEdge.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEvent.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Global.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Joint.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\World.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\PhysicWorld.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{DF599AFB-744F-41E5-AF0C-2146F90575C8}</ProjectGuid>

View File

@ -2,22 +2,23 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="..\..\src\kiwano-physics\kiwano-physics.h" />
<ClInclude Include="..\..\src\kiwano-physics\Body.h" />
<ClInclude Include="..\..\src\kiwano-physics\World.h" />
<ClInclude Include="..\..\src\kiwano-physics\Joint.h" />
<ClInclude Include="..\..\src\kiwano-physics\helper.h" />
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEvent.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactEdge.h" />
<ClInclude Include="..\..\src\kiwano-physics\Global.h" />
<ClInclude Include="..\..\src\kiwano-physics\PhysicBody.h" />
<ClInclude Include="..\..\src\kiwano-physics\PhysicWorld.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\World.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Joint.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEvent.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactEdge.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Global.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\PhysicBody.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\PhysicWorld.cpp" />
</ItemGroup>
</Project>

View File

@ -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 <kiwano-physics/Body.h>
#include <kiwano-physics/World.h>
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<Point> 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<Point> 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

View File

@ -18,9 +18,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano-physics/Body.h>
#include <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/World.h>
#include <kiwano-physics/PhysicWorld.h>
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

View File

@ -20,13 +20,11 @@
#pragma once
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/helper.h>
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 <typename _Ty>
class IteratorImpl : public std::iterator<std::forward_iterator_tag, _Ty>
class IteratorImpl
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
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<typename herit::reference>(elem_);
return const_cast<reference>(elem_);
}
inline typename herit::pointer operator->() const
inline pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
return std::pointer_traits<pointer>::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_;

View File

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

View File

@ -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 <typename _Ty>
class IteratorImpl : public std::iterator<std::forward_iterator_tag, _Ty>
class IteratorImpl
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
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<typename herit::reference>(elem_);
return const_cast<reference>(elem_);
}
inline typename herit::pointer operator->() const
inline pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
return std::pointer_traits<pointer>::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<Body*>(edge_->other->GetUserData());
}
inline Contact ContactEdge::GetContact() const
{
KGE_ASSERT(edge_);
Contact contact;
contact.SetB2Contact(edge_->contact);
return contact;
return static_cast<PhysicBody*>(edge_->other->GetUserData());
}
inline b2ContactEdge* ContactEdge::GetB2ContactEdge() const

View File

@ -19,7 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/Body.h>
#include <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/Contact.h>
namespace kiwano

View File

@ -18,127 +18,111 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano-physics/Body.h>
#include <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/World.h>
#include <kiwano-physics/PhysicWorld.h>
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<b2CircleShape>();
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<b2PolygonShape>();
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<Point> const& vertexs)
{
FixturePtr ptr = new (std::nothrow) Fixture;
if (ptr)
{
Vector<b2Vec2> 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<b2PolygonShape>();
shape->Set(&b2vertexs[0], static_cast<int32>(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<Point> const& vertexs)
{
KGE_ASSERT(body);
World* world = body->GetWorld();
Vector<b2Vec2> 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<b2EdgeShape>();
shape->Set(start, end);
ptr->shape_ = std::move(shape);
ptr->param_ = param;
}
b2PolygonShape shape;
shape.Set(&b2vertexs[0], static_cast<int32>(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<Point> 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<Point> const& vertexs, bool loop)
{
KGE_ASSERT(body);
World* world = body->GetWorld();
Vector<b2Vec2> 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<b2Vec2> 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<int32>(b2vertexs.size()));
auto shape = std::make_unique<b2ChainShape>();
if (loop)
{
shape->CreateLoop(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
}
else
{
shape->CreateChain(&b2vertexs[0], static_cast<int32>(b2vertexs.size()));
}
ptr->shape_ = std::move(shape);
ptr->param_ = param;
}
else
{
shape.CreateChain(&b2vertexs[0], static_cast<int32>(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<Body*>(fixture_->GetBody()->GetUserData());
return static_cast<PhysicBody*>(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

View File

@ -19,13 +19,13 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/helper.h>
#include <memory>
#include <kiwano-physics/Global.h>
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<Point> const& vertexs);
static FixturePtr CreatePolygon(Param const& param, Vector<Point> 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<Point> const& vertexs, bool loop = false);
static FixturePtr CreateChain(Param const& param, Vector<Point> 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<b2Shape> shape_;
Fixture::Param param_;
};
/// \~chinese
@ -169,13 +178,14 @@ private:
class FixtureList
{
template <typename _Ty>
class IteratorImpl : public std::iterator<std::forward_iterator_tag, _Ty>
class IteratorImpl
{
using herit = std::iterator<std::forward_iterator_tag, _Ty>;
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<typename herit::reference>(*elem_);
return const_cast<reference>(*elem_);
}
inline pointer operator->() const
{
return std::pointer_traits<typename herit::pointer>::pointer_to(**this);
return std::pointer_traits<pointer>::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<value_type>;
using const_iterator = IteratorImpl<const value_type>;
@ -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

View File

@ -19,22 +19,51 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/kiwano.h>
// Box2D
#include <3rd-party/Box2D/Box2D.h>
#include <kiwano-physics/Global.h>
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

View File

@ -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 <kiwano/kiwano.h>
// 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

View File

@ -19,7 +19,7 @@
// THE SOFTWARE.
#include <kiwano-physics/Joint.h>
#include <kiwano-physics/World.h>
#include <kiwano-physics/PhysicWorld.h>
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*>(body->GetUserData()));
return PhysicBodyPtr(static_cast<PhysicBody*>(body->GetUserData()));
}
BodyPtr Joint::GetBodyB() const
PhysicBodyPtr Joint::GetBodyB() const
{
KGE_ASSERT(joint_);
b2Body* body = joint_->GetBodyB();
return BodyPtr(static_cast<Body*>(body->GetUserData()));
return PhysicBodyPtr(static_cast<PhysicBody*>(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<b2DistanceJoint*>(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<b2FrictionJoint*>(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<b2GearJoint*>(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<b2MotorJoint*>(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<b2PrismaticJoint*>(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<b2PulleyJoint*>(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<b2RevoluteJoint*>(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<b2RopeJoint*>(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<b2WeldJoint*>(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<b2WheelJoint*>(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<b2MouseJoint*>(GetB2Joint());
return raw_joint_ != nullptr;
}

View File

@ -19,8 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/Body.h>
#include <kiwano-physics/helper.h>
#include <kiwano-physics/PhysicBody.h>
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_;
}

View File

@ -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 <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/PhysicWorld.h>
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<Point> 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<Point> 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

View File

@ -19,17 +19,13 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/ContactEdge.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/helper.h>
#include <kiwano-physics/ContactEdge.h>
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<Point> const& vertexs, float density, float friction = 0.2f,
float restitution = 0.f, bool is_sensor = false);
Fixture* AddPolygonShape(Vector<Point> 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<Point> const& vertexs, bool loop, float density, float friction = 0.2f,
float restitution = 0.f, bool is_sensor = false);
Fixture* AddChainShape(Vector<Point> 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<FixturePtr> 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<b2BodyType>(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

View File

@ -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 <kiwano-physics/PhysicWorld.h>
#include <kiwano-physics/ContactEvent.h>
namespace kiwano
{
namespace physics
{
class DestructionListener : public b2DestructionListener
{
Function<void(b2Joint*)> joint_destruction_callback_;
public:
DestructionListener(Function<void(b2Joint*)> callback)
: joint_destruction_callback_(callback)
{
}
void SayGoodbye(b2Joint* joint) override
{
joint_destruction_callback_(joint);
}
void SayGoodbye(b2Fixture* fixture) override {}
};
class ContactListener : public b2ContactListener
{
Function<void(Event*)> dispatcher_;
public:
ContactListener(Function<void(Event*)> 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<PhysicBody*>(b2contact->GetFixtureA()->GetBody()->GetUserData());
PhysicBody* body_b = static_cast<PhysicBody*>(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<DestructionListener>(Closure(this, &PhysicWorld::JointRemoved));
world_.SetDestructionListener(destroy_listener_.get());
contact_listener_ = std::make_unique<ContactListener>(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<PhysicBodyPtr>& 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<JointPtr>& 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<Joint*>(b2joint->GetUserData());
if (joint)
{
auto iter = std::find(joints_.begin(), joints_.end(), joint);
if (iter != joints_.end())
{
joints_.erase(iter);
}
}
}
} // namespace physics
} // namespace kiwano

View File

@ -19,14 +19,13 @@
// THE SOFTWARE.
#pragma once
#include <kiwano-physics/Body.h>
#include <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/Joint.h>
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<PhysicBodyPtr>& GetAllBodies() const;
/// \~chinese
/// @brief 添加关节
void AddJoint(JointPtr joint);
/// \~chinese
/// @brief 移除关节
void RemoveJoint(JointPtr joint);
/// \~chinese
/// @brief 移除所有关节
void RemoveAllJoints();
/// \~chinese
/// @brief 获取所有关节
const List<JointPtr>& 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<PhysicBodyPtr> bodies_;
List<JointPtr> joints_;
class ContactListener;
friend ContactListener;
ContactListener* contact_listener_;
bool removing_joint_;
Vector<Joint*> joints_;
std::unique_ptr<b2DestructionListener> destroy_listener_;
std::unique_ptr<b2ContactListener> 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

View File

@ -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 <kiwano-physics/ContactEvent.h>
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<Body*>(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<Body*>(b2body->GetUserData());
if (body && body->GetType() != Body::Type::Static)
{
body->UpdateActor();
}
b2body = b2body->GetNext();
}
Stage::Update(dt);
}
} // namespace physics
} // namespace kiwano

View File

@ -20,9 +20,9 @@
#pragma once
#include <kiwano-physics/Body.h>
#include <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/Contact.h>
#include <kiwano-physics/ContactEvent.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Joint.h>
#include <kiwano-physics/World.h>
#include <kiwano-physics/PhysicWorld.h>

View File

@ -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<ActorPtr> const& children)
{
for (const auto& actor : children)
@ -549,9 +569,9 @@ Vector<ActorPtr> 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<Actor*>(&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<Actor*>(&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");

View File

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

View File

@ -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<MouseHoverEvent>())
{
SetStatus(Status::Hover);
@ -151,16 +121,7 @@ void Button::HandleEvent(Event* evt)
else if (evt->IsType<MouseClickEvent>())
{
if (click_callback_)
click_callback_(this, actor_);
}
}
void Button::BindActor(Actor* actor)
{
Component::BindActor(actor);
if (actor)
{
actor->SetResponsible(true);
click_callback_(this, GetBoundActor());
}
}

View File

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

View File

@ -19,32 +19,36 @@
// THE SOFTWARE.
#include <kiwano/2d/Component.h>
#include <kiwano/2d/Actor.h>
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

View File

@ -19,6 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/Time.h>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/IntrusiveList.h>
@ -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);

View File

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

View File

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

View File

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

View File

@ -39,10 +39,6 @@ public:
/// @brief 添加动画
Action* AddAction(ActionPtr action);
/// \~chinese
/// @brief 添加动画
Action* AddAction(Action* action);
/// \~chinese
/// @brief 继续所有暂停动画
void ResumeAllActions();

View File

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

View File

@ -34,10 +34,6 @@ public:
/// @brief 添加监听器
EventListener* AddListener(EventListenerPtr listener);
/// \~chinese
/// @brief 添加监听器
EventListener* AddListener(EventListener* listener);
/// \~chinese
/// @brief 添加监听器
/// @param type 监听的事件类型

View File

@ -33,8 +33,8 @@ template <typename _PtrTy>
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 <typename _PTy>
template <typename _PtrTy>
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<pointer&>(base_);
}
inline reference operator*() const
{
KGE_ASSERT(base_ && !is_end_);
return const_cast<reference>(*base_);
return const_cast<reference>(base_);
}
inline pointer operator->() const
{
KGE_ASSERT(base_ && !is_end_);
return const_cast<pointer&>(base_);
return std::pointer_traits<pointer>::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<value_type>::type base_;
};
public:
using iterator = Iterator<pointer>;
using const_iterator = Iterator<const pointer>;
using iterator = Iterator<value_type>;
using const_iterator = Iterator<const value_type>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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 <typename _PtrTy>
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>;
};

View File

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

View File

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

View File

@ -58,7 +58,7 @@ RunnerPtr Runner::Create(WindowPtr main_window, Function<void()> on_ready, Funct
SmartPtr<CallbackRunner> 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

View File

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

View File

@ -33,7 +33,6 @@ Window::Window()
Window::~Window()
{
Destroy();
}
EventPtr Window::PollEvent()