physics: character controller (Jolt CharacterVirtual)
- CharacterControllerComponent: capsule params (radius/halfHeight, mass, max slope, step height); entity origin = feet via shape offset - CharacterController per-entity wrapper: gravity integration + grounded clamp, ExtendedUpdate (sweep/slide + stick-to-floor + walk-stairs), SetLinearVelocity/Jump/IsGrounded facade - PhysicsWorld: SyncCharacters reconcile (create/rebuild on param change, editor-drag teleport), UpdateCharacters after physics Update (Jolt recommended order), writes back to Transform - Inspector: params + grounded/velocity telemetry + jump debug button - Serialization: params only, state rebuilt by reconcile
This commit is contained in:
@@ -259,6 +259,21 @@ namespace Engine::ECS {
|
||||
bool operator==(const JointComponent&) const = default;
|
||||
};
|
||||
|
||||
// 角色控制器参数(Jolt CharacterVirtual 扫掠运动学,非刚体——不受
|
||||
// 物理模拟驱动,游戏逻辑经 PhysicsWorld 门面喂速度/跳跃)。本组件
|
||||
// 只存参数(序列化:存参数不存状态),速度/着地等运行时状态在
|
||||
// PhysicsWorld 的 CharacterController 里(对账重建)
|
||||
struct CharacterControllerComponent {
|
||||
f32 radius = 0.3f; // 胶囊半径
|
||||
f32 capsuleHalfHeight = 0.4f; // 圆柱段半高(总高 = 2*(hh+r))
|
||||
f32 mass = 70.0f;
|
||||
f32 maxSlopeAngle = 45.0f; // 度:可站立的最大坡角
|
||||
f32 stepHeight = 0.4f; // 台阶自动攀爬高(WalkStairs)
|
||||
|
||||
bool operator==(const CharacterControllerComponent&) const = default;
|
||||
// 实体原点 = 脚底(胶囊底端),符合角色 pivot 习惯
|
||||
};
|
||||
|
||||
} // namespace Engine::ECS
|
||||
|
||||
#endif //HELLOVULKAN_COMPONENTS_H
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// CharacterController:单实体角色控制器(Jolt CharacterVirtual 后端)。
|
||||
//
|
||||
// 非刚体、扫掠运动学:CharacterVirtual 不注册进 PhysicsSystem,位置由
|
||||
// 本类每步扫掠推进(撞墙滑动/斜坡限制/贴地/上台阶),其他物理对象
|
||||
// "看不到"它(无碰撞解算,仅查询)。由 PhysicsWorld 对账创建/销毁并
|
||||
// 在 PhysicsSystem::Update 之后驱动(Jolt 官方建议序)。
|
||||
//
|
||||
// 速度语义(游戏逻辑职责分工):
|
||||
// - 水平移动:游戏逻辑每帧 SetCharacterVelocity 喂意图速度
|
||||
// - 垂直分量:本类自动积分重力(着地清零向下分量);Jump 置垂直速度
|
||||
// (Unity CharacterController.Move + gravity 手动积分同构)
|
||||
//
|
||||
// 实体原点 = 脚底(胶囊底端经 mShapeOffset 抬升到原点上方)。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_CHARACTERCONTROLLER_H
|
||||
#define HELLOVULKAN_CHARACTERCONTROLLER_H
|
||||
|
||||
#include <Engine/Core/Types.h>
|
||||
|
||||
#include <Jolt/Jolt.h>
|
||||
#include <Jolt/Physics/PhysicsSystem.h>
|
||||
#include <Jolt/Physics/Character/CharacterVirtual.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class CharacterController {
|
||||
public:
|
||||
// 创建参数快照(变更检测 → 重建 CharacterVirtual)
|
||||
struct Params {
|
||||
f32 radius = 0.3f; // 胶囊半径
|
||||
f32 halfHeight = 0.4f; // 圆柱段半高
|
||||
f32 mass = 70.0f;
|
||||
f32 maxSlopeAngle = 45.0f; // 度
|
||||
f32 stepHeight = 0.4f; // 台阶攀爬高
|
||||
|
||||
bool operator==(const Params&) const = default;
|
||||
};
|
||||
|
||||
CharacterController(JPH::PhysicsSystem& system, const Params& params,
|
||||
const glm::vec3& position);
|
||||
~CharacterController() = default; // Ref 引用计数自动释放
|
||||
|
||||
// 每物理步调用:重力积分 + ExtendedUpdate(扫掠滑动 + 贴地 +
|
||||
// 上台阶)。allocator 与 PhysicsSystem::Update 串行复用同一池
|
||||
void Update(f32 dt, const JPH::Vec3& gravity,
|
||||
JPH::TempAllocator& allocator);
|
||||
|
||||
// ---- 游戏逻辑门面(PhysicsWorld 转发)----
|
||||
void SetLinearVelocity(const glm::vec3& velocity);
|
||||
glm::vec3 GetLinearVelocity() const;
|
||||
void Jump(f32 speed); // 垂直速度置 speed(着地方向才有效)
|
||||
bool IsGrounded() const;
|
||||
glm::vec3 GetPosition() const;
|
||||
void Teleport(const glm::vec3& position); // 编辑器拖动
|
||||
|
||||
const Params& GetParams() const { return m_Params; }
|
||||
|
||||
private:
|
||||
Params m_Params;
|
||||
JPH::Ref<JPH::CharacterVirtual> m_Character;
|
||||
JPH::CharacterVirtual::ExtendedUpdateSettings m_Ext;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_CHARACTERCONTROLLER_H
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <Engine/Physics/PhysicsDebugDraw.h>
|
||||
#include <Engine/Physics/PhysicsEvents.h>
|
||||
#include <Engine/Physics/PhysicsRay.h>
|
||||
#include <Engine/Physics/CharacterController.h>
|
||||
#include <Engine/ECS/Components.h> // BodyRecord 快照存 CompoundChild(完整类型)
|
||||
|
||||
#include <Jolt/Jolt.h>
|
||||
@@ -90,6 +91,14 @@ namespace Engine {
|
||||
// 无 body / 静态体返回零向量
|
||||
glm::vec3 GetLinearVelocity(u32 entityBits) const;
|
||||
|
||||
// ---- 角色控制器(游戏逻辑门面;实体无 CharacterControllerComponent
|
||||
// 或未就绪时静默忽略)----
|
||||
// 速度直写喂意图(水平移动);垂直分量由 Update 自动积分重力
|
||||
void SetCharacterVelocity(u32 entityBits, const glm::vec3& velocity);
|
||||
void Jump(u32 entityBits, f32 speed); // 垂直速度置 speed
|
||||
bool IsCharacterGrounded(u32 entityBits) const;
|
||||
glm::vec3 GetCharacterVelocity(u32 entityBits) const;
|
||||
|
||||
private:
|
||||
// 创建时缓存的参数(变更检测 → 重建 body)
|
||||
struct BodyRecord {
|
||||
@@ -121,6 +130,12 @@ namespace Engine {
|
||||
void CreateConstraint(u32 ownerBits, u32 targetBits,
|
||||
const ECS::JointComponent& jc);
|
||||
void RemoveConstraint(u32 ownerBits);
|
||||
// 角色对账:孤儿清理 / 参数变更重建 / 编辑器拖动传送。
|
||||
// 角色非刚体(不进 PhysicsSystem),无 body 清理负担
|
||||
void SyncCharacters();
|
||||
// 每物理步(PhysicsSystem::Update 之后,Jolt 官方建议序):
|
||||
// 重力积分 + 扫掠 → 写回 TransformComponent(标脏)
|
||||
void UpdateCharacters(f32 dt);
|
||||
// Mesh 碰撞体:实体视觉网格 → Jolt 形状(Static=MeshShape /
|
||||
// Dynamic=ConvexHull)。无 MeshRenderer 或构建失败返回 null(回退 Box)
|
||||
JPH::RefConst<JPH::Shape> BuildMeshShape(u32 entityBits,
|
||||
@@ -132,6 +147,7 @@ namespace Engine {
|
||||
ECS::TransformComponent& tr);
|
||||
void RemoveBody(u32 entityBits);
|
||||
const BodyRecord* FindRecord(u32 entityBits) const; // 刚体驱动寻址
|
||||
CharacterController* FindCharacter(u32 entityBits); // 角色门面寻址
|
||||
void QueueEvent(CollisionEvent&& ev); // 回调线程 append(多线程并发,加锁)
|
||||
bool TryBitsByBodyId(const JPH::BodyID& id, u32& outBits) const;
|
||||
|
||||
@@ -144,6 +160,13 @@ namespace Engine {
|
||||
};
|
||||
std::unordered_map<u32, ConstraintRecord> m_Constraints;
|
||||
|
||||
// ---- 角色(entityBits → CharacterVirtual 封装)----
|
||||
struct CharacterEntry {
|
||||
std::unique_ptr<CharacterController> cc;
|
||||
glm::vec3 lastPos{0.0f}; // 编辑器拖动检测
|
||||
};
|
||||
std::unordered_map<u32, CharacterEntry> m_Characters;
|
||||
|
||||
ECS::Scene& m_Scene;
|
||||
Assets::AssetManager* m_Assets = nullptr; // Mesh 碰撞体解析 modelRef
|
||||
bool m_Enabled = true;
|
||||
|
||||
Reference in New Issue
Block a user