‹›
Utility Scripts · Body Penetration

Targets and Resistance

A target defines what can be penetrated, how much force it resists and its maximum depth.

jolt_penetration_target(body) prepares an inactive setter object; activate it with set_enabled(true). The explicit (body, config) overload still returns a bool and configures immediately. Use an existing Static or Dynamic non-sensor body. Registration itself does not disable its collisions; a specific pair is suppressed only when a relationship is created.

GML
target_penetration = jolt_penetration_target(target);
target_penetration.set_forward_force(8);
target_penetration.set_backward_force(20);
target_penetration.set_max_depth(0.15);
target_penetration.set_category_bits(1);
if (!target_penetration.set_enabled(true)) show_debug_message(jolt_get_error_message());

get_info() returns a settings copy. Repeating the call for the same body returns the same object. Setters return bool and preserve previous values on failure. The following explicit configuration remains a compatible alternative.

GML
var material = {
    enabled: true,
    category_bits: 1,
    forward_force: 8,
    backward_force: 20,
    max_depth: 0.15
};
if (!jolt_penetration_target(target, material)) {
    show_debug_message(jolt_get_error_message());
}
NameDefault / rangeMeaning
enabledfalse / legacy config: trueEnables new hits on the target.
category_bits1 / uint32Material category bits intersected with tip.mask. This is not a collision-layer ID.
forward_force100 N / ≥ 0Resistance against inward sliding after actual entry.
backward_force300 N / ≥ 0Resistance against extraction. It can differ from insertion resistance.
max_depth0.5 m / > 0Material depth limit. The relationship limit is min(target.max_depth, tip.max_insertion).

What resistance means#

The forces are neither percentages nor friction coefficients. The constraint attempts to bring relative axial speed to zero within forward_force and backward_force limits. Impact energy can overcome resistance even when weight alone is insufficient. For scale, 1 kg at g=9.81 weighs 9.81 N; high resistance can stop further insertion after a valid capture.

Updating configuration#

Every target call rebuilds the full configuration from the supplied values and defaults; it does not merge with the previous material. Keep your own complete material struct when changing one field. Reconfiguring a target involved in relationships is rejected, including attempts to disable it. End the relationships or extract the body first.

Shapes and motion#

Supported solid shapes are Box, Sphere, Capsule, Cylinder, TaperedCapsule, TaperedCylinder and ConvexHull, including compounds from jolt_asset_create_body() or jolt_compound(), child positions and rotations, and COM offsets. Both penetrators and targets are supported. Targets may be Static or Dynamic; Kinematic targets and sensors are rejected. Mesh, HeightField, Plane and ScaledShape are unsupported. A supported shape still has to pass actual entry geometry checks. Resistance, depth and temporary collision suppression apply to the whole body; compound children are not separate material layers.

Verified operation contracts#

These contracts distinguish units, return values, errors and lifetime according to the current implementation. Check results: false, 0 and undefined can mean different things for different methods.

Symbol / ownerSignatureOperation contract
jolt_penetration_targetjolt_penetration_target(body,config=undefined)Body without config returns an inactive JoltPenetrationTarget for setters; explicit config registers immediately and returns Boolean. Defaults forward/backward force 100/300 N, depth 0.5 m, category 1; explicit config defaults enabled true, builder false.
JoltPenetrationTarget.get_infoJoltPenetrationTarget.get_info()is_valid is Boolean host/world state; get_info copies configuration or returns undefined. A valid builder need not be enabled or registered.
JoltPenetrationTarget.is_validJoltPenetrationTarget.is_valid()is_valid is Boolean host/world state; get_info copies configuration or returns undefined. A valid builder need not be enabled or registered.
JoltPenetrationTarget.set_backward_forceJoltPenetrationTarget.set_backward_force(value)Boolean result; enabled Boolean/0/1, finite forces >=0 N, depth >0 m, category integer uint32. Before activation edits config only; after registration respects native busy guards; commits cache only on success.
JoltPenetrationTarget.set_category_bitsJoltPenetrationTarget.set_category_bits(value)Boolean result; enabled Boolean/0/1, finite forces >=0 N, depth >0 m, category integer uint32. Before activation edits config only; after registration respects native busy guards; commits cache only on success.
JoltPenetrationTarget.set_enabledJoltPenetrationTarget.set_enabled(value)Boolean result; enabled Boolean/0/1, finite forces >=0 N, depth >0 m, category integer uint32. Before activation edits config only; after registration respects native busy guards; commits cache only on success.
JoltPenetrationTarget.set_forward_forceJoltPenetrationTarget.set_forward_force(value)Boolean result; enabled Boolean/0/1, finite forces >=0 N, depth >0 m, category integer uint32. Before activation edits config only; after registration respects native busy guards; commits cache only on success.
JoltPenetrationTarget.set_max_depthJoltPenetrationTarget.set_max_depth(value)Boolean result; enabled Boolean/0/1, finite forces >=0 N, depth >0 m, category integer uint32. Before activation edits config only; after registration respects native busy guards; commits cache only on success.