logo
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
use super::*;

/// Joint component. A joint connects two dynamic, or one static and one dynamic, entity physically.
/// It doesn't have to be a component of one of the entities it connects, but that can be convenient at times.
///
/// There are many different kinds of joints. A `Joint` can represent all standard joint types except D6,
/// which we have `D6Joint` for.
///
/// If you don't set a `second_entity`, the joint will be to kind of a static invisible global frame - not super
/// realistic, but often useful.
///
/// Usually accessed through `entity.joint`().
///
/// Most of the time, you'll be better served by a `D6Joint`. `Joint` represent `PhysX`'s legacy joint types. They
/// can be easier to use for simpler applications but `D6Joint` has all the capabilities and are more flexible.



pub struct Joint {
    id: Entity,
}

impl std::fmt::Debug for Joint {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Joint")
            .field("entity", &self.id.name())
            .finish_non_exhaustive()
    }
}

impl Joint {
    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the joint type of the entity.
        ///
        /// Used to set/get the mesh style.
        Joint,
        Type,
        JointType,
        joint_type,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The first entity of the joint.
        Joint,
        FirstEntity,
        Entity,
        first_entity,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The second entity of the joint.
        Joint,
        SecondEntity,
        Entity,
        second_entity,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The location on the first entity that the joint is attached to.
        Joint,
        FirstOffset,
        Vec3,
        first_offset,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The location on the second entity that the joint is attached to.
        Joint,
        SecondOffset,
        Vec3,
        second_offset,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The orientation of the joint on the second entity that the joint is attached to.
        /// For hinge joints, the default is the exact X axis, rotated by this orientation.
        Joint,
        FirstOrientation,
        Quat,
        first_orientation,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The orientation of the joint on the second entity that the joint is attached to.
        /// For hinge joints, the default is the exact X axis, rotated by this orientation.
        Joint,
        SecondOrientation,
        Quat,
        second_orientation,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The limit bounds of a joint. x is min, y is max, what exactly it limits depends on the joint type:
        /// * Ball joint: x is the y angle limit of the cone (around the x axis), while y sets the z angle limit.
        /// * Hinge: x is the lower angle limit, y is the upper angle limit.
        /// * Slider: x is the lower position limit, y is the upper position limit.
        /// * Distance: x is the minimum distance, y is the maximum distance.
        Joint,
        Limits,
        Vec2,
        limits,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The limit type of a joint.
        Joint,
        LimitType,
        JointLimitType,
        limit_type,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The joint velocity (angular for hinge joints, linear for linear joints).
        /// Can only be retrieved for now, need to use forces to change it.
        Joint,
        Velocity,
        f32,
        velocity,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// Turns on joint drive. Currently only works with Hinge joints. `D6Joint` has more flexible drive capabilities, though.
        Joint,
        DriveEnabled,
        bool,
        drive_enable,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// The drive velocity. Does nothing unless `drive_enable` is set to true.
        Joint,
        DriveVelocity,
        f32,
        drive_velocity,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Sets the maximum force the joint drive can exercise.
        Joint,
        DriveForceLimit,
        f32,
        drive_force_limit,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Sets the gear ratio of the joint drive.
        Joint,
        DriveGearRatio,
        f32,
        drive_gear_ratio,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Enables freespin on the joint drive (it'll continue to spin by inertia if you
        /// turn off the drive).
        Joint,
        DriveFreespin,
        bool,
        drive_freespin,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Sets the force threshold for breaking the joint. Default is std::f32::MAX (effectively unbreakable).
        Joint,
        BreakForce,
        f32,
        break_force,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Sets the torque threshold for breaking the joint. Default is std::f32::MAX (effectively unbreakable).
        Joint,
        BreakTorque,
        f32,
        break_torque,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Lets you check whether the joint is broken. Cannot be modified.
        Joint,
        IsBroken,
        bool,
        is_broken,
        ValueAccessorRead
    );

    impl_world_accessor!(
        /// Lets you check the angles or position of the joint. Interpreted differently depending on the joint type:
        /// - Hinge: x means the angle. You can use `hinge_angle` instead.
        /// - Ball: y means the y-angle, z means the z-angle. You can use `ball_swing_angles` instead.
        /// - Linear: x means the position along the joint. You can use `linear_position` instead.
        Joint,
        AngleOrPosition,
        Vec3,
        angle_or_position,
        ValueAccessorRead
    );

    /// Utility function for `angle_or_position`: If the joint is a hinge, returns the angle directly.
    pub fn hinge_angle(&self) -> f32 {
        self.angle_or_position().get().x
    }

    /// Utility function: If the joint is linear, returns the position along the line directly.
    pub fn linear_position(&self) -> f32 {
        self.angle_or_position().get().x
    }

    /// Utility function: If the joint is a ball joint, return the swing angles.
    pub fn ball_swing_angles(&self) -> Vec2 {
        Vec2::new(
            self.angle_or_position().get().y,
            self.angle_or_position().get().z,
        )
    }
}

impl_world_component!(Joint);