Update physics

This commit is contained in:
Nomango 2020-02-22 17:24:31 +08:00
parent d6b95e3b40
commit f7844c1ac9
13 changed files with 339 additions and 176 deletions

View File

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

View File

@ -33,8 +33,8 @@ FixturePtr Fixture::CreateCircle(const Param& param, float radius, const Point&
if (ptr)
{
auto shape = std::make_unique<b2CircleShape>();
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<b2PolygonShape>();
shape->SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation));
@ -68,7 +68,7 @@ FixturePtr Fixture::CreatePolygon(const Param& param, const Vector<Point>& 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<b2PolygonShape>();
@ -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<b2EdgeShape>();
shape->Set(start, end);
@ -106,7 +106,7 @@ FixturePtr Fixture::CreateChain(const Param& param, const Vector<Point>& 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<b2ChainShape>();
@ -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()

View File

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

View File

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

View File

@ -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<b2FrictionJoint*>(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<b2PrismaticJoint*>(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<b2PulleyJoint*>(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<b2RopeJoint*>(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;

View File

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

View File

@ -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<FixturePtr> fixtures_;
Point offset_;
Point position_cached_;
};
/** @} */

View File

@ -113,6 +113,8 @@ PhysicWorld::PhysicWorld()
, vel_iter_(6)
, pos_iter_(2)
{
SetName("KGE_PHYSIC_WORLD");
destroy_listener_ = std::make_unique<DestructionListener>(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

View File

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

View File

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

View File

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

View File

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

View File

@ -115,7 +115,7 @@ KGE_SUPPRESS_WARNING_POP
}
template <typename _Lty, typename _Rty>
inline Matrix3x2T& operator=(MatrixMultiply<ValueType, _Lty, const _Rty>& other)
inline Matrix3x2T& operator=(const MatrixMultiply<ValueType, _Lty, _Rty>& other)
{
Matrix3x2T result(other);
(*this) = result;
@ -280,7 +280,7 @@ inline MatrixMultiply<_Ty, Matrix3x2T<_Ty>, Matrix3x2T<_Ty>> operator*(const Mat
template <typename _Ty, typename _Lty, typename _Rty>
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);
}