diff --git a/src/kiwano-physics/Contact.cpp b/src/kiwano-physics/Contact.cpp index 80e63a36..8f6c5854 100644 --- a/src/kiwano-physics/Contact.cpp +++ b/src/kiwano-physics/Contact.cpp @@ -61,13 +61,13 @@ PhysicBody* Contact::GetBodyB() const void Contact::SetTangentSpeed(float speed) { KGE_ASSERT(contact_); - contact_->SetTangentSpeed(global::ToMeters(speed)); + contact_->SetTangentSpeed(global::LocalToWorld(speed)); } float Contact::GetTangentSpeed() const { KGE_ASSERT(contact_); - return global::ToPixels(contact_->GetTangentSpeed()); + return global::WorldToLocal(contact_->GetTangentSpeed()); } } // namespace physics diff --git a/src/kiwano-physics/Fixture.cpp b/src/kiwano-physics/Fixture.cpp index d004ac9b..b43d5884 100644 --- a/src/kiwano-physics/Fixture.cpp +++ b/src/kiwano-physics/Fixture.cpp @@ -33,8 +33,8 @@ FixturePtr Fixture::CreateCircle(const Param& param, float radius, const Point& if (ptr) { auto shape = std::make_unique(); - shape->m_radius = global::ToMeters(radius); - shape->m_p = global::ToMeters(offset); + shape->m_radius = global::LocalToWorld(radius); + shape->m_p = global::LocalToWorld(offset); ptr->shape_ = std::move(shape); ptr->param_ = param; @@ -47,8 +47,8 @@ FixturePtr Fixture::CreateRect(const Param& param, const Size& size, const Point FixturePtr ptr = new (std::nothrow) Fixture; if (ptr) { - b2Vec2 b2size = global::ToMeters(size); - b2Vec2 b2offset = global::ToMeters(offset); + b2Vec2 b2size = global::LocalToWorld(size); + b2Vec2 b2offset = global::LocalToWorld(offset); auto shape = std::make_unique(); shape->SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation)); @@ -68,7 +68,7 @@ FixturePtr Fixture::CreatePolygon(const Param& param, const Vector& verte b2vertexs.reserve(vertexs.size()); for (const auto& v : vertexs) { - b2vertexs.push_back(global::ToMeters(v)); + b2vertexs.push_back(global::LocalToWorld(v)); } auto shape = std::make_unique(); @@ -85,8 +85,8 @@ FixturePtr Fixture::CreateEdge(const Param& param, const Point& p1, const Point& FixturePtr ptr = new (std::nothrow) Fixture; if (ptr) { - b2Vec2 start = global::ToMeters(p1); - b2Vec2 end = global::ToMeters(p2); + b2Vec2 start = global::LocalToWorld(p1); + b2Vec2 end = global::LocalToWorld(p2); auto shape = std::make_unique(); shape->Set(start, end); @@ -106,7 +106,7 @@ FixturePtr Fixture::CreateChain(const Param& param, const Vector& vertexs b2vertexs.reserve(vertexs.size()); for (const auto& v : vertexs) { - b2vertexs.push_back(global::ToMeters(v)); + b2vertexs.push_back(global::LocalToWorld(v)); } auto shape = std::make_unique(); @@ -189,7 +189,7 @@ void Fixture::GetMassData(float* mass, Point* center, float* inertia) const if (mass) *mass = data.mass; if (center) - *center = global::ToPixels(data.center); + *center = global::WorldToLocal(data.center); if (inertia) *inertia = data.I; } @@ -197,7 +197,7 @@ 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)); + return fixture_->TestPoint(global::LocalToWorld(p)); } void Fixture::Destroy() diff --git a/src/kiwano-physics/Global.cpp b/src/kiwano-physics/Global.cpp index 3bc64dc6..ce6eeeba 100644 --- a/src/kiwano-physics/Global.cpp +++ b/src/kiwano-physics/Global.cpp @@ -43,24 +43,24 @@ void SetScale(float scale) global_scale = scale; } -float ToPixels(float value) +float WorldToLocal(float value) { return value * global_scale; } -Vec2 ToPixels(const b2Vec2& pos) +Vec2 WorldToLocal(const b2Vec2& pos) { - return Point(ToPixels(pos.x), ToPixels(pos.y)); + return Point(WorldToLocal(pos.x), WorldToLocal(pos.y)); } -float ToMeters(float value) +float LocalToWorld(float value) { return value / global_scale; } -b2Vec2 ToMeters(const Vec2& pos) +b2Vec2 LocalToWorld(const Vec2& pos) { - return b2Vec2(ToMeters(pos.x), ToMeters(pos.y)); + return b2Vec2(LocalToWorld(pos.x), LocalToWorld(pos.y)); } } // namespace global diff --git a/src/kiwano-physics/Global.h b/src/kiwano-physics/Global.h index 0fbaeffd..29e8d471 100644 --- a/src/kiwano-physics/Global.h +++ b/src/kiwano-physics/Global.h @@ -48,22 +48,22 @@ void SetScale(float scale); /// \~chinese /// @brief 游戏世界单位转换为物理世界单位 /// @details 根据全局缩放比例将物理世界的单位米转换为像素单位 -float ToPixels(float value); +float WorldToLocal(float value); /// \~chinese /// @brief 游戏世界单位转换为物理世界单位 /// @details 根据全局缩放比例将物理世界的单位米转换为像素单位 -Vec2 ToPixels(const b2Vec2& pos); +Vec2 WorldToLocal(const b2Vec2& pos); /// \~chinese /// @brief 物理世界单位转换为游戏世界单位 /// @details 根据全局缩放比例将像素单位转换为物理世界的单位米 -float ToMeters(float value); +float LocalToWorld(float value); /// \~chinese /// @brief 物理世界单位转换为游戏世界单位 /// @details 根据全局缩放比例将像素单位转换为物理世界的单位米 -b2Vec2 ToMeters(const Vec2& pos); +b2Vec2 LocalToWorld(const Vec2& pos); } // namespace global } // namespace physics diff --git a/src/kiwano-physics/Joint.cpp b/src/kiwano-physics/Joint.cpp index e0d74fb9..74bc3a54 100644 --- a/src/kiwano-physics/Joint.cpp +++ b/src/kiwano-physics/Joint.cpp @@ -129,8 +129,8 @@ bool DistanceJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2DistanceJointDef def; - def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor_a), - global::ToMeters(param_.anchor_b)); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(param_.anchor_a), + global::LocalToWorld(param_.anchor_b)); def.frequencyHz = param_.frequency_hz; def.dampingRatio = param_.damping_ratio; @@ -142,13 +142,13 @@ bool DistanceJoint::Init(PhysicWorld* world) void DistanceJoint::SetLength(float length) { KGE_ASSERT(raw_joint_); - raw_joint_->SetLength(global::ToMeters(length)); + raw_joint_->SetLength(global::LocalToWorld(length)); } float DistanceJoint::GetLength() const { KGE_ASSERT(raw_joint_); - return global::ToMeters(raw_joint_->GetLength()); + return global::LocalToWorld(raw_joint_->GetLength()); } // @@ -175,9 +175,9 @@ bool FrictionJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2FrictionJointDef def; - def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor)); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(param_.anchor)); def.maxForce = param_.max_force; - def.maxTorque = global::ToMeters(param_.max_torque); + def.maxTorque = global::LocalToWorld(param_.max_torque); Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); @@ -199,13 +199,13 @@ float FrictionJoint::GetMaxForce() const void FrictionJoint::SetMaxTorque(float length) { KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxTorque(global::ToMeters(length)); + raw_joint_->SetMaxTorque(global::LocalToWorld(length)); } float FrictionJoint::GetMaxTorque() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetMaxTorque()); + return global::WorldToLocal(raw_joint_->GetMaxTorque()); } // @@ -279,7 +279,7 @@ bool MotorJoint::Init(PhysicWorld* world) b2MotorJointDef def; def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body()); def.maxForce = param_.max_force; - def.maxTorque = global::ToMeters(param_.max_torque); + def.maxTorque = global::LocalToWorld(param_.max_torque); def.correctionFactor = param_.correction_factor; Joint::Init(world, &def); @@ -302,13 +302,13 @@ float MotorJoint::GetMaxForce() const void MotorJoint::SetMaxTorque(float length) { KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxTorque(global::ToMeters(length)); + raw_joint_->SetMaxTorque(global::LocalToWorld(length)); } float MotorJoint::GetMaxTorque() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetMaxTorque()); + return global::WorldToLocal(raw_joint_->GetMaxTorque()); } // @@ -335,14 +335,14 @@ bool PrismaticJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2PrismaticJointDef def; - def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor), + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(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.lowerTranslation = global::LocalToWorld(param_.lower_translation); + def.upperTranslation = global::LocalToWorld(param_.upper_translation); def.enableMotor = param_.enable_motor; def.maxMotorForce = param_.max_motor_force; - def.motorSpeed = global::ToMeters(param_.motor_speed); + def.motorSpeed = global::LocalToWorld(param_.motor_speed); Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); @@ -352,31 +352,31 @@ bool PrismaticJoint::Init(PhysicWorld* world) float PrismaticJoint::GetJointTranslation() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetJointTranslation()); + return global::WorldToLocal(raw_joint_->GetJointTranslation()); } float PrismaticJoint::GetJointSpeed() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetJointSpeed()); + return global::WorldToLocal(raw_joint_->GetJointSpeed()); } float PrismaticJoint::GetLowerLimit() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetLowerLimit()); + return global::WorldToLocal(raw_joint_->GetLowerLimit()); } float PrismaticJoint::GetUpperLimit() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetUpperLimit()); + return global::WorldToLocal(raw_joint_->GetUpperLimit()); } void PrismaticJoint::SetLimits(float lower, float upper) { KGE_ASSERT(raw_joint_); - raw_joint_->SetLimits(global::ToMeters(lower), global::ToMeters(upper)); + raw_joint_->SetLimits(global::LocalToWorld(lower), global::LocalToWorld(upper)); } // @@ -403,9 +403,9 @@ bool PulleyJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2PulleyJointDef def; - 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); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(param_.ground_anchor_a), + global::LocalToWorld(param_.ground_anchor_b), global::LocalToWorld(param_.anchor_a), + global::LocalToWorld(param_.anchor_b), param_.ratio); Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); @@ -415,13 +415,13 @@ bool PulleyJoint::Init(PhysicWorld* world) Point PulleyJoint::GetGroundAnchorA() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetGroundAnchorA()); + return global::WorldToLocal(raw_joint_->GetGroundAnchorA()); } Point PulleyJoint::GetGroundAnchorB() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetGroundAnchorB()); + return global::WorldToLocal(raw_joint_->GetGroundAnchorB()); } float PulleyJoint::GetRatio() const @@ -433,25 +433,25 @@ float PulleyJoint::GetRatio() const float PulleyJoint::GetLengthA() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetLengthA()); + return global::WorldToLocal(raw_joint_->GetLengthA()); } float PulleyJoint::GetLengthB() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetLengthB()); + return global::WorldToLocal(raw_joint_->GetLengthB()); } float PulleyJoint::GetCurrentLengthA() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetCurrentLengthA()); + return global::WorldToLocal(raw_joint_->GetCurrentLengthA()); } float PulleyJoint::GetCurrentLengthB() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetCurrentLengthB()); + return global::WorldToLocal(raw_joint_->GetCurrentLengthB()); } // @@ -478,12 +478,12 @@ bool RevoluteJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2RevoluteJointDef def; - def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor)); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(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.maxMotorTorque = global::LocalToWorld(param_.max_motor_torque); def.motorSpeed = math::Degree2Radian(param_.motor_speed); Joint::Init(world, &def); @@ -524,13 +524,13 @@ void RevoluteJoint::SetLimits(float lower, float upper) void RevoluteJoint::SetMaxMotorTorque(float torque) { KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxMotorTorque(global::ToMeters(torque)); + raw_joint_->SetMaxMotorTorque(global::LocalToWorld(torque)); } float RevoluteJoint::GetMaxMotorTorque() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetMaxMotorTorque()); + return global::WorldToLocal(raw_joint_->GetMaxMotorTorque()); } // @@ -559,9 +559,9 @@ bool RopeJoint::Init(PhysicWorld* world) b2RopeJointDef def; 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); + def.localAnchorA = global::LocalToWorld(param_.local_anchor_a); + def.localAnchorB = global::LocalToWorld(param_.local_anchor_b); + def.maxLength = global::LocalToWorld(param_.max_length); Joint::Init(world, &def); raw_joint_ = static_cast(GetB2Joint()); @@ -571,13 +571,13 @@ bool RopeJoint::Init(PhysicWorld* world) void RopeJoint::SetMaxLength(float length) { KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxLength(global::ToMeters(length)); + raw_joint_->SetMaxLength(global::LocalToWorld(length)); } float RopeJoint::GetMaxLength() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetMaxLength()); + return global::WorldToLocal(raw_joint_->GetMaxLength()); } // @@ -604,7 +604,7 @@ bool WeldJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2WeldJointDef def; - def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor)); + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(param_.anchor)); def.frequencyHz = param_.frequency_hz; def.dampingRatio = param_.damping_ratio; @@ -637,11 +637,11 @@ bool WheelJoint::Init(PhysicWorld* world) KGE_ASSERT(param_.body_a && param_.body_b); b2WheelJointDef def; - def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::ToMeters(param_.anchor), + def.Initialize(param_.body_a->GetB2Body(), param_.body_b->GetB2Body(), global::LocalToWorld(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.maxMotorTorque = global::LocalToWorld(param_.max_motor_torque); + def.motorSpeed = global::LocalToWorld(param_.motor_speed); def.frequencyHz = param_.frequency_hz; def.dampingRatio = param_.damping_ratio; @@ -653,25 +653,25 @@ bool WheelJoint::Init(PhysicWorld* world) float WheelJoint::GetJointTranslation() const { KGE_ASSERT(raw_joint_); - return global::ToMeters(raw_joint_->GetJointTranslation()); + return global::LocalToWorld(raw_joint_->GetJointTranslation()); } float WheelJoint::GetJointLinearSpeed() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetJointLinearSpeed()); + return global::WorldToLocal(raw_joint_->GetJointLinearSpeed()); } void WheelJoint::SetMaxMotorTorque(float torque) { KGE_ASSERT(raw_joint_); - raw_joint_->SetMaxMotorTorque(global::ToMeters(torque)); + raw_joint_->SetMaxMotorTorque(global::LocalToWorld(torque)); } float WheelJoint::GetMaxMotorTorque() const { KGE_ASSERT(raw_joint_); - return global::ToPixels(raw_joint_->GetMaxMotorTorque()); + return global::WorldToLocal(raw_joint_->GetMaxMotorTorque()); } // @@ -700,7 +700,7 @@ bool MouseJoint::Init(PhysicWorld* world) b2MouseJointDef def; def.bodyA = param_.body_a->GetB2Body(); def.bodyB = param_.body_b->GetB2Body(); - def.target = global::ToMeters(param_.target); + def.target = global::LocalToWorld(param_.target); def.maxForce = param_.max_force; def.frequencyHz = param_.frequency_hz; def.dampingRatio = param_.damping_ratio; diff --git a/src/kiwano-physics/PhysicBody.cpp b/src/kiwano-physics/PhysicBody.cpp index 8bd09e4c..351cc486 100644 --- a/src/kiwano-physics/PhysicBody.cpp +++ b/src/kiwano-physics/PhysicBody.cpp @@ -26,25 +26,26 @@ namespace kiwano namespace physics { -PhysicBodyPtr PhysicBody::Create(ActorPtr actor, Type type) +PhysicBodyPtr PhysicBody::Create(PhysicWorldPtr world, Type type) { - return PhysicBody::Create(actor.Get(), type); + return PhysicBody::Create(world.Get(), type); } -PhysicBodyPtr PhysicBody::Create(Actor* actor, Type type) +PhysicBodyPtr PhysicBody::Create(PhysicWorld* world, Type type) { - if (!actor) - { - return nullptr; - } + KGE_ASSERT(world); PhysicBodyPtr ptr = new (std::nothrow) PhysicBody; if (ptr) { ptr->SetType(type); - actor->AddComponent(ptr); + if (ptr->Init(world)) + { + world->AddBody(ptr); + return ptr; + } } - return ptr; + return nullptr; } PhysicBody::PhysicBody() @@ -55,6 +56,7 @@ PhysicBody::PhysicBody() , mask_bits_(0xFFFF) , group_index_(0) { + SetName("KGE_PHYSIC_BODY"); } PhysicBody::~PhysicBody() {} @@ -62,7 +64,10 @@ PhysicBody::~PhysicBody() {} void PhysicBody::InitComponent(Actor* actor) { Component::InitComponent(actor); - UpdateFromActor(); + + actor->SetPhysicBody(this); + + UpdateFromActor(actor); } void PhysicBody::DestroyComponent() @@ -98,19 +103,90 @@ bool PhysicBody::Init(PhysicWorld* world) 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::Destroy() +{ + RemoveAllFixtures(); + + if (body_ && world_) + { + b2World* b2world = world_->GetB2World(); + b2world->DestroyBody(body_); + } + + body_ = nullptr; + world_ = nullptr; + + Component::RemoveFromActor(); +} + +void PhysicBody::BeforeSimulation(Actor* actor, const Matrix3x2& parent_to_world, const Matrix3x2& actor_to_world, + float parent_rotation) +{ + UpdateFromActor(actor, actor_to_world, parent_rotation + actor->GetRotation()); + + /*if (actor->GetAnchor() != Vec2(0.5f, 0.5f)) + { + Point position = parent_to_world.Invert().Transform(position_cached_); + + offset_ = position - actor->GetPosition(); + }*/ +} + +void PhysicBody::AfterSimulation(Actor* actor, const Matrix3x2& parent_to_world, float parent_rotation) +{ + Point position_in_parent = GetPosition(); + if (position_cached_ != position_in_parent) + { + /*position_in_parent = parent_to_world.Invert().Transform(position_in_parent); + actor->SetPosition(position_in_parent - offset_);*/ + + position_in_parent = parent_to_world.Invert().Transform(position_in_parent); + actor->SetPosition(position_in_parent); + } + actor->SetRotation(GetRotation() - parent_rotation); +} + +void PhysicBody::UpdateFromActor(Actor* actor) +{ + KGE_ASSERT(actor); + KGE_ASSERT(world_); + + Actor* world_actor = world_->GetBoundActor(); + if (world_actor) + { + float rotation = 0.0f; + Matrix3x2 transform_to_world; + + Actor* ptr = actor; + while (ptr && ptr != world_actor) + { + rotation += ptr->GetRotation(); + transform_to_world *= ptr->GetTransformMatrixToParent(); + + ptr = ptr->GetParent(); + } + + UpdateFromActor(actor, transform_to_world, rotation); + } +} + +void PhysicBody::UpdateFromActor(Actor* actor, const Matrix3x2& actor_to_world, float rotation) +{ + /*Point center = actor->GetSize() / 2; + Point position = actor_to_world.Transform(center);*/ + Point anchor = actor->GetAnchor(); + Point size = actor->GetSize(); + Point position = actor_to_world.Transform(Point(anchor.x * size.x, anchor.y * size.y)); + SetTransform(position, rotation); + + position_cached_ = GetPosition(); +} + void PhysicBody::AddFixture(FixturePtr fixture) { if (fixture) @@ -240,7 +316,7 @@ void PhysicBody::GetMassData(float* mass, Point* center, float* inertia) const if (mass) *mass = data.mass; if (center) - *center = global::ToPixels(data.center); + *center = global::WorldToLocal(data.center); if (inertia) *inertia = data.I; } @@ -251,7 +327,7 @@ void PhysicBody::SetMassData(float mass, const Point& center, float inertia) b2MassData data; data.mass = mass; - data.center = global::ToMeters(center); + data.center = global::LocalToWorld(center); data.I = inertia; body_->SetMassData(&data); } @@ -265,43 +341,43 @@ void PhysicBody::ResetMassData() Point PhysicBody::GetPosition() const { KGE_ASSERT(body_); - return global::ToPixels(body_->GetPosition()); + return global::WorldToLocal(body_->GetPosition()); } void PhysicBody::SetTransform(const Point& pos, float angle) { KGE_ASSERT(body_); - body_->SetTransform(global::ToMeters(pos), math::Degree2Radian(angle)); + body_->SetTransform(global::LocalToWorld(pos), math::Degree2Radian(angle)); } Point PhysicBody::GetLocalPoint(const Point& world) const { KGE_ASSERT(body_); - return global::ToPixels(body_->GetLocalPoint(global::ToMeters(world))); + return global::WorldToLocal(body_->GetLocalPoint(global::LocalToWorld(world))); } Point PhysicBody::GetWorldPoint(const Point& local) const { KGE_ASSERT(body_); - return global::ToPixels(body_->GetWorldPoint(global::ToMeters(local))); + return global::WorldToLocal(body_->GetWorldPoint(global::LocalToWorld(local))); } Point PhysicBody::GetLocalCenter() const { KGE_ASSERT(body_); - return global::ToPixels(body_->GetLocalCenter()); + return global::WorldToLocal(body_->GetLocalCenter()); } Point PhysicBody::GetWorldCenter() const { KGE_ASSERT(body_); - return global::ToPixels(body_->GetWorldCenter()); + return global::WorldToLocal(body_->GetWorldCenter()); } void PhysicBody::ApplyForce(const Vec2& force, const Point& point, bool wake) { KGE_ASSERT(body_); - body_->ApplyForce(b2Vec2(force.x, force.y), global::ToMeters(point), wake); + body_->ApplyForce(b2Vec2(force.x, force.y), global::LocalToWorld(point), wake); } void PhysicBody::ApplyForceToCenter(const Vec2& force, bool wake) @@ -326,45 +402,6 @@ void PhysicBody::SetB2Body(b2Body* body) } } -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; diff --git a/src/kiwano-physics/PhysicBody.h b/src/kiwano-physics/PhysicBody.h index e83cad32..56da2876 100644 --- a/src/kiwano-physics/PhysicBody.h +++ b/src/kiwano-physics/PhysicBody.h @@ -27,6 +27,8 @@ namespace kiwano namespace physics { +class PhysicWorld; + /** * \addtogroup Physics * @{ @@ -36,6 +38,8 @@ namespace physics /// @brief 物体 class KGE_API PhysicBody : public Component { + friend class PhysicWorld; + public: /// \~chinese /// @brief 物体类型 @@ -48,15 +52,15 @@ public: /// \~chinese /// @brief 初始化物体 - /// @param actor 绑定该物体的角色 + /// @param world 物理世界 /// @param type 物体类型 - static PhysicBodyPtr Create(ActorPtr actor, Type type); + static PhysicBodyPtr Create(PhysicWorldPtr world, Type type); /// \~chinese /// @brief 初始化物体 - /// @param actor 绑定该物体的角色 + /// @param world 物理世界 /// @param type 物体类型 - static PhysicBodyPtr Create(Actor* actor, Type type); + static PhysicBodyPtr Create(PhysicWorld* world, Type type); PhysicBody(); @@ -290,14 +294,6 @@ public: /// @brief 获取物体所在物理世界 PhysicWorld* GetWorld() const; - /// \~chinese - /// @brief 将物体信息更新到角色 - void UpdateActor(); - - /// \~chinese - /// @brief 将角色信息更新到物体 - void UpdateFromActor(); - /// \~chinese /// @brief 销毁物体 void Destroy(); @@ -319,21 +315,39 @@ protected: /// @brief 销毁组件 void DestroyComponent() override; -private: + /// \~chinese + /// @brief 更新物体状态 + void UpdateFromActor(Actor* actor); + + /// \~chinese + /// @brief 更新物体状态 + void UpdateFromActor(Actor* actor, const Matrix3x2& actor_to_world, float parent_rotation); + /// \~chinese /// @brief 更新夹具过滤器 void UpdateFixtureFilter(b2Fixture* fixture); + /// \~chinese + /// @brief 更新物理身体前 + void BeforeSimulation(Actor* actor, const Matrix3x2& parent_to_world, const Matrix3x2& actor_to_world, + float parent_rotation); + + /// \~chinese + /// @brief 更新物理身体后 + void AfterSimulation(Actor* actorconst, const Matrix3x2& parent_to_world, float parent_rotation); + private: - PhysicWorld* world_; - b2Body* body_; - - uint16_t category_bits_; - uint16_t mask_bits_; - int16_t group_index_; - PhysicBody::Type type_; + PhysicWorld* world_; + b2Body* body_; + uint16_t category_bits_; + uint16_t mask_bits_; + int16_t group_index_; + PhysicBody::Type type_; Vector fixtures_; + + Point offset_; + Point position_cached_; }; /** @} */ diff --git a/src/kiwano-physics/PhysicWorld.cpp b/src/kiwano-physics/PhysicWorld.cpp index fcfeadcd..e5880204 100644 --- a/src/kiwano-physics/PhysicWorld.cpp +++ b/src/kiwano-physics/PhysicWorld.cpp @@ -113,6 +113,8 @@ PhysicWorld::PhysicWorld() , vel_iter_(6) , pos_iter_(2) { + SetName("KGE_PHYSIC_WORLD"); + destroy_listener_ = std::make_unique(Closure(this, &PhysicWorld::JointRemoved)); world_.SetDestructionListener(destroy_listener_.get()); @@ -134,9 +136,6 @@ void PhysicWorld::AddBody(PhysicBodyPtr body) { if (body) { - bool success = body->Init(this); - KGE_ASSERT(success); - bodies_.push_back(body); } } @@ -234,22 +233,25 @@ ContactList PhysicWorld::GetContactList() return ContactList(contact); } +void PhysicWorld::InitComponent(Actor* actor) +{ + Component::InitComponent(actor); + + // Update body status + Actor* world_actor = GetBoundActor(); + BeforeSimulation(world_actor, Matrix3x2(), 0.0f); +} + void PhysicWorld::OnUpdate(Duration dt) { - // Update bodies transform from actors - for (auto& body : bodies_) - { - body->UpdateFromActor(); - } + Actor* world_actor = GetBoundActor(); + BeforeSimulation(world_actor, Matrix3x2(), 0.0f); + + // Update physic world 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(); - } + AfterSimulation(world_actor, Matrix3x2(), 0.0f); } void PhysicWorld::DispatchEvent(Event* evt) @@ -274,5 +276,38 @@ void PhysicWorld::JointRemoved(b2Joint* b2joint) } } +void PhysicWorld::BeforeSimulation(Actor* parent, const Matrix3x2& parent_to_world, float parent_rotation) +{ + for (auto child : parent->GetAllChildren()) + { + Matrix3x2 child_to_world = child->GetTransformMatrixToParent() * parent_to_world; + + PhysicBody* body = child->GetPhysicBody(); + if (body) + { + body->BeforeSimulation(child.Get(), parent_to_world, child_to_world, parent_rotation); + } + + float rotation = parent_rotation + child->GetRotation(); + BeforeSimulation(child.Get(), child_to_world, rotation); + } +} + +void PhysicWorld::AfterSimulation(Actor* parent, const Matrix3x2& parent_to_world, float parent_rotation) +{ + for (auto child : parent->GetAllChildren()) + { + PhysicBody* body = child->GetPhysicBody(); + if (body) + { + body->AfterSimulation(child.Get(), parent_to_world, parent_rotation); + } + + Matrix3x2 child_to_world = child->GetTransformMatrixToParent() * parent_to_world; + float rotation = parent_rotation + child->GetRotation(); + AfterSimulation(child.Get(), child_to_world, rotation); + } +} + } // namespace physics } // namespace kiwano diff --git a/src/kiwano-physics/PhysicWorld.h b/src/kiwano-physics/PhysicWorld.h index 39843882..6b533f1e 100644 --- a/src/kiwano-physics/PhysicWorld.h +++ b/src/kiwano-physics/PhysicWorld.h @@ -121,12 +121,30 @@ public: const b2World* GetB2World() const; protected: + /// \~chinese + /// @brief 初始化组件 + void InitComponent(Actor* actor) override; + + /// \~chinese + /// @brief 更新组件 void OnUpdate(Duration dt) override; + /// \~chinese + /// @brief 分发物理世界事件 void DispatchEvent(Event* evt); + /// \~chinese + /// @brief 关节移除时的回调函数 void JointRemoved(b2Joint* b2joint); + /// \~chinese + /// @brief 更新物理世界前 + void BeforeSimulation(Actor* parent, const Matrix3x2& parent_to_world, float parent_rotation); + + /// \~chinese + /// @brief 更新物理世界后 + void AfterSimulation(Actor* parent, const Matrix3x2& parent_to_world, float parent_rotation); + private: b2World world_; int vel_iter_; diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 61334163..0e8251ef 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -65,6 +65,7 @@ Actor::Actor() , opacity_(1.f) , displayed_opacity_(1.f) , anchor_(default_anchor_x, default_anchor_y) + , physic_body_(nullptr) { } @@ -315,6 +316,12 @@ const Matrix3x2& Actor::GetTransformInverseMatrix() const return transform_matrix_inverse_; } +const Matrix3x2& Actor::GetTransformMatrixToParent() const +{ + UpdateTransform(); + return transform_matrix_to_parent_; +} + void Actor::UpdateTransform() const { if (!dirty_transform_) @@ -326,16 +333,18 @@ void Actor::UpdateTransform() const if (is_fast_transform_) { - transform_matrix_ = Matrix3x2::Translation(transform_.position); + transform_matrix_to_parent_ = Matrix3x2::Translation(transform_.position); } else { // matrix multiplication is optimized by expression template - transform_matrix_ = transform_.ToMatrix(); + transform_matrix_to_parent_ = transform_.ToMatrix(); } - transform_matrix_.Translate(Point{ -size_.x * anchor_.x, -size_.y * anchor_.y }); + Point anchor_offset(-size_.x * anchor_.x, -size_.y * anchor_.y); + transform_matrix_to_parent_.Translate(anchor_offset); + transform_matrix_ = transform_matrix_to_parent_; if (parent_) { transform_matrix_ *= parent_->transform_matrix_; @@ -727,8 +736,20 @@ bool Actor::ContainsPoint(const Point& point) const if (size_.x == 0.f || size_.y == 0.f) return false; + Point local = ConvertToLocal(point); + return local.x >= 0 && local.y >= 0 && local.x <= size_.x && local.y <= size_.y; +} + +Point Actor::ConvertToLocal(const Point& point) const +{ Point local = GetTransformInverseMatrix().Transform(point); - return GetBounds().ContainsPoint(local); + return local; +} + +Point Actor::ConvertToWorld(const Point& point) const +{ + Point world = GetTransformMatrix().Transform(point); + return world; } } // namespace kiwano diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index 4435194c..318cedf7 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -33,8 +33,12 @@ class Stage; class Director; class RenderContext; -KGE_DECLARE_SMART_PTR(Actor); +namespace physics +{ +class PhysicBody; +} +KGE_DECLARE_SMART_PTR(Actor); /// \~chinese /// @brief 角色列表 @@ -225,6 +229,10 @@ public: /// @brief 获取二维变换的逆矩阵 const Matrix3x2& GetTransformInverseMatrix() const; + /// \~chinese + /// @brief 获取变换到父角色的二维变换矩阵 + const Matrix3x2& GetTransformMatrixToParent() const; + /// \~chinese /// @brief 设置角色是否可见 void SetVisible(bool val); @@ -408,10 +416,26 @@ public: /// @brief 获取更新时的回调函数 UpdateCallback GetCallbackOnUpdate() const; + /// \~chinese + /// @brief 获取物理身体,仅当kiwano-physics包启用时生效 + physics::PhysicBody* GetPhysicBody() const; + + /// \~chinese + /// @brief 设置物理身体,仅当kiwano-physics包启用时生效 + void SetPhysicBody(physics::PhysicBody* body); + /// \~chinese /// @brief 判断点是否在角色内 virtual bool ContainsPoint(const Point& point) const; + /// \~chinese + /// @brief 将世界坐标系点转换为局部坐标系点 + Point ConvertToLocal(const Point& point) const; + + /// \~chinese + /// @brief 将局部坐标系点转换为世界坐标系点 + Point ConvertToWorld(const Point& point) const; + /// \~chinese /// @brief 渲染角色边界 void ShowBorder(bool show); @@ -499,6 +523,9 @@ private: mutable bool dirty_transform_inverse_; mutable Matrix3x2 transform_matrix_; mutable Matrix3x2 transform_matrix_inverse_; + mutable Matrix3x2 transform_matrix_to_parent_; + + physics::PhysicBody* physic_body_; }; /** @} */ @@ -683,6 +710,16 @@ inline Actor::UpdateCallback Actor::GetCallbackOnUpdate() const return cb_update_; } +inline physics::PhysicBody* Actor::GetPhysicBody() const +{ + return physic_body_; +} + +inline void Actor::SetPhysicBody(physics::PhysicBody* body) +{ + physic_body_ = body; +} + inline void Actor::ShowBorder(bool show) { show_border_ = show; diff --git a/src/kiwano/2d/Button.cpp b/src/kiwano/2d/Button.cpp index 127d132d..061c87fb 100644 --- a/src/kiwano/2d/Button.cpp +++ b/src/kiwano/2d/Button.cpp @@ -47,6 +47,7 @@ ButtonPtr Button::Create(const Callback& click, const Callback& pressed, const C Button::Button() : status_(Status::Normal) { + SetName("KGE_BUTTON"); } Button::~Button() diff --git a/src/kiwano/math/Matrix.hpp b/src/kiwano/math/Matrix.hpp index e66a9b15..0e55d21d 100644 --- a/src/kiwano/math/Matrix.hpp +++ b/src/kiwano/math/Matrix.hpp @@ -115,7 +115,7 @@ KGE_SUPPRESS_WARNING_POP } template - inline Matrix3x2T& operator=(MatrixMultiply& other) + inline Matrix3x2T& operator=(const MatrixMultiply& other) { Matrix3x2T result(other); (*this) = result; @@ -280,7 +280,7 @@ inline MatrixMultiply<_Ty, Matrix3x2T<_Ty>, Matrix3x2T<_Ty>> operator*(const Mat template inline MatrixMultiply<_Ty, MatrixMultiply<_Ty, _Lty, _Rty>, Matrix3x2T<_Ty>> -operator*(MatrixMultiply<_Ty, _Lty, const _Rty>& lhs, const Matrix3x2T<_Ty>& rhs) +operator*(const MatrixMultiply<_Ty, _Lty, _Rty>& lhs, const Matrix3x2T<_Ty>& rhs) { return MatrixMultiply<_Ty, MatrixMultiply<_Ty, _Lty, _Rty>, Matrix3x2T<_Ty>>(lhs, rhs); }