Step 2 of the joints: a door that opens by itself, a lift and a piston need a joint that slides along one line and a motor that turns or pushes. A graph also needs to read how far such a joint stands. - Slider: a fifth joint type on Rapier's prismatic joint. Its rail is the joint's own x axis, so turning the joint turns the rail. Joints now carry Scale, Rotation and Mirror like a sprite. - Limit distance with Min and Max, in world units from where the object was placed. - Motor on hinge and slider: Off, Speed or Target, with Motor speed, Motor target and Max force (0 = no limit). Target goes there at no more than the speed and slows down for the last stretch. - Changing speed, target or force keeps the engine joint. Switching the motor on or off builds it again. - New node Joint position: value and speed of a hinge (degrees, counting past a full round) or a slider (world units). - Scene view draws a slider's rail dashed, with a tick at each limit. - shownFor in the schema takes a list of choices that must all hold. Findings, measured with a probe against Rapier 0.20: - A prismatic joint holds both bodies at one angle. Held to the scene or to an object without a rigidbody, the joint's own anchor body is turned by the placed difference, so nothing jumps. Between two rigidbodies the held one is turned to match, and the console says so once. - Rapier reads no joint angle back. The position is worked out from the two bodies. - A hinge motor is weak on a small body at the end of a long arm (box 20 on an arm of 100 does not lift itself). More solver iterations would help but cost every scene. A door of 100 x 20 reaches -90 and holds it. This is written in the wiki. Tests: - Unit: 16 new in joints.test.ts, 1 in joint-links, 3 catalog cases. - e2e 41: 27 checks (25 + 2), block 41f with a real mouse in the inspector and the motor in play (59.1 of 60 units in 1 s). - 9 of 9 unit counter-probes fail as they should. - Gate: 220 files, 3436 tests (3416 + 20), CHECK EXIT 0. - e2e total 1701 is counted (1699 + 2), the full suite did not run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
56 lines
2.3 KiB
TypeScript
56 lines
2.3 KiB
TypeScript
/**
|
|
* A joint ties the object it is placed below to another one (#154): a hinge turns round one point, a
|
|
* spring pulls towards a length, a rope allows no more than one, and a fixed joint keeps the two as
|
|
* they were placed, and a slider lets it glide along one axis only. These are the keys of its rows;
|
|
* what the engine reads off them is in `properties/joint.ts`.
|
|
*/
|
|
export const JOINT_TYPES = ['hinge', 'spring', 'rope', 'fixed', 'slider'] as const;
|
|
export type JointType = (typeof JOINT_TYPES)[number];
|
|
|
|
export const JOINT_TYPE_LABELS: Record<JointType, string> = {
|
|
hinge: 'Hinge',
|
|
spring: 'Spring',
|
|
rope: 'Rope',
|
|
fixed: 'Fixed',
|
|
slider: 'Slider',
|
|
};
|
|
|
|
export const JOINT_TYPE_KEY = 'jointType';
|
|
export const JOINT_CONNECTED_KEY = 'connected';
|
|
export const JOINT_ANCHOR_X_KEY = 'connectedAnchorX';
|
|
export const JOINT_ANCHOR_Y_KEY = 'connectedAnchorY';
|
|
export const JOINT_LENGTH_KEY = 'length';
|
|
export const JOINT_STIFFNESS_KEY = 'stiffness';
|
|
export const JOINT_DAMPING_KEY = 'damping';
|
|
export const JOINT_LIMIT_KEY = 'limitAngle';
|
|
export const JOINT_MIN_ANGLE_KEY = 'minAngle';
|
|
export const JOINT_MAX_ANGLE_KEY = 'maxAngle';
|
|
export const JOINT_LIMIT_DISTANCE_KEY = 'limitDistance';
|
|
export const JOINT_MIN_DISTANCE_KEY = 'minDistance';
|
|
export const JOINT_MAX_DISTANCE_KEY = 'maxDistance';
|
|
export const JOINT_MOTOR_KEY = 'motor';
|
|
export const JOINT_MOTOR_SPEED_KEY = 'motorSpeed';
|
|
export const JOINT_MOTOR_TARGET_KEY = 'motorTarget';
|
|
export const JOINT_MAX_FORCE_KEY = 'maxForce';
|
|
export const JOINT_COLLIDE_KEY = 'collideConnected';
|
|
|
|
/** What a motor on a hinge or a slider does: nothing, turn or glide on, or go to a place and stay. */
|
|
export const JOINT_MOTORS = ['off', 'speed', 'target'] as const;
|
|
export type JointMotor = (typeof JOINT_MOTORS)[number];
|
|
|
|
export const JOINT_MOTOR_LABELS: Record<JointMotor, string> = {
|
|
off: 'Off',
|
|
speed: 'Speed',
|
|
target: 'Target',
|
|
};
|
|
|
|
/** The types that move along one axis, which a motor can drive and a position can be read of. */
|
|
export const AXIS_TYPES: readonly JointType[] = ['hinge', 'slider'];
|
|
|
|
/** The types with a point of their own on the other end; a hinge and a fixed joint have the one they sit on. */
|
|
export const TWO_ANCHOR_TYPES: readonly JointType[] = ['spring', 'rope'];
|
|
|
|
export function hasConnectedAnchor(type: JointType): boolean {
|
|
return TWO_ANCHOR_TYPES.includes(type);
|
|
}
|