Add physic::Contact

This commit is contained in:
Nomango 2019-10-31 20:34:38 +08:00
parent eb069a9fef
commit dade0ef4cd
27 changed files with 768 additions and 119 deletions

View File

@ -12,6 +12,8 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\kiwano-physics\Body.h" />
<ClInclude Include="..\..\src\kiwano-physics\Contact.h" />
<ClInclude Include="..\..\src\kiwano-physics\ContactListener.h" />
<ClInclude Include="..\..\src\kiwano-physics\Fixture.h" />
<ClInclude Include="..\..\src\kiwano-physics\helper.h" />
<ClInclude Include="..\..\src\kiwano-physics\Joint.h" />
@ -21,6 +23,8 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactListener.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Joint.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Shape.cpp" />

View File

@ -8,6 +8,8 @@
<ClInclude Include="..\..\src\kiwano-physics\Shape.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\ContactListener.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano-physics\Body.cpp" />
@ -15,5 +17,7 @@
<ClCompile Include="..\..\src\kiwano-physics\Joint.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Shape.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Fixture.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\Contact.cpp" />
<ClCompile Include="..\..\src\kiwano-physics\ContactListener.cpp" />
</ItemGroup>
</Project>

View File

@ -36,7 +36,7 @@ namespace
uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp)
{
kiwano::string* recv_buffer = (kiwano::string*)userp;
core::string* recv_buffer = (core::string*)userp;
uint32_t total = size * nmemb;
// add data to the end of recv_buffer
@ -46,10 +46,10 @@ namespace
return total;
}
kiwano::string convert_to_utf8(kiwano::wstring const& str)
core::string convert_to_utf8(core::wstring const& str)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
kiwano::string result;
core::string result;
try
{
@ -63,10 +63,10 @@ namespace
return result;
}
kiwano::wstring convert_from_utf8(kiwano::string const& str)
core::wstring convert_from_utf8(core::string const& str)
{
kiwano::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
kiwano::wstring result;
core::wstring result;
try
{
@ -104,7 +104,7 @@ namespace
}
}
bool Init(HttpClient* client, Vector<kiwano::string> const& headers, kiwano::string const& url, kiwano::string* response_data, kiwano::string* response_header, char* error_buffer)
bool Init(HttpClient* client, Vector<core::string> const& headers, core::string const& url, core::string* response_data, core::string* response_header, char* error_buffer)
{
if (!SetOption(CURLOPT_ERRORBUFFER, error_buffer))
return false;
@ -170,11 +170,11 @@ namespace
public:
static inline bool GetRequest(
HttpClient* client,
Vector<kiwano::string> const& headers,
kiwano::string const& url,
Vector<core::string> const& headers,
core::string const& url,
long* response_code,
kiwano::string* response_data,
kiwano::string* response_header,
core::string* response_data,
core::string* response_header,
char* error_buffer)
{
Curl curl;
@ -185,12 +185,12 @@ namespace
static inline bool PostRequest(
HttpClient* client,
Vector<kiwano::string> const& headers,
kiwano::string const& url,
kiwano::string const& request_data,
Vector<core::string> const& headers,
core::string const& url,
core::string const& request_data,
long* response_code,
kiwano::string* response_data,
kiwano::string* response_header,
core::string* response_data,
core::string* response_header,
char* error_buffer)
{
Curl curl;
@ -203,12 +203,12 @@ namespace
static inline bool PutRequest(
HttpClient* client,
Vector<kiwano::string> const& headers,
kiwano::string const& url,
kiwano::string const& request_data,
Vector<core::string> const& headers,
core::string const& url,
core::string const& request_data,
long* response_code,
kiwano::string* response_data,
kiwano::string* response_header,
core::string* response_data,
core::string* response_header,
char* error_buffer)
{
Curl curl;
@ -221,11 +221,11 @@ namespace
static inline bool DeleteRequest(
HttpClient* client,
Vector<kiwano::string> const& headers,
kiwano::string const& url,
Vector<core::string> const& headers,
core::string const& url,
long* response_code,
kiwano::string* response_data,
kiwano::string* response_header,
core::string* response_data,
core::string* response_header,
char* error_buffer)
{
Curl curl;
@ -307,13 +307,13 @@ namespace kiwano
bool ok = false;
long response_code = 0;
char error_message[256] = { 0 };
kiwano::string response_header;
kiwano::string response_data;
core::string response_header;
core::string response_data;
kiwano::string url = convert_to_utf8(request->GetUrl());
kiwano::string data = convert_to_utf8(request->GetData());
core::string url = convert_to_utf8(request->GetUrl());
core::string data = convert_to_utf8(request->GetData());
Vector<kiwano::string> headers;
Vector<core::string> headers;
headers.reserve(request->GetHeaders().size());
for (const auto& pair : request->GetHeaders())
{

View File

@ -30,6 +30,9 @@ namespace kiwano
: body_(nullptr)
, actor_(nullptr)
, world_(nullptr)
, category_bits_(0x0001)
, mask_bits_(0xFFFF)
, group_index_(0)
{
}
@ -111,6 +114,57 @@ namespace kiwano
}
}
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)
{
KGE_ASSERT(body_ && world_);
@ -252,5 +306,14 @@ namespace kiwano
}
}
void PhysicBody::UpdateFixtureFilter(b2Fixture* fixture)
{
b2Filter filter;
filter.categoryBits = category_bits_;
filter.maskBits = mask_bits_;
filter.groupIndex = group_index_;
fixture->SetFilterData(filter);
}
}
}

View File

@ -22,6 +22,7 @@
#include <kiwano-physics/helper.h>
#include <kiwano-physics/Shape.h>
#include <kiwano-physics/Fixture.h>
#include <kiwano-physics/Contact.h>
namespace kiwano
{
@ -60,11 +61,26 @@ namespace kiwano
PhysicFixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
// 삿혤셸야
PhysicFixture GetFixture() const { KGE_ASSERT(body_); PhysicFixture(body_->GetFixtureList()); }
PhysicFixture GetFixtureList() const { KGE_ASSERT(body_); PhysicFixture(body_->GetFixtureList()); }
// 盧뇜셸야
void RemoveFixture(PhysicFixture const& fixture);
// »ñÈ¡½Ó´¥±ß
PhysicContactEdge GetContactList() const { KGE_ASSERT(body_); PhysicContactEdge(body_->GetContactList()); }
// Àà±ðÂë
uint16_t GetCategoryBits() const { return category_bits_; }
void SetCategoryBits(uint16_t category_bits);
// ÅöײÑÚÂë
uint16_t GetMaskBits() const { return mask_bits_; }
void SetMaskBits(uint16_t mask_bits);
// ×éË÷Òý
int16_t GetGroupIndex() const { return group_index_; }
void SetGroupIndex(int16_t index);
// 旗瘻실똑
float GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); }
void SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); }
@ -143,10 +159,17 @@ namespace kiwano
void UpdateActor();
void UpdateFromActor();
protected:
void UpdateFixtureFilter(b2Fixture* fixture);
protected:
Actor* actor_;
PhysicWorld* world_;
b2Body* body_;
uint16_t category_bits_;
uint16_t mask_bits_;
int16_t group_index_;
};
}
}

View File

@ -0,0 +1,116 @@
// 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/Contact.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/World.h>
namespace kiwano
{
namespace physics
{
PhysicContact::PhysicContact()
: contact_(nullptr)
{
}
PhysicContact::PhysicContact(b2Contact* contact)
: PhysicContact()
{
SetB2Contact(contact);
}
PhysicContact PhysicContact::GetNext()
{
KGE_ASSERT(contact_);
return PhysicContact(contact_->GetNext());
}
const PhysicContact PhysicContact::GetNext() const
{
KGE_ASSERT(contact_);
return PhysicContact(contact_->GetNext());
}
PhysicFixture PhysicContact::GetFixtureA()
{
KGE_ASSERT(contact_);
return PhysicFixture(contact_->GetFixtureA());
}
const PhysicFixture PhysicContact::GetFixtureA() const
{
KGE_ASSERT(contact_);
return PhysicFixture(contact_->GetFixtureA());
}
PhysicFixture PhysicContact::GetFixtureB()
{
KGE_ASSERT(contact_);
return PhysicFixture(contact_->GetFixtureB());
}
const PhysicFixture PhysicContact::GetFixtureB() const
{
KGE_ASSERT(contact_);
return PhysicFixture(contact_->GetFixtureB());
}
void PhysicContact::SetTangentSpeed(float speed)
{
KGE_ASSERT(contact_);
PhysicBody* body = GetFixtureA().GetBody();
KGE_ASSERT(body);
PhysicWorld* world = body->GetWorld();
KGE_ASSERT(world);
contact_->SetTangentSpeed(world->Stage2World(speed));
}
float PhysicContact::GetTangentSpeed() const
{
KGE_ASSERT(contact_);
const PhysicBody* body = GetFixtureA().GetBody();
KGE_ASSERT(body);
const PhysicWorld* world = body->GetWorld();
KGE_ASSERT(world);
return world->World2Stage(contact_->GetTangentSpeed());
}
PhysicContactEdge::PhysicContactEdge()
: edge_(nullptr)
{
}
PhysicContactEdge::PhysicContactEdge(b2ContactEdge* edge)
: PhysicContactEdge()
{
SetB2ContactEdge(edge);
}
}
}

View File

@ -0,0 +1,112 @@
// 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-physics/helper.h>
#include <kiwano-physics/Fixture.h>
namespace kiwano
{
namespace physics
{
class PhysicBody;
// 接触
class KGE_API PhysicContact
{
public:
PhysicContact();
PhysicContact(b2Contact* contact);
// 是否是接触
bool IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); }
// 启用或禁用 (仅作用于一个时间步)
void SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); }
bool IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); }
// 获取下一接触
PhysicContact GetNext();
const PhysicContact GetNext() const;
// 夹具 A
PhysicFixture GetFixtureA();
const PhysicFixture GetFixtureA() const;
// 夹具 B
PhysicFixture GetFixtureB();
const PhysicFixture GetFixtureB() const;
// 摩擦
void SetFriction(float friction) { KGE_ASSERT(contact_); contact_->SetFriction(friction); }
float GetFriction() const { KGE_ASSERT(contact_); return contact_->GetFriction(); }
void ResetFriction() { KGE_ASSERT(contact_); contact_->ResetFriction(); }
// 弹性恢复
void SetRestitution(float restitution) { KGE_ASSERT(contact_); contact_->SetRestitution(restitution); }
float GetRestitution() const { KGE_ASSERT(contact_); return contact_->GetRestitution(); }
void ResetRestitution() { KGE_ASSERT(contact_); contact_->ResetRestitution(); }
// 切线速度
void SetTangentSpeed(float speed);
float GetTangentSpeed() const;
b2Contact* GetB2Contact() { return contact_; }
const b2Contact* GetB2Contact() const { return contact_; }
void SetB2Contact(b2Contact* contact) { contact_ = contact; }
protected:
b2Contact* contact_;
};
// 接触边
class KGE_API PhysicContactEdge
{
public:
PhysicContactEdge();
PhysicContactEdge(b2ContactEdge* edge);
// 获取接触物体
PhysicBody* GetOtherBody() { KGE_ASSERT(edge_); return static_cast<PhysicBody*>(edge_->other->GetUserData()); }
const PhysicBody* GetOtherBody() const { KGE_ASSERT(edge_); return static_cast<PhysicBody*>(edge_->other->GetUserData()); }
// 获取接触
PhysicContact GetContact() { KGE_ASSERT(edge_); return PhysicContact(edge_->contact); }
const PhysicContact GetContact() const { KGE_ASSERT(edge_); return PhysicContact(edge_->contact); }
// 获取上一接触边
PhysicContactEdge GetPrev() { KGE_ASSERT(edge_); return PhysicContactEdge(edge_->prev); }
const PhysicContactEdge GetPrev() const { KGE_ASSERT(edge_); return PhysicContactEdge(edge_->prev); }
// 获取下一接触边
PhysicContactEdge GetNext() { KGE_ASSERT(edge_); return PhysicContactEdge(edge_->next); }
const PhysicContactEdge GetNext() const { KGE_ASSERT(edge_); return PhysicContactEdge(edge_->next); }
b2ContactEdge* GetB2ContactEdge() { return edge_; }
const b2ContactEdge* GetB2ContactEdge() const { return edge_; }
void SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; }
protected:
b2ContactEdge* edge_;
};
}
}

View File

@ -0,0 +1,137 @@
// 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/ContactListener.h>
#include <kiwano-physics/Body.h>
#include <kiwano-physics/World.h>
namespace kiwano
{
namespace physics
{
PhysicContactListener::PhysicContactListener()
: running_(true)
{
}
PhysicContactListener::~PhysicContactListener()
{
}
PhysicContactCallbackListener::PhysicContactCallbackListener()
{
}
PhysicContactCallbackListener::~PhysicContactCallbackListener()
{
}
PhysicContactListener* PhysicContactDispatcher::AddContactListener(PhysicContactListenerPtr listener)
{
return AddContactListener(listener.get());
}
PhysicContactListener* PhysicContactDispatcher::AddContactListener(PhysicContactListener* listener)
{
KGE_ASSERT(listener && "AddListener failed, NULL pointer exception");
if (listener)
{
listeners_.push_back(listener);
}
return listener;
}
void PhysicContactDispatcher::StartContactListeners(String const& listener_name)
{
for (auto listener = listeners_.first_item(); listener; listener = listener->next_item())
{
if (listener->IsName(listener_name))
{
listener->Start();
}
}
}
void PhysicContactDispatcher::StopContactListeners(String const& listener_name)
{
for (auto listener = listeners_.first_item(); listener; listener = listener->next_item())
{
if (listener->IsName(listener_name))
{
listener->Stop();
}
}
}
void PhysicContactDispatcher::RemoveContactListeners(String const& listener_name)
{
PhysicContactListenerPtr next;
for (auto listener = listeners_.first_item(); listener; listener = next)
{
next = listener->next_item();
if (listener->IsName(listener_name))
{
listeners_.remove(listener);
}
}
}
void PhysicContactDispatcher::OnContactBegin(b2Contact* b2contact)
{
if (listeners_.empty())
return;
PhysicContact contact(b2contact);
PhysicContactListenerPtr next;
for (auto listener = listeners_.first_item(); listener; listener = next)
{
next = listener->next_item();
if (listener->IsRunning())
{
listener->OnContactBegin(contact);
}
}
}
void PhysicContactDispatcher::OnContactEnd(b2Contact* b2contact)
{
if (listeners_.empty())
return;
PhysicContact contact(b2contact);
PhysicContactListenerPtr next;
for (auto listener = listeners_.first_item(); listener; listener = next)
{
next = listener->next_item();
if (listener->IsRunning())
{
listener->OnContactEnd(contact);
}
}
}
}
}

View File

@ -0,0 +1,132 @@
// 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-physics/Contact.h>
namespace kiwano
{
namespace physics
{
class PhysicContactDispatcher;
KGE_DECLARE_SMART_PTR(PhysicContactListener);
// 接触监听器
class KGE_API PhysicContactListener
: public ObjectBase
, protected IntrusiveListItem<PhysicContactListenerPtr>
{
friend IntrusiveList<PhysicContactListenerPtr>;
friend class PhysicContactDispatcher;
public:
PhysicContactListener();
virtual ~PhysicContactListener();
// 接触开始
virtual void OnContactBegin(PhysicContact contact) { KGE_NOT_USED(contact); }
// 接触结束
virtual void OnContactEnd(PhysicContact contact) { KGE_NOT_USED(contact); }
inline void Start() { running_ = true; }
inline void Stop() { running_ = true; }
inline bool IsRunning() const { return running_; }
protected:
bool running_;
};
KGE_DECLARE_SMART_PTR(PhysicContactCallbackListener);
// 接触回调监听器
class KGE_API PhysicContactCallbackListener
: public PhysicContactListener
{
friend IntrusiveList<PhysicContactListenerPtr>;
friend class PhysicContactDispatcher;
public:
using ContactBeginCallback = Function<void(PhysicContact)>;
using ContactEndCallback = Function<void(PhysicContact)>;
PhysicContactCallbackListener();
virtual ~PhysicContactCallbackListener();
// 接触开始回调
void SetCallbackOnContactBegin(ContactBeginCallback const& cb) { begin_ = cb; }
ContactBeginCallback GetCallbackOnContactBegin() const { return begin_; }
// 接触结束回调
void SetCallbackOnContactEnd(ContactEndCallback const& cb) { end_ = cb; }
ContactEndCallback GetCallbackOnContactEnd() const { return end_; }
void OnContactBegin(PhysicContact contact) override { if (begin_) begin_(contact); }
void OnContactEnd(PhysicContact contact) override { if (end_) end_(contact); }
protected:
ContactBeginCallback begin_;
ContactEndCallback end_;
};
// 接触分发器
class KGE_API PhysicContactDispatcher
{
public:
using Listeners = IntrusiveList<PhysicContactListenerPtr>;
// 添加监听器
PhysicContactListener* AddContactListener(
PhysicContactListenerPtr listener
);
// 添加监听器
PhysicContactListener* AddContactListener(
PhysicContactListener* listener
);
// 启动监听器
void StartContactListeners(
String const& listener_name
);
// 停止监听器
void StopContactListeners(
String const& listener_name
);
// 移除监听器
void RemoveContactListeners(
String const& listener_name
);
protected:
void OnContactBegin(b2Contact* contact);
void OnContactEnd(b2Contact* contact);
private:
Listeners listeners_;
};
}
}

View File

@ -58,6 +58,18 @@ namespace kiwano
return PhysicFixture();
}
PhysicBody* PhysicFixture::GetBody()
{
KGE_ASSERT(fixture_);
return static_cast<PhysicBody*>(fixture_->GetBody()->GetUserData());
}
const PhysicBody* PhysicFixture::GetBody() const
{
KGE_ASSERT(fixture_);
return static_cast<const PhysicBody*>(fixture_->GetBody()->GetUserData());
}
PhysicShape PhysicFixture::GetShape() const
{
KGE_ASSERT(fixture_);

View File

@ -37,7 +37,14 @@ namespace kiwano
static PhysicFixture Create(PhysicBody* body, PhysicShape* shape, float density = 0.f, float friction = 0.2f, float restitution = 0.f);
// 物体
PhysicBody* GetBody();
const PhysicBody* GetBody() const;
// 形状
PhysicShape GetShape() const;
// 下一夹具 (同一物体上)
PhysicFixture GetNext() const;
bool IsValid() const { return !!fixture_; }

View File

@ -53,16 +53,37 @@ namespace kiwano
}
};
class PhysicWorld::ContactListener
: public b2ContactListener
{
PhysicWorld* world_;
public:
ContactListener(PhysicWorld* world)
: world_(world)
{
}
void BeginContact(b2Contact* contact) override { world_->OnContactBegin(contact); }
void EndContact(b2Contact* contact) override { world_->OnContactEnd(contact); }
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); }
};
PhysicWorld::PhysicWorld()
: world_(b2Vec2(0, 10.0f))
, vel_iter_(6)
, pos_iter_(2)
, global_scale_(DefaultGlobalScale)
, 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_);
}
PhysicWorld::~PhysicWorld()
@ -74,6 +95,13 @@ namespace kiwano
destruction_listener_ = nullptr;
}
world_.SetContactListener(nullptr);
if (contact_listener_)
{
delete contact_listener_;
contact_listener_ = nullptr;
}
// Make sure b2World was destroyed after b2Body
RemoveAllChildren();
RemoveAllBodies();

View File

@ -21,6 +21,7 @@
#pragma once
#include <kiwano-physics/Body.h>
#include <kiwano-physics/Joint.h>
#include <kiwano-physics/ContactListener.h>
namespace kiwano
{
@ -29,6 +30,7 @@ namespace kiwano
// 物理世界
class KGE_API PhysicWorld
: public Stage
, public PhysicContactDispatcher
{
friend class PhysicBody;
friend class PhysicJoint;
@ -45,32 +47,29 @@ namespace kiwano
void SetGravity(Vec2 gravity);
// 获取全局缩放比例
inline float GetGlobalScale() const { return global_scale_; }
inline float GetGlobalScale() const { return global_scale_; }
// 设置全局缩放比例
inline void SetGlobalScale(float scale) { global_scale_ = scale; }
inline void SetGlobalScale(float scale) { global_scale_ = scale; }
// 游戏世界单位转换为物理世界单位
inline float World2Stage(float value) { return value * GetGlobalScale(); }
inline Point World2Stage(const b2Vec2& pos) { return Point(World2Stage(pos.x), World2Stage(pos.y)); }
inline float World2Stage(float value) const { return value * GetGlobalScale(); }
inline Point World2Stage(const b2Vec2& pos) const { return Point(World2Stage(pos.x), World2Stage(pos.y)); }
// 物理世界单位转换为游戏世界单位
inline float Stage2World(float value) { return value / GetGlobalScale(); }
inline b2Vec2 Stage2World(const Point& pos) { return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); }
inline float Stage2World(float value) const { return value / GetGlobalScale(); }
inline b2Vec2 Stage2World(const Point& pos) const { return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); }
// 设置速度迭代次数, 默认为 6
inline void SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; }
inline void SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; }
// 设置位置迭代次数, 默认为 2
inline void SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; }
inline void SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; }
// »ñÈ¡ Box2D ÊÀ½ç
b2World* GetB2World();
// »ñÈ¡ Box2D ÊÀ½ç
const b2World* GetB2World() const;
protected:
private:
// 移除物体
void RemoveBody(PhysicBody* body);
@ -89,19 +88,22 @@ namespace kiwano
// 关节被移除
void JointRemoved(b2Joint* joint);
protected:
void Update(Duration dt) override;
class DestructionListener;
friend DestructionListener;
protected:
private:
b2World world_;
int vel_iter_;
int pos_iter_;
float global_scale_;
class DestructionListener;
friend DestructionListener;
DestructionListener* destruction_listener_;
class ContactListener;
friend ContactListener;
ContactListener* contact_listener_;
bool removing_joint_;
Vector<PhysicJoint*> joints_;
};

View File

@ -283,7 +283,7 @@ namespace kiwano
void Actor::SetStage(Stage* stage)
{
if (stage && stage_ != stage)
if (stage_ != stage)
{
stage_ = stage;
for (Actor* child = children_.first_item().get(); child; child = child->next_item().get())
@ -539,6 +539,11 @@ namespace kiwano
return nullptr;
}
Actor::Children& Actor::GetAllChildren()
{
return children_;
}
Actor::Children const & Actor::GetAllChildren() const
{
return children_;

View File

@ -49,10 +49,10 @@ namespace kiwano
Actor();
// 更新角色
virtual void OnUpdate(Duration dt) { KGE_UNUSED(dt); }
virtual void OnUpdate(Duration dt) { KGE_NOT_USED(dt); }
// 渲染角色
virtual void OnRender(RenderTarget* rt) { KGE_UNUSED(rt); }
virtual void OnRender(RenderTarget* rt) { KGE_NOT_USED(rt); }
// 获取显示状态
bool IsVisible() const { return visible_; }
@ -334,6 +334,9 @@ namespace kiwano
String const& name
) const;
// 获取全部子角色
Children& GetAllChildren();
// 获取全部子角色
Children const& GetAllChildren() const;
@ -407,7 +410,7 @@ namespace kiwano
void SetStage(Stage* stage);
protected:
private:
bool visible_;
bool update_pausing_;
bool cascade_opacity_;

View File

@ -84,7 +84,7 @@ namespace kiwano
void DebugActor::OnUpdate(Duration dt)
{
KGE_UNUSED(dt);
KGE_NOT_USED(dt);
frame_time_.push_back(Time::Now());
while (frame_time_.back() - frame_time_.front() >= time::Sec)

View File

@ -72,7 +72,7 @@ namespace kiwano
if (!swallow_)
{
ActorPtr prev;
for (auto child = children_.last_item(); child; child = prev)
for (auto child = GetAllChildren().last_item(); child; child = prev)
{
prev = child->prev_item();
child->Dispatch(evt);

View File

@ -189,7 +189,7 @@ namespace kiwano
void RoundRectActor::SetRadius(Vec2 const& radius)
{
SetRoundedRect(size_, radius);
SetRoundedRect(GetSize(), radius);
}
void RoundRectActor::SetRectSize(Size const& size)

View File

@ -166,7 +166,7 @@ namespace kiwano
inline Vec2 GetRadius() const { return radius_; }
inline Size GetRectSize() const { return size_; }
inline Size GetRectSize() const { return GetSize(); }
void SetRadius(
Vec2 const& radius

View File

@ -26,7 +26,7 @@ namespace kiwano
{
Stage::Stage()
{
stage_ = this;
SetStage(this);
SetAnchor(Vec2{ 0, 0 });
SetSize(Renderer::GetInstance()->GetOutputSize());

View File

@ -42,10 +42,10 @@ namespace kiwano
Text::Text()
: font_(text_default_font)
, style_(text_default_style)
, layout_dirty_(false)
, format_dirty_(false)
{
text_layout_.SetTextStyle(text_default_style);
}
Text::Text(String const& text)
@ -65,11 +65,11 @@ namespace kiwano
Text::Text(String const& text, const Font & font, const TextStyle & style)
: font_(font)
, style_(style)
, text_(text)
, layout_dirty_(true)
, format_dirty_(true)
{
text_layout_.SetTextStyle(style);
}
Text::~Text()
@ -84,7 +84,7 @@ namespace kiwano
void Text::SetStyle(const TextStyle& style)
{
style_ = style;
text_layout_.SetTextStyle(style);
layout_dirty_ = true;
}
@ -121,11 +121,6 @@ namespace kiwano
}
}
void Text::SetColor(Color const& color)
{
style_.color = color;
}
void Text::SetItalic(bool italic)
{
if (font_.italic != italic)
@ -137,67 +132,73 @@ namespace kiwano
void Text::SetWrapWidth(float wrap_width)
{
if (style_.wrap_width != wrap_width)
if (text_layout_.GetTextStyle().wrap_width != wrap_width)
{
style_.wrap_width = wrap_width;
text_layout_.GetTextStyle().wrap_width = wrap_width;
layout_dirty_ = true;
}
}
void Text::SetLineSpacing(float line_spacing)
{
if (style_.line_spacing != line_spacing)
if (text_layout_.GetTextStyle().line_spacing != line_spacing)
{
style_.line_spacing = line_spacing;
text_layout_.GetTextStyle().line_spacing = line_spacing;
layout_dirty_ = true;
}
}
void Text::SetAlignment(TextAlign align)
{
if (style_.alignment != align)
if (text_layout_.GetTextStyle().alignment != align)
{
style_.alignment = align;
text_layout_.GetTextStyle().alignment = align;
layout_dirty_ = true;
}
}
void Text::SetUnderline(bool underline)
{
if (style_.underline != underline)
if (text_layout_.GetTextStyle().underline != underline)
{
style_.underline = underline;
text_layout_.GetTextStyle().underline = underline;
layout_dirty_ = true;
}
}
void Text::SetStrikethrough(bool strikethrough)
{
if (style_.strikethrough != strikethrough)
if (text_layout_.GetTextStyle().strikethrough != strikethrough)
{
style_.strikethrough = strikethrough;
text_layout_.GetTextStyle().strikethrough = strikethrough;
layout_dirty_ = true;
}
}
void Text::SetColor(Color const& color)
{
text_layout_.GetTextStyle().color = color;
text_layout_.GetTextStyle().color = color;
}
void Text::SetOutline(bool outline)
{
style_.outline = outline;
text_layout_.GetTextStyle().outline = outline;
}
void Text::SetOutlineColor(Color const&outline_color)
{
style_.outline_color = outline_color;
text_layout_.GetTextStyle().outline_color = outline_color;
}
void Text::SetOutlineWidth(float outline_width)
{
style_.outline_width = outline_width;
text_layout_.GetTextStyle().outline_width = outline_width;
}
void Text::SetOutlineStroke(StrokeStyle outline_stroke)
{
style_.outline_stroke = outline_stroke;
text_layout_.GetTextStyle().outline_stroke = outline_stroke;
}
void Text::OnRender(RenderTarget* rt)
@ -216,13 +217,13 @@ namespace kiwano
if (format_dirty_)
{
format_dirty_ = false;
text_layout_.Update(font_);
text_layout_.UpdateFont(font_);
}
if (layout_dirty_)
{
layout_dirty_ = false;
text_layout_.Update(text_, style_);
text_layout_.UpdateLayout(text_);
SetSize(text_layout_.GetLayoutSize());
}
}

View File

@ -60,7 +60,7 @@ namespace kiwano
inline Font GetFont() const { return font_; }
// 获取文本样式
inline TextStyle GetStyle() const { return style_; }
inline TextStyle GetStyle() const { return text_layout_.GetTextStyle(); }
// 获取文本布局
inline TextLayout GetLayout() const { return text_layout_; }
@ -171,6 +171,5 @@ namespace kiwano
TextLayout text_layout_;
String text_;
Font font_;
TextStyle style_;
};
}

View File

@ -33,7 +33,7 @@ namespace kiwano
{
next = listener->next_item();
if (listener->type_ == evt.type)
if (listener->IsRunning() && listener->type_ == evt.type)
{
listener->callback_(evt);
}

View File

@ -112,6 +112,6 @@
# pragma warning (disable: 4251)
#endif
#define KGE_UNUSED(VAR) ((void)VAR)
#define KGE_NOT_USED(VAR) ((void)VAR)
#define KGE_DEPRECATED(...) __declspec(deprecated(__VA_ARGS__))

View File

@ -53,19 +53,18 @@ namespace kiwano
TextLayout::TextLayout(String const& text, Font const& font, TextStyle const& style)
{
Update(font);
Update(text, style);
UpdateFont(font);
SetTextStyle(style);
UpdateLayout(text);
}
void TextLayout::Update(Font const& font)
void TextLayout::UpdateFont(Font const& font)
{
text_format_.Update(font);
}
void TextLayout::Update(String const& text, TextStyle const& style)
void TextLayout::UpdateLayout(String const& text)
{
style_ = style;
if (text.empty())
{
text_format_.SetTextFormat(nullptr);
@ -83,7 +82,7 @@ namespace kiwano
if (SUCCEEDED(hr))
{
if (style.line_spacing == 0.f)
if (style_.line_spacing == 0.f)
{
hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
}
@ -91,25 +90,25 @@ namespace kiwano
{
hr = text_layout_->SetLineSpacing(
DWRITE_LINE_SPACING_METHOD_UNIFORM,
style.line_spacing,
style.line_spacing * 0.8f
style_.line_spacing,
style_.line_spacing * 0.8f
);
}
}
if (SUCCEEDED(hr))
{
hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style.alignment));
hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment));
}
if (SUCCEEDED(hr))
{
hr = text_layout_->SetWordWrapping((style.wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP);
hr = text_layout_->SetWordWrapping((style_.wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP);
}
if (SUCCEEDED(hr))
{
if (style.underline)
if (style_.underline)
{
hr = text_layout_->SetUnderline(true, { 0, UINT32(text.length()) });
}
@ -117,7 +116,7 @@ namespace kiwano
if (SUCCEEDED(hr))
{
if (style.strikethrough)
if (style_.strikethrough)
{
text_layout_->SetStrikethrough(true, { 0, UINT32(text.length()) });
}
@ -125,9 +124,9 @@ namespace kiwano
if (SUCCEEDED(hr))
{
if (style.wrap_width > 0)
if (style_.wrap_width > 0)
{
hr = text_layout_->SetMaxWidth(style.wrap_width);
hr = text_layout_->SetMaxWidth(style_.wrap_width);
}
else
{

View File

@ -52,15 +52,17 @@ namespace kiwano
TextLayout(String const& text, Font const& font, TextStyle const& style);
void Update(Font const& font);
void UpdateFont(Font const& font);
void Update(String const& text, TextStyle const& style);
void UpdateLayout(String const& text);
uint32_t GetLineCount();
Size GetLayoutSize() const;
inline TextStyle& GetTextStyle() { return style_; }
inline TextStyle const& GetTextStyle() const { return style_; }
inline void SetTextStyle(TextStyle const& style) { style_ = style; }
public:
inline TextFormat GetTextFormat() const { return text_format_; }

View File

@ -213,10 +213,10 @@ namespace kiwano
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect)
{
KGE_UNUSED(clientDrawingContext);
KGE_UNUSED(measuringMode);
KGE_UNUSED(glyphRunDescription);
KGE_UNUSED(clientDrawingEffect);
KGE_NOT_USED(clientDrawingContext);
KGE_NOT_USED(measuringMode);
KGE_NOT_USED(glyphRunDescription);
KGE_NOT_USED(clientDrawingEffect);
HRESULT hr = S_OK;
@ -311,8 +311,8 @@ namespace kiwano
__in DWRITE_UNDERLINE const* underline,
IUnknown* clientDrawingEffect)
{
KGE_UNUSED(clientDrawingContext);
KGE_UNUSED(clientDrawingEffect);
KGE_NOT_USED(clientDrawingContext);
KGE_NOT_USED(clientDrawingEffect);
HRESULT hr;
@ -380,8 +380,8 @@ namespace kiwano
__in DWRITE_STRIKETHROUGH const* strikethrough,
IUnknown* clientDrawingEffect)
{
KGE_UNUSED(clientDrawingContext);
KGE_UNUSED(clientDrawingEffect);
KGE_NOT_USED(clientDrawingContext);
KGE_NOT_USED(clientDrawingEffect);
HRESULT hr;
@ -451,13 +451,13 @@ namespace kiwano
BOOL IsRightToLeft,
IUnknown* clientDrawingEffect)
{
KGE_UNUSED(clientDrawingContext);
KGE_UNUSED(originX);
KGE_UNUSED(originY);
KGE_UNUSED(inlineObject);
KGE_UNUSED(IsSideways);
KGE_UNUSED(IsRightToLeft);
KGE_UNUSED(clientDrawingEffect);
KGE_NOT_USED(clientDrawingContext);
KGE_NOT_USED(originX);
KGE_NOT_USED(originY);
KGE_NOT_USED(inlineObject);
KGE_NOT_USED(IsSideways);
KGE_NOT_USED(IsRightToLeft);
KGE_NOT_USED(clientDrawingEffect);
return E_NOTIMPL;
}
@ -465,7 +465,7 @@ namespace kiwano
__maybenull void* clientDrawingContext,
__out BOOL* isDisabled)
{
KGE_UNUSED(clientDrawingContext);
KGE_NOT_USED(clientDrawingContext);
*isDisabled = FALSE;
return S_OK;
@ -475,7 +475,7 @@ namespace kiwano
__maybenull void* clientDrawingContext,
__out DWRITE_MATRIX* transform)
{
KGE_UNUSED(clientDrawingContext);
KGE_NOT_USED(clientDrawingContext);
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
return S_OK;
@ -485,7 +485,7 @@ namespace kiwano
__maybenull void* clientDrawingContext,
__out float* pixelsPerDip)
{
KGE_UNUSED(clientDrawingContext);
KGE_NOT_USED(clientDrawingContext);
float x, yUnused;