1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Port of the event types from include/box3d/types.h (events group).
//
// The C aggregate views (b3SensorEvents, b3ContactEvents, b3BodyEvents,
// b3JointEvents) are pointer+count pairs over world-owned arrays. The Rust
// world API returns slices; BodyEvents/JointEvents collapse to a single
// slice while SensorEvents/ContactEvents keep grouping structs because they
// bundle several arrays.
//
// SPDX-FileCopyrightText: 2025 Erin Catto
// SPDX-License-Identifier: MIT
use crate::id::{BodyId, ContactId, JointId, ShapeId};
use crate::manifold::Manifold;
use crate::math_functions::{Pos, Vec3, WorldTransform};
/// The contact data for solid shape pairs. Manifolds are an owned snapshot of
/// the contact's current manifolds (C exposes a transient pointer).
/// (b3ContactData)
#[derive(Debug, Clone, PartialEq)]
pub struct ContactData {
/// The contact id. May become orphaned; use contact_is_valid before other use.
pub contact_id: ContactId,
/// The first shape id.
pub shape_id_a: ShapeId,
/// The second shape id.
pub shape_id_b: ShapeId,
/// Contact manifolds (owned copy; C: const b3Manifold* + manifoldCount).
pub manifolds: Vec<Manifold>,
}
/// A begin-touch event is generated when a shape starts to overlap a sensor
/// shape. (b3SensorBeginTouchEvent)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SensorBeginTouchEvent {
/// The id of the sensor shape
pub sensor_shape_id: ShapeId,
/// The id of the shape that began touching the sensor shape
pub visitor_shape_id: ShapeId,
}
/// An end touch event is generated when a shape stops overlapping a sensor
/// shape. Always confirm the shape id is valid before use. (b3SensorEndTouchEvent)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SensorEndTouchEvent {
/// The id of the sensor shape. @warning may have been destroyed
pub sensor_shape_id: ShapeId,
/// The id of the shape that stopped touching. @warning may have been destroyed
pub visitor_shape_id: ShapeId,
}
/// Sensor events buffered in the world for the current time step.
/// Borrowed from world storage; invalidated by the next `World::step`.
/// (b3SensorEvents)
#[derive(Debug, Clone, Copy)]
pub struct SensorEvents<'a> {
/// Array of sensor begin touch events
pub begin_events: &'a [SensorBeginTouchEvent],
/// Array of sensor end touch events (previous double-buffer slot)
pub end_events: &'a [SensorEndTouchEvent],
}
/// A begin-touch event is generated when two shapes begin touching.
/// (b3ContactBeginTouchEvent)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContactBeginTouchEvent {
/// Id of the first shape
pub shape_id_a: ShapeId,
/// Id of the second shape
pub shape_id_b: ShapeId,
/// The transient contact id. May be destroyed automatically when the world
/// is modified or simulated.
pub contact_id: ContactId,
}
/// An end touch event is generated when two shapes stop touching.
/// (b3ContactEndTouchEvent)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ContactEndTouchEvent {
/// Id of the first shape. @warning may have been destroyed
pub shape_id_a: ShapeId,
/// Id of the second shape. @warning may have been destroyed
pub shape_id_b: ShapeId,
/// Id of the contact. @warning may have been destroyed
pub contact_id: ContactId,
}
/// A hit touch event is generated when two shapes collide faster than the hit
/// speed threshold. (b3ContactHitEvent)
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ContactHitEvent {
/// Id of the first shape
pub shape_id_a: ShapeId,
/// Id of the second shape
pub shape_id_b: ShapeId,
/// Id of the contact. @warning may have been destroyed
pub contact_id: ContactId,
/// Point where the shapes hit, a mid-point between the two surfaces.
pub point: Pos,
/// Normal vector pointing from shape A to shape B
pub normal: Vec3,
/// The speed the shapes are approaching. Always positive.
pub approach_speed: f32,
/// User material on shape A
pub user_material_id_a: u64,
/// User material on shape B
pub user_material_id_b: u64,
}
/// Body move event, triggered when a body moves due to simulation. Not
/// reported for bodies moved by the user. (b3BodyMoveEvent)
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BodyMoveEvent {
pub user_data: u64,
pub transform: WorldTransform,
pub body_id: BodyId,
pub fell_asleep: bool,
}
/// Joint event, reported for awake joints whose force and/or torque exceed the
/// threshold. (b3JointEvent)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct JointEvent {
/// The joint id
pub joint_id: JointId,
/// The user data from the joint for convenience
pub user_data: u64,
}
/// Contact events buffered in the world after a time step. (b3ContactEvents)
#[derive(Debug, Clone, Copy)]
pub struct ContactEvents<'a> {
pub begin_events: &'a [ContactBeginTouchEvent],
pub end_events: &'a [ContactEndTouchEvent],
pub hit_events: &'a [ContactHitEvent],
}