物理系统
内置 AABB 物理和 Rapier 3D 集成
AnvilKit 提供两种物理方案:轻量级的内置 AABB 系统(默认)和通过 rapier3d 实现的完整刚体模拟(需启用 feature)。
v0.3 模块重构
在 v0.3 中,物理模块从单个 physics.rs 文件拆分为 physics/ 目录,以更好地组织代码:
physics/mod.rs-- 重导出(导入路径保持不变)physics/components.rs--Velocity、AabbCollider、RigidBody、Colliderphysics/aabb.rs-- AABB 碰撞检测逻辑physics/rapier.rs-- Rapier 集成系统physics/events.rs--CollisionEvent和事件提取
通过 mod.rs 中的重导出,导入路径保持不变,现有代码不受影响。
数学工具
Aabb 和射线投射工具现在也可以从 anvilkit_core::math 获取(从渲染 crate 移出),无 GPU 依赖:
anvilkit_core::math::Aabb-- 纯数学 AABB,无 GPU 依赖anvilkit_core::math::raycast--screen_to_ray、ray_plane_intersection、ray_sphere_intersection
内置 AABB 物理(默认)
PhysicsPlugin 在 Update 中注册速度积分和 N-平方 AABB 碰撞检测。
| 类型 | 类别 | 说明 |
|---|---|---|
DeltaTime | Resource | 帧间隔时间(秒)— 由 update_delta_time_system 自动从 Time 同步 |
Velocity | Component | linear: Vec3, angular: Vec3 |
AabbCollider | Component | half_extents: Vec3 |
CollisionEvents | Resource | 已弃用 -- 请改用 EventWriter<CollisionEvent> / EventReader<CollisionEvent> |
CollisionEvent | Struct | a: Entity, b: Entity |
| 系统 | 说明 |
|---|---|
update_delta_time_system | 从核心 Time 资源同步 DeltaTime(在 PreUpdate 中注册) |
velocity_integration_system | transform.translation += velocity.linear * dt |
collision_detection_system | N-平方 AABB 重叠检测(缩放感知),写入 CollisionEvents |
推荐调度
物理系统应在 FixedUpdate 中运行以实现确定性模拟:
app.add_systems(AnvilKitSchedule::FixedUpdate, (
velocity_integration_system,
collision_detection_system.after(velocity_integration_system),
));FixedUpdate 以固定 1/60s 时间步长运行(可通过 app.set_fixed_timestep() 配置),独立于帧率。确保不同硬件上的物理行为一致。
use anvilkit::prelude::*;
fn setup_physics(mut commands: Commands) {
// 动态移动方块
commands.spawn((
Transform::from_xyz(0.0, 10.0, 0.0),
Velocity::linear(Vec3::new(0.0, -5.0, 0.0)),
AabbCollider::cube(0.5),
));
// 静态地面
commands.spawn((
Transform::from_xyz(0.0, 0.0, 0.0),
AabbCollider::new(Vec3::new(50.0, 0.1, 50.0)),
));
}
fn read_collisions(mut events: EventReader<CollisionEvent>) {
for event in events.read() {
log::info!("Hit: {:?} <-> {:?}", event.a, event.b);
}
}Rapier 集成(feature "rapier")
启用 rapier feature 以使用 rapier3d 进行完整的刚体模拟。
RapierPhysicsPlugin 在 Update 中注册四个系统:
| 系统 | 顺序 | 说明 |
|---|---|---|
sync_to_rapier_system | 第 1 | 从 ECS 的 RigidBody+Collider+Transform 创建 rapier 刚体 |
step_physics_system | 第 2 | 推进 rapier 模拟一个 tick |
sync_from_rapier_system | 第 3 | 将 rapier 位置写回 ECS 的 Transform |
extract_collision_events_system | 第 3 | 从 rapier 窄相检测填充 CollisionEvents |
| 类型 | 说明 |
|---|---|
RapierContext | 持有所有 rapier 状态的 Resource(刚体集合、碰撞体集合、管线等) |
RigidBody | Component:body_type、mass、gravity_scale、is_sensor、damping |
Collider | Component:shape(Sphere/Cuboid/Capsule/TriMesh)、friction、restitution |
RaycastHit | 结果结构体:entity、point、normal、distance |
use anvilkit::prelude::*;
fn setup_rapier(mut commands: Commands) {
// 动态球体
commands.spawn((
Transform::from_xyz(0.0, 10.0, 0.0),
RigidBody::dynamic(),
Collider::sphere(0.5),
Velocity::default(),
));
// 静态地面
commands.spawn((
Transform::default(),
RigidBody::fixed(),
Collider::cuboid(Vec3::new(50.0, 0.1, 50.0)),
));
}
// 射线查询
fn shoot_ray(ctx: Res<RapierContext>) {
if let Some(hit) = ctx.raycast(
Vec3::new(0.0, 5.0, 0.0), // 起点
Vec3::NEG_Y, // 方向
100.0, // 最大距离
) {
log::info!(
"Hit entity {:?} at {} (distance {})",
hit.entity, hit.point, hit.distance
);
}
}