Skip to main content

SoftBody2D

Inherits: Polygon2D

A 2D softbody generated from a texture: one RigidBody2D per region with a CollisionShape2D, Joint2Ds between neighbours, and a Skeleton2D whose bones deform the texture. Everything below is grouped the way the inspector groups it.

Properties

General

PropertyTypeDefaultDescription
draw_regionsboolfalseDraw the generated regions instead of building the softbody, to see how it will be split.
vertex_intervalfloat30Distance between regions, in pixels. Changing it also resets radius to a value derived from it.
bake_scaleVector2(1, 1)Scale baked into the generated geometry. Use it instead of the node's scale, which physics does not support; scaling the node in the editor folds into it. A larger softbody gets more particles of the same size.

Region

PropertyTypeDefaultDescription
pattern_type"hexagon" | "rectangle""hexagon"Layout of the region grid.
exclude_textureTexture2DTexture whose outline is cut out of the softbody, making a hole.
texture_epsilonfloat1Outline simplification; lower keeps more points.
min_alphafloat0.05Alpha above which a pixel counts as part of the texture.
margin_pixelsint0Grows (positive) or shrinks (negative) the outline.
polygon_offsetVector2(0, 0)Shifts the region grid over the texture.
min_areafloat0.2Regions clipped below this share of a full region are merged into a neighbour. Around 0.08 keeps small corners as their own body.

Joint

PropertyTypeDefaultDescription
joint_type"pin" | "spring""pin"PinJoint2D or DampedSpringJoint2D between neighbours.
biasfloat0Joint2D.bias of every joint.
disable_collisionbooltrueJointed bodies do not collide with each other.
joint_reachint2How far joints reach, in hops. 1 joins neighbours only; 2 also joins bodies two hops away, which holds the overall shape; 3 one hop further. See Joints.

| yield_strain | float | 0 | Squeeze past which a joint takes a permanent set (clay); stretching always springs back. 0 is elastic. Interior joints need interior_strength times as much. | | yield_limit | float | 0.3 | Most permanent squeeze a joint may accumulate; past it, it stops yielding. |

Joint / Break

PropertyTypeDefaultDescription
break_modeBreakModeDISTANCEWhich criterion breaks joints. The other modes' settings are hidden.
break_distance_ratiofloat0Distance mode: joints break once stretched this many times their generated distance. 0 disables breaking.
break_forcefloat0Force mode: joints break once the force holding them exceeds this. 0 disables. Needs Rapier.
break_torquefloat0Force mode: joints break once their torque exceeds this. 0 disables. Needs Rapier.
break_smoothingfloat0.5Force mode: 0 breaks on a single spike, closer to 1 needs sustained load.
interior_strengthfloat4Joints between two interior bodies with all their neighbours need this many times the threshold. Tears start at the surface or at existing damage. 1 treats every joint the same.
max_breaks_per_stepint3Most joints that may break in one physics step.

Joint / DampedSpringJoint

PropertyTypeDefaultDescription
stiffnessfloat10DampedSpringJoint2D.stiffness.
dampingfloat0.2DampedSpringJoint2D.damping.
rest_length_ratiofloat0Rest length as a ratio of the generated distance.
length_ratiofloat0Length as a ratio of the generated distance.

Joint / PinJoint

PropertyTypeDefaultDescription
softnessfloat60How far the pins give: the squish. 0 is a rigid truss.
angular_limit_enabledboolfalseBound how far two jointed bodies may twist against each other.
angular_limit_lowerfloat0Lower twist limit, in degrees.
angular_limit_upperfloat0Upper twist limit, in degrees.

Shape

PropertyTypeDefaultDescription
radiusfloat20Shape size: circle radius is half of it, square side is all of it. Set from vertex_interval.
shape_type"Circle" | "Rectangle""Circle"Circles fit the hexagon lattice; squares collide with their own second neighbours once rotated.
edge_clearancefloat-1Least distance a body sits from the outline so its shape stays inside the texture. -1 fits it to the shape automatically, 0 disables.

Skin

PropertyTypeDefaultDescription
skin_smoothingfloat0.5How far the texture blends across region borders. 0 pins each vertex to its own region.

RigidBody

PropertyTypeDefaultDescription
massfloat0.1Mass of every body.
can_sleepbooltrue
gravity_scalefloat1
constant_forceVector2(0, 0)
constant_torquefloat0
collision_layerint1
collision_maskint1
exclude_arrayArray[Node][]Nodes the bodies never collide with.
rigidbody_scenePackedSceneScene with a RigidBody2D root instantiated for every body.
physics_material_overridePhysicsMaterial
linear_dampfloat0
angular_dampfloat0

Debug

PropertyTypeDefaultDescription
debug_drawflags0Joints (bit 1): joints coloured by load, blue slack to red at the break threshold or the peak seen. Shapes (bit 2): collision shapes, green, orange once retired. Draws in the editor and in game.

Methods

MethodDescription
create_softbody2d(runtime: bool = false)Regenerate the softbody. In the editor it runs on any property change; at runtime call it with true after setting the properties.
clear_softbody2d()Remove every generated child, polygon and bone.
create_regions()Generate and draw the regions only.
get_rigid_bodies() -> Array[SoftBodyChild]Every body with its rigidbody, bone, joints and shape.
get_center_body() -> SoftBodyChildThe body nearest the middle.
get_bones_center_position() -> Vector2Centre of all bodies, or the node's position when there are none.
get_clusters() -> ArrayConnected groups of bodies, each an Array[SoftBodyChild]. One after generation, one more per split.
get_joint_target(joint: Joint2D) -> PhysicsBody2DThe body on the far side of a joint.
remove_joint(child: SoftBodyChild, joint: Joint2D)Remove one joint and its reciprocal, split the texture along it, retire a body that lost its last neighbour.
cut(from: Vector2, to: Vector2) -> intRemove every joint crossing the global segment; returns how many.
apply_impulse(impulse: Vector2, position := Vector2.ZERO)Impulse on every body; position is an offset from each body's centre.
apply_force(force: Vector2, position := Vector2.ZERO)Force on every body.
apply_impulse_at_point(impulse: Vector2, global_point: Vector2, falloff_radius := 0.0)Impulse from a world point with the correct lever arm; fades to nothing at falloff_radius if set.

Signals

SignalDescription
baked(body_count: int)Generation finished.
joint_removed(rigid_body_a: SoftBodyChild, rigid_body_b: SoftBodyChild)A joint between these two bodies was removed.
body_detached(rigid_body: SoftBodyChild)A body lost its last neighbour joint and was retired.

Enumerations

enum BreakMode

ValueDescription
NONEJoints never break.
DISTANCEBreak on stretch past break_distance_ratio. Any physics engine.
FORCEBreak on the solver's reaction force past break_force / break_torque. Needs Rapier.

Constants

ConstantValueDescription
MAX_REGIONS400Generation refuses to create more regions than this.
DEBUG_DRAW_JOINTS1Bit of debug_draw.
DEBUG_DRAW_SHAPES2Bit of debug_draw.

Inner classes

SoftBodyChild

One body of the softbody: rigidbody: PhysicsBody2D, bone: Bone2D, joints: Array[Joint2D] (the joints parented to this body; every pair of bodies is joined by one joint, which lives on one of the two), shape: CollisionShape2D.