physics: capsule/cylinder/compound collider shapes

- ColliderType + Capsule/Cylinder/Compound; CompoundChild list (Box/
  Sphere/Capsule, local pos/quat, non-recursive)
- CreateBody: CapsuleShape/CylinderShape (ctor param orders differ) +
  StaticCompoundShape; empty/failed compound falls back to Box
- BodyRecord caches radius/halfHeight/compound; SyncScene rebuilds on
  change (per-collider param extraction)
- Inspector: combo entries + shape params + compound child list editor
- Serialization: new fields with as<T> fallback, compound seq round-trip
This commit is contained in:
2026-10-03 16:17:44 +08:00
parent 6c81bfd70d
commit a744b332eb
5 changed files with 245 additions and 10 deletions
+57 -1
View File
@@ -268,6 +268,34 @@ namespace Engine::Serialization {
EmitVec3(out, rb->boxHalfExtents);
out << YAML::Key << "SphereRadius" << YAML::Value
<< rb->sphereRadius;
out << YAML::Key << "CapsuleRadius" << YAML::Value
<< rb->capsuleRadius;
out << YAML::Key << "CapsuleHalfHeight" << YAML::Value
<< rb->capsuleHalfHeight;
out << YAML::Key << "CylinderRadius" << YAML::Value
<< rb->cylinderRadius;
out << YAML::Key << "CylinderHalfHeight" << YAML::Value
<< rb->cylinderHalfHeight;
if (!rb->compound.empty()) {
out << YAML::Key << "Compound" << YAML::Value
<< YAML::BeginSeq;
for (const auto& c : rb->compound) {
out << YAML::BeginMap;
out << YAML::Key << "Shape" << YAML::Value
<< static_cast<int>(c.shape);
out << YAML::Key << "BoxHalfExtents" << YAML::Value;
EmitVec3(out, c.boxHalfExtents);
out << YAML::Key << "Radius" << YAML::Value << c.radius;
out << YAML::Key << "CapsuleHalfHeight" << YAML::Value
<< c.capsuleHalfHeight;
out << YAML::Key << "Position" << YAML::Value;
EmitVec3(out, c.position);
out << YAML::Key << "Rotation" << YAML::Value;
EmitQuat(out, c.rotation); // (w,x,y,z)
out << YAML::EndMap;
}
out << YAML::EndSeq;
}
out << YAML::Key << "Mass" << YAML::Value << rb->mass;
out << YAML::Key << "GravityScale" << YAML::Value
<< rb->gravityScale;
@@ -491,7 +519,7 @@ namespace Engine::Serialization {
static_cast<ECS::RigidBodyComponent::BodyType>(type);
}
if (const int col = n["Collider"].as<int>(0);
col >= 0 && col <= 2) {
col >= 0 && col <= 5) {
rb.collider =
static_cast<ECS::RigidBodyComponent::ColliderType>(
col);
@@ -499,6 +527,34 @@ namespace Engine::Serialization {
rb.boxHalfExtents = ReadVec3(n["BoxHalfExtents"],
rb.boxHalfExtents);
rb.sphereRadius = n["SphereRadius"].as<f32>(rb.sphereRadius);
rb.capsuleRadius = n["CapsuleRadius"].as<f32>(rb.capsuleRadius);
rb.capsuleHalfHeight =
n["CapsuleHalfHeight"].as<f32>(rb.capsuleHalfHeight);
rb.cylinderRadius =
n["CylinderRadius"].as<f32>(rb.cylinderRadius);
rb.cylinderHalfHeight =
n["CylinderHalfHeight"].as<f32>(rb.cylinderHalfHeight);
// 僵尸节点铁律:拷贝初始化 + 判空再遍历(缺 Compound 键安全)
if (const YAML::Node cs = n["Compound"]) {
for (const auto& item : cs) {
ECS::RigidBodyComponent::CompoundChild c;
if (const int sh = item["Shape"].as<int>(0);
sh >= 0 && sh <= 2) {
c.shape = static_cast<
ECS::RigidBodyComponent::CompoundChild::Shape>(
sh);
}
c.boxHalfExtents = ReadVec3(item["BoxHalfExtents"],
c.boxHalfExtents);
c.radius = item["Radius"].as<f32>(c.radius);
c.capsuleHalfHeight =
item["CapsuleHalfHeight"].as<f32>(
c.capsuleHalfHeight);
c.position = ReadVec3(item["Position"], c.position);
c.rotation = ReadQuat(item["Rotation"]);
rb.compound.push_back(std::move(c));
}
}
rb.mass = n["Mass"].as<f32>(rb.mass);
rb.gravityScale = n["GravityScale"].as<f32>(rb.gravityScale);
rb.friction = n["Friction"].as<f32>(rb.friction);