he3d_physics/lib.rs
1//! HE3D physics — rigid-body dynamics for interactive applications.
2//! HE3D 物理 —— 面向交互式应用的刚体动力学。
3//!
4//! The crate owns its Bodies through a [`BodyId`] and knows nothing about
5//! rendering: it never sees an `ObjectId`, a `Scene`, or a `Transform`. A Body's
6//! placement is a position and an orientation, and the application owns both the
7//! link between a Body and whatever draws it and the per-frame copy of that
8//! placement. See `docs/adr/0001`.
9//! 本 crate 通过 [`BodyId`] 拥有自己的 Body,且对渲染一无所知:它永远看不到
10//! `ObjectId`、`Scene` 或 `Transform`。Body 的摆放是位置与朝向;Body 与"画它的东西"
11//! 之间的联系、以及每帧复制该摆放的动作,都由应用拥有。见 `docs/adr/0001`。
12//!
13//! Bodies come in three motion modes; the one that needs care is
14//! [`MotionType::Kinematic`], driven by a velocity the application sets and
15//! changeable by no Contact. See [`MotionType`].
16//! Body 有三种运动模式;其中需要留意的是 [`MotionType::Kinematic`]:它由应用设定的速度
17//! 驱动,且没有任何 Contact 能改变它。见 [`MotionType`]。
18//!
19//! # Example
20//! 示例
21//! ```
22//! use he3d_math::Vec3;
23//! use he3d_physics::{BodyDesc, ContactPhase, Shape, World};
24//!
25//! let mut world = World::new();
26//!
27//! // Static scenery is just a Body that never moves.
28//! // 静态景物就是一个永不移动的 Body。
29//! world.add_body(
30//! BodyDesc::stationary(Shape::cuboid(Vec3::new(10.0, 0.5, 10.0))).at(Vec3::ZERO),
31//! );
32//! let ball = world.add_body(
33//! BodyDesc::dynamic(Shape::sphere(0.5), 1.0)
34//! .at(Vec3::new(0.0, 8.0, 0.0))
35//! .with_friction(0.45)
36//! .with_restitution(0.3),
37//! );
38//!
39//! // A fixed step; the caller owns the accumulator and the per-frame step cap.
40//! // 固定步长;累加器与每帧步数上限由调用方拥有。
41//! //
42//! // Each step publishes the Contacts it found. Asking that list is the *only* thing
43//! // needed to know whether the ball has touched down: no geometry, no tolerances.
44//! // 每一步都会发布它找到的 Contact。问这个列表就是判断球是否触地所需的**全部**手段:
45//! // 无需几何,无需容差。
46//! let mut touched_down = false;
47//! for _ in 0..240 {
48//! world.step(1.0 / 120.0);
49//! touched_down |= world
50//! .contacts()
51//! .iter()
52//! .any(|contact| contact.involves(ball) && contact.phase != ContactPhase::End);
53//! }
54//! assert!(touched_down, "the ball must reach the floor on the way down");
55//!
56//! // Let it finish bouncing and settle.
57//! // 让它弹完并稳定下来。
58//! for _ in 0..600 {
59//! world.step(1.0 / 120.0);
60//! }
61//! let resting = world.position(ball).expect("the ball exists");
62//! assert!((resting.y - 1.0).abs() < 0.05, "resting at {resting:?} instead");
63//!
64//! // One thing to know before relying on `contacts()`: a Body that has gone to sleep
65//! // stops producing constraints, so its Contacts disappear with it. Ask while the
66//! // Body is awake, or wake it first with [`World::wake`].
67//! // 依赖 `contacts()` 之前要知道一件事:睡着的 Body 不再产生约束,因此它的 Contact 会随
68//! // 之消失。请在 Body 清醒时询问,或先用 [`World::wake`] 唤醒它。
69//! assert!(!world.is_empty());
70//! ```
71
72#![no_std]
73#![forbid(unsafe_code)]
74
75extern crate alloc;
76
77#[cfg(feature = "std")]
78extern crate std;
79
80mod aabb;
81mod body;
82mod broadphase;
83mod contact;
84mod narrowphase;
85mod shape;
86mod solver;
87mod static_geometry;
88mod storage;
89mod world;
90
91pub use aabb::Aabb;
92pub use body::{BodyDesc, BodyId, DEFAULT_FRICTION, MotionType};
93pub use contact::{Contact, ContactPartner, ContactPhase};
94pub use shape::{MassProperties, Shape};
95pub use static_geometry::StaticMeshId;
96pub use world::{
97 DEFAULT_GRAVITY, SLEEP_ANGULAR_THRESHOLD, SLEEP_LINEAR_THRESHOLD, SLEEP_TIME, World,
98};