Update physics

This commit is contained in:
Nomango 2019-12-31 16:01:41 +08:00
parent 1e530411ae
commit b0b02ddf62
30 changed files with 1011 additions and 379 deletions

View File

@ -104,8 +104,7 @@ namespace kiwano
{
if (fixture.GetB2Fixture())
{
b2Fixture* ptr = const_cast<b2Fixture*>(fixture.GetB2Fixture());
body_->DestroyFixture(ptr);
body_->DestroyFixture(fixture.GetB2Fixture());
}
}
@ -254,7 +253,7 @@ namespace kiwano
void Body::Destroy()
{
if (world_)
if (world_ && body_)
{
world_->RemoveBody(this);
}

View File

@ -30,140 +30,283 @@ namespace kiwano
{
class World;
// 膠竟
KGE_DECLARE_SMART_PTR(Body);
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物体
class KGE_API Body
: public virtual RefCounter
{
public:
/// \~chinese
/// @brief 物体类型
enum class Type
{
Static = 0,
Kinematic,
Dynamic,
Static = 0, ///< 静态物体
Kinematic, ///< 动力学物体
Dynamic, ///< 动态物体
};
Body();
Body(b2Body* body, Actor* actor);
Body(World* world, Actor* actor);
Body(World* world, ActorPtr actor) : Body(world, actor.get()) {}
Body(World* world, ActorPtr actor);
virtual ~Body();
// 놓迦뺏
/// \~chinese
/// @brief 初始化
/// @param[in] world 物理世界
/// @param[in] actor 绑定的角色
void Init(World* world, Actor* actor);
// 警속셸야
/// \~chinese
/// @brief 添加夹具
/// @param shape 物体形状
/// @param density 物体密度
Fixture AddFixture(Shape* shape, const Fixture::Param& param);
// 警속近榴
/// \~chinese
/// @brief 添加圆形夹具
/// @param radius 圆形半径
/// @param density 物体密度
Fixture AddCircleShape(float radius, float density = 0.f);
/// \~chinese
/// @brief 添加盒形夹具
/// @param size 盒大小
/// @param density 物体密度
Fixture AddBoxShape(Vec2 const& size, float density = 0.f);
/// \~chinese
/// @brief 添加多边形夹具
/// @param vertexs 多边形端点
/// @param density 物体密度
Fixture AddPolygonShape(Vector<Point> const& vertexs, float density = 0.f);
/// \~chinese
/// @brief 添加线段形夹具
/// @param p1 线段起点
/// @param p2 线段终点
/// @param density 物体密度
Fixture AddEdgeShape(Point const& p1, Point const& p2, float density = 0.f);
/// \~chinese
/// @brief 添加链条形夹具
/// @param vertexs 链条端点
/// @param loop 是否闭合
/// @param density 物体密度
Fixture AddChainShape(Vector<Point> const& vertexs, bool loop, float density = 0.f);
// 삿혤셸야
Fixture GetFixtureList() const { KGE_ASSERT(body_); return Fixture(body_->GetFixtureList()); }
/// \~chinese
/// @brief 获取夹具列表
FixtureList GetFixtureList() const;
// 盧뇜셸야
/// \~chinese
/// @brief 移除夹具
void RemoveFixture(Fixture const& fixture);
// 삿혤쌈뇰긋
ContactEdge GetContactList() const { KGE_ASSERT(body_); ContactEdge(body_->GetContactList()); }
/// \~chinese
/// @brief 获取接触边列表
ContactEdgeList GetContactList() const;
// 잚깎쯤
uint16_t GetCategoryBits() const { return category_bits_; }
/// \~chinese
/// @brief 获取类别码
uint16_t GetCategoryBits() const;
/// \~chinese
/// @brief 设置类别码
void SetCategoryBits(uint16_t category_bits);
// 툭旒拿쯤
uint16_t GetMaskBits() const { return mask_bits_; }
/// \~chinese
/// @brief 获取碰撞掩码
uint16_t GetMaskBits() const;
/// \~chinese
/// @brief 设置碰撞掩码
void SetMaskBits(uint16_t mask_bits);
// 莉乞多
int16_t GetGroupIndex() const { return group_index_; }
/// \~chinese
/// @brief 获取组索引
int16_t GetGroupIndex() const;
/// \~chinese
/// @brief 设置组索引
void SetGroupIndex(int16_t index);
// 旗瘻실똑
float GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); }
void SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); }
/// \~chinese
/// @brief 获取旋转角度
float GetBodyRotation() const;
// 貫零
/// \~chinese
/// @brief 设置旋转角度
void SetBodyRotation(float angle);
/// \~chinese
/// @brief 获取物体位置
Point GetBodyPosition() const;
void SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); }
// 貫零뵨旗瘻긴뻣
/// \~chinese
/// @brief 设置物体位置
void SetBodyPosition(Point const& pos);
/// \~chinese
/// @brief 位置和旋转变换
void SetBodyTransform(Point const& pos, float angle);
// 醴좆
float GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); }
/// \~chinese
/// @brief 获取质量 [kg]
float GetMass() const;
// 발昑
float GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); }
/// \~chinese
/// @brief 获取惯性
float GetInertia() const;
// 醴좆鑒앴
/// \~chinese
/// @brief 获取质量数据
/// @param[out] mass 物体质量 [kg]
/// @param[out] center 质心位置
/// @param[out] inertia 惯性
void GetMassData(float* mass, Point* center, float* inertia) const;
/// \~chinese
/// @brief 设置质量数据
/// @param mass 物体质量 [kg]
/// @param center 质心位置
/// @param inertia 惯性
void SetMassData(float mass, Point const& center, float inertia);
/// \~chinese
/// @brief 重置质量数据
void ResetMassData();
// 麟깃瘻뻣
/// \~chinese
/// @brief 获取世界坐标系上的点在物体上的位置
Point GetLocalPoint(Point const& world) const;
/// \~chinese
/// @brief 获取物体上的点在世界坐标系的位置
Point GetWorldPoint(Point const& local) const;
// 醴懃麟깃
/// \~chinese
/// @brief 获取物体质心相对于物体的位置
Point GetLocalCenter() const;
/// \~chinese
/// @brief 获取物体质心位置
Point GetWorldCenter() const;
// 膠竟잚謹
Type GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); }
void SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast<b2BodyType>(type)); }
/// \~chinese
/// @brief 获取物体类型
Type GetType() const;
// 路제凜綾
float GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); }
void SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); }
/// \~chinese
/// @brief 设置物体类型
void SetType(Type type);
// 嘉제
/// \~chinese
/// @brief 获取物体受重力的比例
float GetGravityScale() const;
/// \~chinese
/// @brief 设置物体受重力的比例
void SetGravityScale(float scale);
/// \~chinese
/// @brief 施力
/// @param force 力的大小和方向
/// @param point 施力点
/// @param wake 是否唤醒物体
void ApplyForce(Vec2 const& force, Point const& point, bool wake = true);
/// \~chinese
/// @brief 给物体中心施力
/// @param force 力的大小和方向
/// @param wake 是否唤醒物体
void ApplyForceToCenter(Vec2 const& force, bool wake = true);
// 嘉속큉앤
void ApplyTorque(float torque, bool wake = true);
/// \~chinese
/// @brief 施加扭矩
/// @param torque 扭矩
/// @param wake 是否唤醒物体
void ApplyTorque(float torque, bool wake = false);
// 미땍旗瘻
bool IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); }
void SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); }
/// \~chinese
/// @brief 旋转角度是否固定
bool IsIgnoreRotation() const;
// 綾뎐
bool IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); }
void SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); }
/// \~chinese
/// @brief 设置是否固定旋转角度
void SetIgnoreRotation(bool flag);
// 金추
bool IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); }
void SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); }
bool IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); }
void SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); }
/// \~chinese
/// @brief 是否是子弹物体
bool IsBullet() const;
// 삶땡榴檄
bool IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); }
void SetActive(bool flag) { KGE_ASSERT(body_); body_->SetActive(flag); }
/// \~chinese
/// @brief 设置物体是否是子弹物体
void SetBullet(bool flag);
Actor* GetActor() const { return actor_; }
void SetActor(Actor* actor) { actor_ = actor; }
/// \~chinese
/// @brief 是否处于唤醒状态
bool IsAwake() const;
b2Body* GetB2Body() { return body_; }
const b2Body* GetB2Body() const { return body_; }
void SetB2Body(b2Body* body);
/// \~chinese
/// @brief 设置唤醒状态
void SetAwake(bool flag);
World* GetWorld() { return world_; }
const World* GetWorld() const { return world_; }
/// \~chinese
/// @brief 是否启用休眠
bool IsSleepingAllowed() const;
void Destroy();
/// \~chinese
/// @brief 设置是否允许休眠
void SetSleepingAllowed(bool flag);
/// \~chinese
/// @brief 是否启用
bool IsActive() const;
/// \~chinese
/// @brief 设置启用状态
void SetActive(bool flag);
/// \~chinese
/// @brief 获取物体所在物理世界
World* GetWorld() const;
/// \~chinese
/// @brief 获取物体绑定的角色
Actor* GetActor() const;
/// \~chinese
/// @brief 设置物体绑定的角色
void SetActor(Actor* actor);
/// \~chinese
/// @brief 将物体信息更新到角色
void UpdateActor();
/// \~chinese
/// @brief 将角色信息更新到物体
void UpdateFromActor();
b2Body* GetB2Body() const;
void SetB2Body(b2Body* body);
private:
/// \~chinese
/// @brief 销毁物体
void UpdateFixtureFilter(b2Fixture* fixture);
/// \~chinese
/// @brief 销毁物体
void Destroy();
private:
Actor* actor_;
World* world_;
@ -173,5 +316,65 @@ namespace kiwano
uint16_t mask_bits_;
int16_t group_index_;
};
/** @} */
inline Body::Body(World* world, ActorPtr actor) : Body(world, actor.get()) {}
inline FixtureList Body::GetFixtureList() const { KGE_ASSERT(body_); return FixtureList(Fixture(body_->GetFixtureList())); }
inline ContactEdgeList Body::GetContactList() const { KGE_ASSERT(body_); return ContactEdgeList(ContactEdge(body_->GetContactList())); }
inline uint16_t Body::GetCategoryBits() const { return category_bits_; }
inline uint16_t Body::GetMaskBits() const { return mask_bits_; }
inline int16_t Body::GetGroupIndex() const { return group_index_; }
inline float Body::GetBodyRotation() const { KGE_ASSERT(body_); return math::Radian2Degree(body_->GetAngle()); }
inline void Body::SetBodyRotation(float angle) { SetBodyTransform(GetBodyPosition(), angle); }
inline void Body::SetBodyPosition(Point const& pos) { SetBodyTransform(pos, GetBodyRotation()); }
inline float Body::GetMass() const { KGE_ASSERT(body_); return body_->GetMass(); }
inline float Body::GetInertia() const { KGE_ASSERT(body_); return body_->GetInertia(); }
inline Body::Type Body::GetType() const { KGE_ASSERT(body_); return Type(body_->GetType()); }
inline void Body::SetType(Type type) { KGE_ASSERT(body_); body_->SetType(static_cast<b2BodyType>(type)); }
inline float Body::GetGravityScale() const { KGE_ASSERT(body_); return body_->GetGravityScale(); }
inline void Body::SetGravityScale(float scale) { KGE_ASSERT(body_); body_->SetGravityScale(scale); }
inline bool Body::IsIgnoreRotation() const { KGE_ASSERT(body_); return body_->IsFixedRotation(); }
inline void Body::SetIgnoreRotation(bool flag) { KGE_ASSERT(body_); body_->SetFixedRotation(flag); }
inline bool Body::IsBullet() const { KGE_ASSERT(body_); return body_->IsBullet(); }
inline void Body::SetBullet(bool flag) { KGE_ASSERT(body_); body_->SetBullet(flag); }
inline bool Body::IsAwake() const { KGE_ASSERT(body_); return body_->IsAwake(); }
inline void Body::SetAwake(bool flag) { KGE_ASSERT(body_); body_->SetAwake(flag); }
inline bool Body::IsSleepingAllowed() const { KGE_ASSERT(body_); return body_->IsSleepingAllowed(); }
inline void Body::SetSleepingAllowed(bool flag) { KGE_ASSERT(body_); body_->SetSleepingAllowed(flag); }
inline bool Body::IsActive() const { KGE_ASSERT(body_); return body_->IsActive(); }
inline void Body::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 { return body_; }
inline World* Body::GetWorld() const { return world_; }
}
}

View File

@ -38,40 +38,26 @@ namespace kiwano
SetB2Contact(contact);
}
Contact Contact::GetNext()
{
KGE_ASSERT(contact_);
return Contact(contact_->GetNext());
}
const Contact Contact::GetNext() const
{
KGE_ASSERT(contact_);
return Contact(contact_->GetNext());
}
Fixture Contact::GetFixtureA()
Fixture Contact::GetFixtureA() const
{
KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureA());
}
const Fixture Contact::GetFixtureA() const
{
KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureA());
}
Fixture Contact::GetFixtureB()
Fixture Contact::GetFixtureB() const
{
KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureB());
}
const Fixture Contact::GetFixtureB() const
Body* Contact::GetBodyA() const
{
KGE_ASSERT(contact_);
return Fixture(contact_->GetFixtureB());
return GetFixtureA().GetBody();
}
Body* Contact::GetBodyB() const
{
return GetFixtureB().GetBody();
}
void Contact::SetTangentSpeed(float speed)

View File

@ -28,85 +28,183 @@ namespace kiwano
{
class Body;
// 接触
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物理接触
class KGE_API Contact
{
public:
Contact();
Contact(b2Contact* contact);
// 是否是接触
bool IsTouching() const { KGE_ASSERT(contact_); return contact_->IsTouching(); }
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
// 启用或禁用 (仅作用于一个时间步)
void SetEnabled(bool flag) { KGE_ASSERT(contact_); contact_->SetEnabled(flag); }
bool IsEnabled() const { KGE_ASSERT(contact_); return contact_->IsEnabled(); }
/// \~chinese
/// @brief 是否是接触
bool IsTouching() const;
// 获取下一接触
Contact GetNext();
const Contact GetNext() const;
/// \~chinese
/// @brief 启用或禁用 (仅作用于一个时间步)
void SetEnabled(bool flag);
// 夹具 A
Fixture GetFixtureA();
const Fixture GetFixtureA() const;
/// \~chinese
/// @brief 是否启用
bool IsEnabled() const;
// 夹具 B
Fixture GetFixtureB();
const Fixture GetFixtureB() const;
/// \~chinese
/// @brief 获取物体A的夹具
Fixture GetFixtureA() 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(); }
/// \~chinese
/// @brief 获取物体B的夹具
Fixture GetFixtureB() const;
// 弹性恢复
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(); }
/// \~chinese
/// @brief 获取物体A
Body* GetBodyA() const;
// 切线速度
/// \~chinese
/// @brief 获取物体B
Body* GetBodyB() const;
/// \~chinese
/// @brief 设置摩擦力
void SetFriction(float friction);
/// \~chinese
/// @brief 获取摩擦力
float GetFriction() const;
/// \~chinese
/// @brief 重置摩擦力
void ResetFriction();
/// \~chinese
/// @brief 设置弹性恢复
void SetRestitution(float restitution);
/// \~chinese
/// @brief 获取弹性恢复
float GetRestitution() const;
/// \~chinese
/// @brief 重置弹性恢复
void ResetRestitution();
/// \~chinese
/// @brief 设置切线速度
void SetTangentSpeed(float speed);
/// \~chinese
/// @brief 获取切线速度
float GetTangentSpeed() const;
b2Contact* GetB2Contact() { return contact_; }
const b2Contact* GetB2Contact() const { return contact_; }
void SetB2Contact(b2Contact* contact) { contact_ = contact; }
b2Contact* GetB2Contact() const;
void SetB2Contact(b2Contact* contact);
private:
b2Contact* contact_;
};
// 接触边
/// \~chinese
/// @brief 接触边
class KGE_API ContactEdge
{
public:
ContactEdge();
ContactEdge(b2ContactEdge* edge);
// 获取接触物体
Body* GetOtherBody() { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
const Body* GetOtherBody() const { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
// 获取接触
Contact GetContact() { KGE_ASSERT(edge_); return Contact(edge_->contact); }
const Contact GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); }
/// \~chinese
/// @brief 获取接触物体
Body* GetOtherBody() const;
// 获取上一接触边
ContactEdge GetPrev() { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); }
const ContactEdge GetPrev() const { KGE_ASSERT(edge_); return ContactEdge(edge_->prev); }
/// \~chinese
/// @brief 获取接触
Contact GetContact() const;
// 获取下一接触边
ContactEdge GetNext() { KGE_ASSERT(edge_); return ContactEdge(edge_->next); }
const ContactEdge GetNext() const { KGE_ASSERT(edge_); return ContactEdge(edge_->next); }
b2ContactEdge* GetB2ContactEdge() { return edge_; }
const b2ContactEdge* GetB2ContactEdge() const { return edge_; }
void SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; }
b2ContactEdge* GetB2ContactEdge() const;
void SetB2ContactEdge(b2ContactEdge* edge);
private:
b2ContactEdge* edge_;
};
/// \~chinese
/// @brief 物理接触列表
class ContactList
: public List<Contact>
{
public:
ContactList()
{
}
ContactList(const Contact& first)
{
Contact current = first;
while (current.GetB2Contact())
{
push_back(current);
current = current.GetB2Contact()->GetNext();
}
}
};
/// \~chinese
/// @brief 物理接触边列表
class ContactEdgeList
: public List<ContactEdge>
{
public:
ContactEdgeList()
{
}
ContactEdgeList(const ContactEdge& first)
{
ContactEdge current = first;
while (current.GetB2ContactEdge())
{
push_back(current);
current = current.GetB2ContactEdge()->next;
}
}
};
/** @} */
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 ContactEdge::IsValid() const { return edge_ != nullptr; }
inline Body* ContactEdge::GetOtherBody() const { KGE_ASSERT(edge_); return static_cast<Body*>(edge_->other->GetUserData()); }
inline Contact ContactEdge::GetContact() const { KGE_ASSERT(edge_); return Contact(edge_->contact); }
inline b2ContactEdge* ContactEdge::GetB2ContactEdge() const { return edge_; }
inline void ContactEdge::SetB2ContactEdge(b2ContactEdge* edge) { edge_ = edge; }
}
}

View File

@ -26,8 +26,6 @@ namespace kiwano
{
ContactBeginEvent::ContactBeginEvent()
: Event(KGE_EVENT(ContactBeginEvent))
, body_a(nullptr)
, body_b(nullptr)
{
}
@ -35,14 +33,10 @@ namespace kiwano
: ContactBeginEvent()
{
this->contact = contact;
body_a = this->contact.GetFixtureA().GetBody();
body_b = this->contact.GetFixtureB().GetBody();
}
ContactEndEvent::ContactEndEvent()
: Event(KGE_EVENT(ContactEndEvent))
, body_a(nullptr)
, body_b(nullptr)
{
}
@ -50,8 +44,6 @@ namespace kiwano
: ContactEndEvent()
{
this->contact = contact;
body_a = this->contact.GetFixtureA().GetBody();
body_b = this->contact.GetFixtureB().GetBody();
}
}

View File

@ -38,10 +38,9 @@ namespace kiwano
{
public:
Contact contact; ///< 产生的接触
Body* body_a; ///< 产生接触的物体A
Body* body_b; ///< 产生接触的物体B
ContactBeginEvent();
ContactBeginEvent(Contact const& contact);
};
@ -52,10 +51,9 @@ namespace kiwano
{
public:
Contact contact; ///< 产生的接触
Body* body_a; ///< 产生接触的物体A
Body* body_b; ///< 产生接触的物体B
ContactEndEvent();
ContactEndEvent(Contact const& contact);
};

View File

@ -58,30 +58,18 @@ namespace kiwano
}
}
Body* Fixture::GetBody()
Body* Fixture::GetBody() const
{
KGE_ASSERT(fixture_);
return static_cast<Body*>(fixture_->GetBody()->GetUserData());
}
const Body* Fixture::GetBody() const
{
KGE_ASSERT(fixture_);
return static_cast<const Body*>(fixture_->GetBody()->GetUserData());
}
Shape Fixture::GetShape() const
{
KGE_ASSERT(fixture_);
return Shape(fixture_->GetShape());
}
Fixture Fixture::GetNext() const
{
KGE_ASSERT(fixture_);
return Fixture(fixture_->GetNext());
}
void Fixture::GetMassData(float* mass, Point* center, float* inertia) const
{
KGE_ASSERT(fixture_);

View File

@ -28,16 +28,24 @@ namespace kiwano
{
class Body;
// 夹具
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 物理夹具
class Fixture
{
public:
/// \~chinese
/// @brief 夹具参数
struct Param
{
float density = 0.f;
float friction = 0.2f;
float restitution = 0.f;
bool is_sensor = false;
float density = 0.f; ///< 密度
float friction = 0.2f; ///< 摩擦力
float restitution = 0.f; ///< 弹性恢复
bool is_sensor = false; ///< 是否是接触传感器
Param() {}
@ -53,46 +61,99 @@ namespace kiwano
Fixture(b2Fixture* fixture);
Fixture(Body* body, Shape* shape, const Param& param);
// 物体
Body* GetBody();
const Body* GetBody() const;
/// \~chinese
/// @brief 是否有效
bool IsValid() const;
// 形状
/// \~chinese
/// @brief 获取夹具所在的物体
Body* GetBody() const;
/// \~chinese
/// @brief 形状
Shape GetShape() const;
// 下一夹具 (同一物体上)
Fixture GetNext() const;
/// \~chinese
/// @brief 是否是接触传感器
bool IsSensor() const;
// 接触传感器
bool IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); }
void SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); }
/// \~chinese
/// @brief 设置夹具是否是接触传感器
/// @details 接触传感器只会产生物理接触,而不会影响物体运动
void SetSensor(bool sensor);
// 质量数据
/// \~chinese
/// @brief 获取夹具的质量数据
void GetMassData(float* mass, Point* center, float* inertia) const;
// 密度
float GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); }
void SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); }
/// \~chinese
/// @brief 获取密度
float GetDensity() const;
// 摩擦力
float GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); }
void SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); }
/// \~chinese
/// @brief 设置密度
void SetDensity(float density);
// 弹性恢复
float GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); }
void SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); }
/// \~chinese
/// @brief 获取摩擦力 [N]
float GetFriction() const;
// 点测试
/// \~chinese
/// @brief 设置摩擦力 [N]
void SetFriction(float friction);
/// \~chinese
/// @brief 获取弹性恢复
float GetRestitution() const;
/// \~chinese
/// @brief 设置弹性恢复
void SetRestitution(float restitution);
/// \~chinese
/// @brief 点测试
bool TestPoint(const Point& p) const;
bool IsValid() const { return !!fixture_; }
b2Fixture* GetB2Fixture() { return fixture_; }
const b2Fixture* GetB2Fixture() const { return fixture_; }
void SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; }
b2Fixture* GetB2Fixture() const;
void SetB2Fixture(b2Fixture* fixture);
private:
b2Fixture* fixture_;
};
/// \~chinese
/// @brief 物理夹具列表
class FixtureList
: public List<Fixture>
{
public:
FixtureList()
{
}
FixtureList(const Fixture& first)
{
Fixture current = first;
while (current.GetB2Fixture())
{
push_back(current);
current = current.GetB2Fixture()->GetNext();
}
}
};
/** @} */
inline bool Fixture::IsSensor() const { KGE_ASSERT(fixture_); return fixture_->IsSensor(); }
inline void Fixture::SetSensor(bool sensor) { KGE_ASSERT(fixture_); fixture_->SetSensor(sensor); }
inline float Fixture::GetDensity() const { KGE_ASSERT(fixture_); return fixture_->GetDensity(); }
inline void Fixture::SetDensity(float density) { KGE_ASSERT(fixture_); fixture_->SetDensity(density); }
inline float Fixture::GetFriction() const { KGE_ASSERT(fixture_); return fixture_->GetFriction(); }
inline void Fixture::SetFriction(float friction) { KGE_ASSERT(fixture_); fixture_->SetFriction(friction); }
inline float Fixture::GetRestitution() const { KGE_ASSERT(fixture_); return fixture_->GetRestitution(); }
inline void Fixture::SetRestitution(float restitution) { KGE_ASSERT(fixture_); fixture_->SetRestitution(restitution); }
inline bool Fixture::IsValid() const { return fixture_ != nullptr; }
inline b2Fixture* Fixture::GetB2Fixture() const { return fixture_; }
inline void Fixture::SetB2Fixture(b2Fixture* fixture) { fixture_ = fixture; }
}
}

View File

@ -260,6 +260,7 @@ namespace kiwano
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;
Init(world, &def);
raw_joint_ = static_cast<b2MotorJoint*>(GetB2Joint());

View File

@ -39,34 +39,51 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(WeldJoint);
KGE_DECLARE_SMART_PTR(WheelJoint);
// 关节
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 关节
class KGE_API Joint
: public virtual RefCounter
{
public:
/// \~chinese
/// @brief 关节类型
enum class Type
{
Unknown = 0,
Revolute,
Prismatic,
Distance,
Pulley,
Mouse,
Gear,
Wheel,
Weld,
Friction,
Rope,
Motor
Unknown = 0, ///< 未知
Revolute, ///< 旋转关节
Prismatic, ///< 平移关节
Distance, ///< 固定距离关节
Pulley, ///< 滑轮关节
Mouse, ///< 鼠标关节
Gear, ///< 齿轮关节
Wheel, ///< 轮关节
Weld, ///< 焊接关节
Friction, ///< 摩擦关节
Rope, ///< 绳关节
Motor ///< 马达关节
};
/// \~chinese
/// @brief 关节基础参数
struct ParamBase
{
Body* body_a;
Body* body_b;
Body* body_a; ///< 关节连接的物体A
Body* body_b; ///< 关节连接的物体B
ParamBase(Body* body_a, Body* body_b) : body_a(body_a), body_b(body_b) {}
ParamBase(BodyPtr body_a, BodyPtr body_b) : body_a(body_a.get()), body_b(body_b.get()) {}
ParamBase(Body* body_a, Body* body_b)
: body_a(body_a), body_b(body_b)
{
}
ParamBase(BodyPtr body_a, BodyPtr body_b)
: body_a(body_a.get()), body_b(body_b.get())
{
}
};
Joint();
@ -76,15 +93,20 @@ namespace kiwano
void Init(World* world, b2JointDef* joint_def);
/// \~chinese
/// @brief 获取关节连接的物体A
BodyPtr GetBodyA() const;
/// \~chinese
/// @brief 获取关节连接的物体B
BodyPtr GetBodyB() const;
b2Joint* GetB2Joint() { return joint_; }
const b2Joint* GetB2Joint() const { return joint_; }
void SetB2Joint(b2Joint* joint);
/// \~chinese
/// @brief 获取物理世界
World* GetWorld() const;
World* GetWorld() { return world_; }
const World* GetWorld() const { return world_; }
b2Joint* GetB2Joint() const;
void SetB2Joint(b2Joint* joint);
private:
b2Joint* joint_;
@ -93,17 +115,20 @@ namespace kiwano
};
// 固定距离关节
/// \~chinese
/// @brief 固定距离关节
class KGE_API DistanceJoint
: public Joint
{
public:
/// \~chinese
/// @brief 固定距离关节参数
struct Param : public Joint::ParamBase
{
Point anchor_a;
Point anchor_b;
float frequency_hz;
float damping_ratio;
Point anchor_a; ///< 物体A的锚点位置
Point anchor_b; ///< 物体B的锚点位置
float frequency_hz; ///< 弹簧阻尼器频率
float damping_ratio; ///< 阻尼比
Param(
Body* body_a,
@ -136,23 +161,28 @@ namespace kiwano
DistanceJoint(World* world, b2DistanceJointDef* def);
DistanceJoint(World* world, Param const& param);
/// \~chinese
/// @brief 设置关节长度
void SetLength(float length);
float GetLength() const;
// 设置弹簧阻尼器频率 [赫兹]
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
/// \~chinese
/// @brief 设置弹簧阻尼器频率 [赫兹]
void SetFrequency(float hz);
float GetFrequency() const;
// 设置阻尼比
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
/// \~chinese
/// @brief 设置阻尼比
void SetDampingRatio(float ratio);
float GetDampingRatio() const;
private:
b2DistanceJoint* raw_joint_;
};
// 摩擦关节
/// \~chinese
/// @brief 摩擦关节
class KGE_API FrictionJoint
: public Joint
{
@ -191,11 +221,13 @@ namespace kiwano
FrictionJoint(World* world, b2FrictionJointDef* def);
FrictionJoint(World* world, Param const& param);
// 设定最大摩擦力
/// \~chinese
/// @brief 设定最大摩擦力
void SetMaxForce(float force);
float GetMaxForce() const;
// 设定最大转矩
/// \~chinese
/// @brief 设定最大转矩
void SetMaxTorque(float torque);
float GetMaxTorque() const;
@ -204,16 +236,19 @@ namespace kiwano
};
// 齿轮关节
/// \~chinese
/// @brief 齿轮关节
class KGE_API GearJoint
: public Joint
{
public:
/// \~chinese
/// @brief 齿轮关节参数
struct Param : public Joint::ParamBase
{
JointPtr joint_a;
JointPtr joint_b;
float ratio;
JointPtr joint_a; ///< 关节A
JointPtr joint_b; ///< 关节B
float ratio; ///< 齿轮传动比
Param(
Joint* joint_a,
@ -239,7 +274,8 @@ namespace kiwano
GearJoint(World* world, b2GearJointDef* def);
GearJoint(World* world, Param param);
// 设定齿轮传动比
/// \~chinese
/// @brief 设定齿轮传动比
void SetRatio(float ratio);
float GetRatio() const;
@ -248,16 +284,19 @@ namespace kiwano
};
// 马达关节
/// \~chinese
/// @brief 马达关节
class KGE_API MotorJoint
: public Joint
{
public:
/// \~chinese
/// @brief 马达关节参数
struct Param : public Joint::ParamBase
{
float max_force;
float max_torque;
float correction_factor;
float max_force; ///< 最大摩擦力
float max_torque; ///< 最大转矩
float correction_factor; ///< 位置矫正因子(范围 0-1
Param(
Body* body_a,
@ -287,11 +326,13 @@ namespace kiwano
MotorJoint(World* world, b2MotorJointDef* def);
MotorJoint(World* world, Param const& param);
// 设定最大摩擦力
/// \~chinese
/// @brief 设定最大摩擦力
void SetMaxForce(float force);
float GetMaxForce() const;
// 设定最大转矩
/// \~chinese
/// @brief 设定最大转矩
void SetMaxTorque(float torque);
float GetMaxTorque() const;
@ -300,21 +341,24 @@ namespace kiwano
};
// 平移关节
/// \~chinese
/// @brief 平移关节
class KGE_API PrismaticJoint
: public Joint
{
public:
/// \~chinese
/// @brief 平移关节参数
struct Param : public Joint::ParamBase
{
Point anchor;
Vec2 axis;
bool enable_limit;
float lower_translation;
float upper_translation;
bool enable_motor;
float max_motor_force;
float motor_speed;
Point anchor; ///< 锚点位置
Vec2 axis; ///< 平移轴向量
bool enable_limit; ///< 关节限制开关
float lower_translation; ///< 关节下限
float upper_translation; ///< 关节上限
bool enable_motor; ///< 马达开关
float max_motor_force; ///< 最大马达力 [N]
float motor_speed; ///< 马达转速 [degree/s]
Param(
Body* body_a,
@ -359,45 +403,64 @@ namespace kiwano
PrismaticJoint(World* world, b2PrismaticJointDef* def);
PrismaticJoint(World* world, Param const& param);
float GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
/// \~chinese
/// @brief 获取参考角
float GetReferenceAngle() const;
/// \~chinese
/// @brief 获取关节转换
float GetJointTranslation() const;
/// \~chinese
/// @brief 获取关节速度
float GetJointSpeed() const;
bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
/// \~chinese
/// @brief 是否启用关节限制
bool IsLimitEnabled() const;
void EnableLimit(bool flag);
/// \~chinese
/// @brief 设置关节限制
float GetLowerLimit() const;
float GetUpperLimit() const;
void SetLimits(float lower, float upper);
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
/// \~chinese
/// @brief 是否启用马达
bool IsMotorEnabled() const;
void EnableMotor(bool flag);
// 设置马达转速 [degree/s]
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
/// \~chinese
/// @brief 设置马达转速 [degree/s]
void SetMotorSpeed(float speed);
float GetMotorSpeed() const;
// 设定最大马达力 [N]
void SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); }
float GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); }
/// \~chinese
/// @brief 设定最大马达力 [N]
void SetMaxMotorForce(float force);
float GetMaxMotorForce() const;
private:
b2PrismaticJoint* raw_joint_;
};
// 滑轮关节
/// \~chinese
/// @brief 滑轮关节
class KGE_API PulleyJoint
: public Joint
{
public:
/// \~chinese
/// @brief 滑轮关节参数
struct Param : public Joint::ParamBase
{
Point anchor_a;
Point anchor_b;
Point ground_anchor_a;
Point ground_anchor_b;
float ratio;
Point anchor_a; ///<
Point anchor_b; ///<
Point ground_anchor_a; ///<
Point ground_anchor_b; ///<
float ratio; ///<
Param(
Body* body_a,
@ -449,7 +512,8 @@ namespace kiwano
};
// 旋转关节
/// \~chinese
/// @brief 旋转关节
class KGE_API RevoluteJoint
: public Joint
{
@ -504,25 +568,27 @@ namespace kiwano
RevoluteJoint(World* world, b2RevoluteJointDef* def);
RevoluteJoint(World* world, Param const& param);
float GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
float GetReferenceAngle() const;
float GetJointAngle() const;
float GetJointSpeed() const;
bool IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
void EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
bool IsLimitEnabled() const;
void EnableLimit(bool flag);
float GetLowerLimit() const;
float GetUpperLimit() const;
void SetLimits(float lower, float upper);
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
bool IsMotorEnabled() const;
void EnableMotor(bool flag);
// 设置马达转速 [degree/s]
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
/// \~chinese
/// @brief 设置马达转速 [degree/s]
void SetMotorSpeed(float speed);
float GetMotorSpeed() const;
// 设定最大马达转矩 [N/m]
/// \~chinese
/// @brief 设定最大马达转矩 [N/m]
void SetMaxMotorTorque(float torque);
float GetMaxMotorTorque() const;
@ -531,7 +597,8 @@ namespace kiwano
};
// 绳关节
/// \~chinese
/// @brief 绳关节
class KGE_API RopeJoint
: public Joint
{
@ -578,7 +645,8 @@ namespace kiwano
};
// 焊接关节
/// \~chinese
/// @brief 焊接关节
class KGE_API WeldJoint
: public Joint
{
@ -617,20 +685,23 @@ namespace kiwano
WeldJoint(World* world, b2WeldJointDef* def);
WeldJoint(World* world, Param const& param);
// 设置弹簧阻尼器频率 [赫兹]
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
/// \~chinese
/// @brief 设置弹簧阻尼器频率 [赫兹]
void SetFrequency(float hz);
float GetFrequency() const;
// 设置阻尼比
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
/// \~chinese
/// @brief 设置阻尼比
void SetDampingRatio(float ratio);
float GetDampingRatio() const;
private:
b2WeldJoint* raw_joint_;
};
// 轮关节
/// \~chinese
/// @brief 轮关节
class KGE_API WheelJoint
: public Joint
{
@ -687,33 +758,36 @@ namespace kiwano
float GetJointTranslation() const;
float GetJointLinearSpeed() const;
float GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); }
float GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); }
float GetJointAngle() const;
float GetJointAngularSpeed() const;
bool IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
void EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
bool IsMotorEnabled() const;
void EnableMotor(bool flag);
// 设置马达转速 [degree/s]
void SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
float GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
/// \~chinese
/// @brief 设置马达转速 [degree/s]
void SetMotorSpeed(float speed);
float GetMotorSpeed() const;
// 设定最大马达转矩 [N/m]
/// \~chinese
/// @brief 设定最大马达转矩 [N/m]
void SetMaxMotorTorque(float torque);
float GetMaxMotorTorque() const;
void SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); }
float GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); }
void SetSpringFrequencyHz(float hz);
float GetSpringFrequencyHz() const;
void SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); }
float GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); }
void SetSpringDampingRatio(float ratio);
float GetSpringDampingRatio() const;
private:
b2WheelJoint* raw_joint_;
};
// 鼠标关节
// 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
/// \~chinese
/// @brief 鼠标关节
/// @details 用于使身体的某个点追踪世界上的指定点,例如让物体追踪鼠标位置
class KGE_API MouseJoint
: public Joint
{
@ -740,14 +814,7 @@ namespace kiwano
, damping_ratio(damping_ratio)
{}
Param(
BodyPtr body_a,
BodyPtr body_b,
Point const& target,
float max_force,
float frequency_hz = 5.0f,
float damping_ratio = 0.7f
)
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)
{}
};
@ -756,20 +823,72 @@ namespace kiwano
MouseJoint(World* world, b2MouseJointDef* def);
MouseJoint(World* world, Param const& param);
// 设定最大摩擦力 [N]
/// \~chinese
/// @brief 设定最大摩擦力 [N]
void SetMaxForce(float force);
float GetMaxForce() const;
// 设置响应速度 [hz]
void SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
float GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
/// \~chinese
/// @brief 设置响应速度 [hz]
void SetFrequency(float hz);
float GetFrequency() const;
// 设置阻尼比
void SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
float GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
/// \~chinese
/// @brief 设置阻尼比
void SetDampingRatio(float ratio);
float GetDampingRatio() const;
private:
b2MouseJoint* raw_joint_;
};
/** @} */
inline b2Joint* Joint::GetB2Joint() const { return joint_; }
inline World* Joint::GetWorld() const { return world_; }
inline void DistanceJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
inline float DistanceJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
inline void DistanceJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
inline float DistanceJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
inline float PrismaticJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
inline bool PrismaticJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
inline void PrismaticJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
inline bool PrismaticJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
inline void PrismaticJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
inline void PrismaticJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
inline float PrismaticJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
inline void PrismaticJoint::SetMaxMotorForce(float force) { KGE_ASSERT(raw_joint_); raw_joint_->SetMaxMotorForce(force); }
inline float PrismaticJoint::GetMaxMotorForce() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetMaxMotorForce(); }
inline float RevoluteJoint::GetReferenceAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetReferenceAngle()); }
inline bool RevoluteJoint::IsLimitEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsLimitEnabled(); }
inline void RevoluteJoint::EnableLimit(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableLimit(flag); }
inline bool RevoluteJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
inline void RevoluteJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
inline void RevoluteJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
inline float RevoluteJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
inline void WeldJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
inline float WeldJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
inline void WeldJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
inline float WeldJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
inline float WheelJoint::GetJointAngle() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngle()); }
inline float WheelJoint::GetJointAngularSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetJointAngularSpeed()); }
inline bool WheelJoint::IsMotorEnabled() const { KGE_ASSERT(raw_joint_); return raw_joint_->IsMotorEnabled(); }
inline void WheelJoint::EnableMotor(bool flag) { KGE_ASSERT(raw_joint_); raw_joint_->EnableMotor(flag); }
inline void WheelJoint::SetMotorSpeed(float speed) { KGE_ASSERT(raw_joint_); raw_joint_->SetMotorSpeed(math::Degree2Radian(speed)); }
inline float WheelJoint::GetMotorSpeed() const { KGE_ASSERT(raw_joint_); return math::Radian2Degree(raw_joint_->GetMotorSpeed()); }
inline void WheelJoint::SetSpringFrequencyHz(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringFrequencyHz(hz); }
inline float WheelJoint::GetSpringFrequencyHz() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringFrequencyHz(); }
inline void WheelJoint::SetSpringDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetSpringDampingRatio(ratio); }
inline float WheelJoint::GetSpringDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetSpringDampingRatio(); }
inline void MouseJoint::SetFrequency(float hz) { KGE_ASSERT(raw_joint_); raw_joint_->SetFrequency(hz); }
inline float MouseJoint::GetFrequency() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetFrequency(); }
inline void MouseJoint::SetDampingRatio(float ratio) { KGE_ASSERT(raw_joint_); raw_joint_->SetDampingRatio(ratio); }
inline float MouseJoint::GetDampingRatio() const { KGE_ASSERT(raw_joint_); return raw_joint_->GetDampingRatio(); }
}
}

View File

@ -35,12 +35,7 @@ namespace kiwano
{
}
b2Shape* Shape::GetB2Shape()
{
return shape_;
}
const b2Shape* Shape::GetB2Shape() const
b2Shape* Shape::GetB2Shape() const
{
return shape_;
}

View File

@ -26,25 +26,35 @@ namespace kiwano
namespace physics
{
class World;
class Fixture;
// 形状基类
/**
* \addtogroup Physics
* @{
*/
/// \~chinese
/// @brief 形状基类
class KGE_API Shape
{
friend class Fixture;
public:
Shape();
Shape(b2Shape* shape);
b2Shape* GetB2Shape();
const b2Shape* GetB2Shape() const;
b2Shape* GetB2Shape() const;
void SetB2Shape(b2Shape* shape);
private:
virtual void FitWorld(World* world) {}
private:
b2Shape* shape_;
};
// 圆形形状
/// \~chinese
/// @brief 圆形形状
class KGE_API CircleShape
: public Shape
{
@ -55,6 +65,7 @@ namespace kiwano
void Set(float radius, Point const& offset = Point());
private:
void FitWorld(World* world) override;
private:
@ -63,7 +74,8 @@ namespace kiwano
b2CircleShape circle_;
};
// 盒子形状
/// \~chinese
/// @brief 盒子形状
class KGE_API BoxShape
: public Shape
{
@ -74,6 +86,7 @@ namespace kiwano
void Set(Vec2 const& size, Point const& offset = Point(), float rotation = 0.f);
private:
void FitWorld(World* world) override;
private:
@ -83,7 +96,8 @@ namespace kiwano
b2PolygonShape polygon_;
};
// 多边形形状
/// \~chinese
/// @brief 多边形形状
class KGE_API PolygonShape
: public Shape
{
@ -94,6 +108,7 @@ namespace kiwano
void Set(Vector<Point> const& vertexs);
private:
void FitWorld(World* world) override;
private:
@ -101,7 +116,8 @@ namespace kiwano
b2PolygonShape polygon_;
};
// 线段形状, 用于表示一条边
/// \~chinese
/// @brief 线段形状, 用于表示一条边
class KGE_API EdgeShape
: public Shape
{
@ -112,6 +128,7 @@ namespace kiwano
void Set(Point const& p1, Point const& p2);
private:
void FitWorld(World* world) override;
private:
@ -119,7 +136,8 @@ namespace kiwano
b2EdgeShape edge_;
};
// 链式形状
/// \~chinese
/// @brief 链式形状
class KGE_API ChainShape
: public Shape
{
@ -130,6 +148,7 @@ namespace kiwano
void Set(Vector<Point> const& vertexs, bool loop = false);
private:
void FitWorld(World* world) override;
private:
@ -137,5 +156,7 @@ namespace kiwano
Vector<Point> vertexs_;
b2ChainShape chain_;
};
/** @} */
}
}

View File

@ -27,7 +27,7 @@ namespace kiwano
{
namespace
{
const float DefaultGlobalScale = 100.f; // 100 pixels per meters
const float default_global_scale = 100.f; // 100 pixels per meters
}
class World::DestructionListener : public b2DestructionListener
@ -85,7 +85,7 @@ namespace kiwano
: world_(b2Vec2(0, 10.0f))
, vel_iter_(6)
, pos_iter_(2)
, global_scale_(DefaultGlobalScale)
, global_scale_(default_global_scale)
, destruction_listener_(nullptr)
, contact_listener_(nullptr)
, removing_joint_(false)
@ -227,23 +227,8 @@ namespace kiwano
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* b2body = world_.GetBodyList();
while (b2body)
{
@ -255,7 +240,6 @@ namespace kiwano
b2body = b2body->GetNext();
}
}
Stage::Update(dt);
}

View File

@ -26,7 +26,22 @@ namespace kiwano
{
namespace physics
{
// 物理世界
KGE_DECLARE_SMART_PTR(World);
/**
* \~chinese
* \defgroup Physics
*/
/**
* \addtogroup Physics
* @{
*/
/**
* \~chinese
* @brief
*/
class KGE_API World
: public Stage
{
@ -38,54 +53,82 @@ namespace kiwano
virtual ~World();
// 获取重力
/// \~chinese
/// @brief 获取重力 [N]
Vec2 GetGravity() const;
// 设置重力
/// \~chinese
/// @brief 设置重力 [N]
void SetGravity(Vec2 gravity);
// 获取全局缩放比例
inline float GetGlobalScale() const { return global_scale_; }
/// \~chinese
/// @brief 获取全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
float GetGlobalScale() const;
// 设置全局缩放比例
inline void SetGlobalScale(float scale) { global_scale_ = scale; }
/// \~chinese
/// @brief 设置全局缩放比例
/// @details 缩放比例是指由物理世界的单位米转换到屏幕像素的比例默认比例为1:100
void SetGlobalScale(float scale);
// 游戏世界单位转换为物理世界单位
inline float World2Stage(float value) const { return value * GetGlobalScale(); }
inline Point World2Stage(const b2Vec2& pos) const { return Point(World2Stage(pos.x), World2Stage(pos.y)); }
/// \~chinese
/// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
float World2Stage(float value) const;
// 物理世界单位转换为游戏世界单位
inline float Stage2World(float value) const { return value / GetGlobalScale(); }
inline b2Vec2 Stage2World(const Point& pos) const { return b2Vec2(Stage2World(pos.x), Stage2World(pos.y)); }
/// \~chinese
/// @brief 游戏世界单位转换为物理世界单位
/// @details 根据全局缩放比例将物理世界的单位米转换为像素单位
Vec2 World2Stage(const b2Vec2& pos) const;
// 设置速度迭代次数, 默认为 6
inline void SetVelocityIterations(int vel_iter) { vel_iter_ = vel_iter; }
/// \~chinese
/// @brief 物理世界单位转换为游戏世界单位
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
float Stage2World(float value) const;
// 设置位置迭代次数, 默认为 2
inline void SetPositionIterations(int pos_iter) { pos_iter_ = pos_iter; }
/// \~chinese
/// @brief 物理世界单位转换为游戏世界单位
/// @details 根据全局缩放比例将像素单位转换为物理世界的单位米
b2Vec2 Stage2World(const Vec2& pos) const;
/// \~chinese
/// @brief 设置速度迭代次数, 默认为 6
void SetVelocityIterations(int vel_iter);
/// \~chinese
/// @brief 设置位置迭代次数, 默认为 2
void SetPositionIterations(int pos_iter);
b2World* GetB2World();
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;
private:
@ -106,6 +149,47 @@ namespace kiwano
Vector<Joint*> joints_;
};
KGE_DECLARE_SMART_PTR(World);
/** @} */
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)
{
vel_iter_ = vel_iter;
}
inline void World::SetPositionIterations(int pos_iter)
{
pos_iter_ = pos_iter;
}
}
}

View File

@ -28,7 +28,7 @@ namespace kiwano
{
namespace physics
{
inline b2Vec2 Stage2World(const Point& pos) { return b2Vec2(pos.x, pos.y); }
inline Point World2Stage(const b2Vec2& pos) { return Point(pos.x, pos.y); }
inline b2Vec2 Stage2World(const Vec2& pos) { return b2Vec2(pos.x, pos.y); }
inline Vec2 World2Stage(const b2Vec2& pos) { return Vec2(pos.x, pos.y); }
}
}

View File

@ -82,14 +82,14 @@ namespace kiwano
};
/// \~chinese
/// @brief 事件特性:判断是否是事件类型
/// @brief 事件特性:判断指定类型是否是事件
template <typename _Ty>
struct IsEvent : public std::bool_constant<std::is_base_of<Event, _Ty>::value || std::is_same<Event, _Ty>::value>
{
};
/// \~chinese
/// @brief 事件特性:判断是否是事件类型
/// @brief 事件特性:判断一个事件能否安全转换到另一事件类型
template <typename _Ty, typename = typename std::enable_if<IsEvent<_Ty>::value, int>::type>
struct IsEventType
{

View File

@ -29,6 +29,11 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(Brush);
/**
* \addtogroup Render
* @{
*/
/// \~chinese
/// @brief 渐变转换点
struct GradientStop
@ -141,6 +146,8 @@ namespace kiwano
ComPtr<ID2D1Brush> raw_;
};
/** @} */
inline Brush::Type Brush::GetType() const { return type_; }
inline ComPtr<ID2D1Brush> Brush::GetBrush() const { return raw_; }

View File

@ -24,6 +24,11 @@
namespace kiwano
{
/**
* \addtogroup Render
* @{
*/
/*
* \~chinese
* @brief ÑÕÉ«
@ -128,6 +133,8 @@ namespace kiwano
float a; ///< AlphaÖµ
};
/** @} */
inline bool Color::operator== (const Color& rhs) const
{
return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a;

View File

@ -30,6 +30,11 @@ namespace kiwano
class Renderer;
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief ×ÖÌå
@ -67,6 +72,8 @@ namespace kiwano
ComPtr<IDWriteFontCollection> collection_;
};
/** @} */
inline ComPtr<IDWriteFontCollection> Font::GetCollection() const
{
return collection_;

View File

@ -27,6 +27,11 @@ namespace kiwano
class Renderer;
class GeometrySink;
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief
@ -117,6 +122,8 @@ namespace kiwano
ComPtr<ID2D1Geometry> geo_;
};
/** @} */
inline ComPtr<ID2D1Geometry> Geometry::GetGeometry() const { return geo_; }
inline void Geometry::SetGeometry(ComPtr<ID2D1Geometry> geometry) { geo_ = geometry; }

View File

@ -26,6 +26,11 @@ namespace kiwano
class RenderTarget;
class Renderer;
/**
* \addtogroup Render
* @{
*/
/// \~chinese
/// @brief 几何形状组合方式
enum class CombineMode
@ -143,6 +148,8 @@ namespace kiwano
ComPtr<ID2D1GeometrySink> sink_;
};
/** @} */
inline ComPtr<ID2D1PathGeometry> GeometrySink::GetPathGeometry() const { return path_geo_; }
inline void GeometrySink::SetPathGeometry(ComPtr<ID2D1PathGeometry> path) { path_geo_ = path; }

View File

@ -28,6 +28,11 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(GifImage);
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief GIFͼÏñ
@ -107,6 +112,8 @@ namespace kiwano
ComPtr<IWICBitmapDecoder> decoder_;
};
/** @} */
inline GifImage::Frame::Frame()
: disposal_type(DisposalType::Unknown)
{

View File

@ -25,6 +25,11 @@ namespace kiwano
{
class RenderTarget;
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief
@ -85,6 +90,8 @@ namespace kiwano
ComPtr<ID2D1Layer> layer_;
};
/** @} */
inline bool LayerArea::IsValid() const { return layer_ != nullptr; }
inline Rect const& LayerArea::GetAreaRect() const { return area_; }

View File

@ -35,6 +35,11 @@ namespace kiwano
KGE_DECLARE_SMART_PTR(RenderTarget);
KGE_DECLARE_SMART_PTR(TextureRenderTarget);
/**
* \addtogroup Render
* @{
*/
/// \~chinese
/// @brief 文字抗锯齿模式
enum class TextAntialiasMode
@ -347,6 +352,8 @@ namespace kiwano
ComPtr<ID2D1BitmapRenderTarget> bitmap_rt_;
};
/** @} */
inline RenderTarget::Status::Status()
: primitives(0)

View File

@ -41,6 +41,16 @@ namespace kiwano
typedef ID3D11DeviceResources ID3DDeviceResources;
#endif
/**
* \~chinese
* \defgroup Render äÖȾÒýÇæ
*/
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief äÖȾÉèÖÃ
@ -315,6 +325,8 @@ namespace kiwano
ComPtr<IResourceFontCollectionLoader> res_font_collection_loader_;
};
/** @} */
inline HWND Renderer::GetTargetWindow() const { return hwnd_; }
inline Size const& Renderer::GetOutputSize() const { return output_size_; }

View File

@ -22,6 +22,11 @@
namespace kiwano
{
/**
* \addtogroup Render
* @{
*/
/// \~chinese
/// @brief 线条样式
/// @details 线条样式表示渲染目标在绘制线条时,如何处理两条线相交部分
@ -31,4 +36,6 @@ namespace kiwano
Bevel = 1, ///< 斜角样式
Round = 2 ///< 圆角样式
};
/** @} */
}

View File

@ -27,6 +27,11 @@ namespace kiwano
class RenderTarget;
class Renderer;
/**
* \addtogroup Render
* @{
*/
/// \~chinese
/// @brief 文本布局
class KGE_API TextLayout
@ -171,6 +176,8 @@ namespace kiwano
TextStyle style_;
};
/** @} */
inline bool TextLayout::IsValid() const
{
return text_layout_ != nullptr;

View File

@ -26,6 +26,11 @@
namespace kiwano
{
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief
@ -94,6 +99,8 @@ namespace kiwano
TextStyle(const String& font_family, float font_size, uint32_t font_weight = FontWeight::Normal);
};
/** @} */
inline TextStyle::TextStyle()
: TextStyle(String(), 18, FontWeight::Normal)
{

View File

@ -28,6 +28,13 @@ namespace kiwano
class TextureRenderTarget;
class Renderer;
KGE_DECLARE_SMART_PTR(Texture);
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief
@ -39,8 +46,6 @@ namespace kiwano
Nearest, ///< 最邻近插值,取最邻近的像素点的颜色值
};
KGE_DECLARE_SMART_PTR(Texture);
/**
* \~chinese
* @brief
@ -140,4 +145,6 @@ namespace kiwano
static InterpolationMode default_interpolation_mode_;
};
/** @} */
}

View File

@ -24,6 +24,11 @@
namespace kiwano
{
/**
* \addtogroup Render
* @{
*/
/**
* \~chinese
* @brief
@ -82,4 +87,6 @@ namespace kiwano
using GifImageMap = UnorderedMap<size_t, GifImagePtr>;
GifImageMap gif_texture_cache_;
};
/** @} */
}