# res://scripts/rig_builder.gd @tool extends Node2D ## Builder script mirroring the exact bone layout, RemoteTransform2D links, ## and IK modifications from the source scene. @export var build_trigger: bool = false: set(val): if val: build_rig() build_trigger = false func build_rig() -> void: for child in get_children(): child.queue_free() name = "Node2D" # 1. Main Hierarchy Containers var sticky := Node2D.new() sticky.name = "Sticky" add_child(sticky) var stickman := Node2D.new() stickman.name = "Stickman" sticky.add_child(stickman) # Container for visual nodes (Line2D / drawn elements) var body := Node2D.new() body.name = "Body" stickman.add_child(body) # Container for skeleton var bones := Node2D.new() bones.name = "Bones" bones.visible = false stickman.add_child(bones) var skeleton := Skeleton2D.new() skeleton.name = "Skeleton2D" bones.add_child(skeleton) # --- 2. BONE HIERARCHY & REMOTE TRANSFORMS --- # Hip (Root Bone) var hip := Bone2D.new() hip.name = "Hip" hip.position = Vector2(-1, 27) hip.rest = Transform2D(0.0, Vector2(0, 32)) skeleton.add_child(hip) # Hip drives main Body visual _create_remote_transform("HipTransform", hip, "../../../../Body/Body", Vector2(0, -24)) # Left Leg var leg_u_l := _create_bone("Leg_Upper_Left", Vector2(-1, 1), hip) _create_remote_transform("RemoteTransform2D", leg_u_l, "../../../../../Body/Leg_Upper_Left", Vector2(1, 0), 2.35619) var leg_l_l := _create_bone("Leg_Lower_Left", Vector2(-8, 8), leg_u_l) leg_l_l.auto_calculate_length_and_angle = false leg_l_l.length = 10.425 leg_l_l.bone_angle = 89.9999 _create_remote_transform("RemoteTransform2D", leg_l_l, "../../../../../../Body/Leg_Lower_Left", Vector2.ZERO, 1.57079) # Right Leg var leg_u_r := _create_bone("Leg_Upper_Right", Vector2(2, 1), hip) _create_remote_transform("RemoteTransform2D", leg_u_r, "../../../../../Body/Leg_Upper_Right", Vector2(-2, 0), 0.785397) var leg_l_r := _create_bone("Leg_Lower_Right", Vector2(7, 8), leg_u_r) leg_l_r.auto_calculate_length_and_angle = false leg_l_r.length = 10.425 leg_l_r.bone_angle = 89.9999 _create_remote_transform("RemoteTransform2D", leg_l_r, "../../../../../../Body/Leg_Lower_Right", Vector2.ZERO, 1.57079) # Left Arm var arm_u_l := _create_bone("Arm_Upper_Left", Vector2(-2, -17), hip) _create_remote_transform("RemoteTransform2D", arm_u_l, "../../../../../Body/Arm_Upper_Left", Vector2(-11, 0)) var arm_l_l := _create_bone("Arm_Lower_Left", Vector2(-11, 0), arm_u_l) arm_l_l.auto_calculate_length_and_angle = false arm_l_l.length = 10.0 arm_l_l.bone_angle = -180.0 _create_remote_transform("RemoteTransform2D", arm_l_l, "../../../../../../Body/Arm_Lower_Left", Vector2(-10, 0)) # Right Arm var arm_u_r := _create_bone("Arm_Upper_Right", Vector2(2, -17), hip) _create_remote_transform("RemoteTransform2D", arm_u_r, "../../../../../Body/Arm_Upper_Right", Vector2.ZERO) var arm_l_r := _create_bone("Arm_Lower_Right", Vector2(11, 0), arm_u_r) arm_l_r.auto_calculate_length_and_angle = false arm_l_r.length = 10.0 arm_l_r.bone_angle = 0.0 _create_remote_transform("RemoteTransform2D", arm_l_r, "../../../../../../Body/Arm_Lower_Right", Vector2.ZERO) # Head var head := _create_bone("Head", Vector2(0, -23), hip) head.rotation = 0.0713012 head.rest = Transform2D( Vector2(2.22127e-06, -1.0), # X-axis basis Vector2(1.0, 2.22127e-06), # Y-axis basis Vector2(0.0, -23.0) # Origin position ) _create_remote_transform("RemoteTransform2D", head, "../../../../../Body/Head", Vector2(-0.498689, -6.98226)) # --- 3. IK TARGET CONTAINERS --- var ik_targets := Node2D.new() ik_targets.name = "IK Targets" sticky.add_child(ik_targets) _create_target("Arm_Left", Vector2(0, 30), ik_targets) _create_target("Arm_Right", Vector2(4, 29), ik_targets) _create_target("Leg_Left", Vector2(-1, 50), ik_targets) _create_target("Leg_Right", Vector2(0, 51), ik_targets) _create_target("Head", Vector2(0, -10), ik_targets) # Body target uses RemoteTransform2D to move Hip bone position var body_target := _create_target("Body", Vector2(-3, -4), ik_targets) _create_remote_transform("RemoteTransform2D", body_target, "../../../Stickman/Bones/Skeleton2D/Hip", Vector2(2, 31)) # --- 4. MODIFICATION STACK & SOLVERS --- var mod_stack := SkeletonModificationStack2D.new() # Leg Left 2-Bone IK var leg_left_ik := SkeletonModification2DTwoBoneIK.new() leg_left_ik.target_nodepath = NodePath("../../../IK Targets/Leg_Left") leg_left_ik.joint_one_bone_idx = 1 leg_left_ik.joint_one_bone2d_node = NodePath("Hip/Leg_Upper_Left") leg_left_ik.joint_two_bone_idx = 2 leg_left_ik.joint_two_bone2d_node = NodePath("Hip/Leg_Upper_Left/Leg_Lower_Left") # Leg Right 2-Bone IK var leg_right_ik := SkeletonModification2DTwoBoneIK.new() leg_right_ik.target_nodepath = NodePath("../../../IK Targets/Leg_Right") leg_right_ik.joint_one_bone_idx = 3 leg_right_ik.joint_one_bone2d_node = NodePath("Hip/Leg_Upper_Right") leg_right_ik.joint_two_bone_idx = 4 leg_right_ik.joint_two_bone2d_node = NodePath("Hip/Leg_Upper_Right/Leg_Lower_Right") # Arm Right 2-Bone IK var arm_right_ik := SkeletonModification2DTwoBoneIK.new() arm_right_ik.target_nodepath = NodePath("../../../IK Targets/Arm_Right") arm_right_ik.flip_bend_direction = true arm_right_ik.joint_one_bone_idx = 7 arm_right_ik.joint_one_bone2d_node = NodePath("Hip/Arm_Upper_Right") arm_right_ik.joint_two_bone_idx = 8 arm_right_ik.joint_two_bone2d_node = NodePath("Hip/Arm_Upper_Right/Arm_Lower_Right") # Arm Left 2-Bone IK var arm_left_ik := SkeletonModification2DTwoBoneIK.new() arm_left_ik.target_nodepath = NodePath("../../../IK Targets/Arm_Left") arm_left_ik.flip_bend_direction = true arm_left_ik.joint_one_bone_idx = 5 arm_left_ik.joint_one_bone2d_node = NodePath("Hip/Arm_Upper_Left") arm_left_ik.joint_two_bone_idx = 6 arm_left_ik.joint_two_bone2d_node = NodePath("Hip/Arm_Upper_Left/Arm_Lower_Left") # Head LookAt Modifier var head_lookat := SkeletonModification2DLookAt.new() head_lookat.bone_index = 9 head_lookat.bone2d_node = NodePath("Hip/Head") head_lookat.target_nodepath = NodePath("../../../IK Targets/Head") head_lookat.enable_constraint = true head_lookat.constraint_angle_min = 65.0 head_lookat.constraint_angle_max = 295.0 head_lookat.constraint_angle_invert = true head_lookat.constraint_in_localspace = true mod_stack.add_modification(leg_left_ik) mod_stack.add_modification(leg_right_ik) mod_stack.add_modification(arm_right_ik) mod_stack.add_modification(arm_left_ik) mod_stack.add_modification(head_lookat) skeleton.set_modification_stack(mod_stack) mod_stack.enabled = true if Engine.is_editor_hint(): _set_owners(self, get_tree().edited_scene_root) func _create_bone(b_name: String, pos: Vector2, parent_node: Node) -> Bone2D: var bone := Bone2D.new() bone.name = b_name bone.position = pos bone.rest = bone.transform parent_node.add_child(bone) return bone func _create_target(t_name: String, pos: Vector2, parent_node: Node) -> Node2D: var target := Node2D.new() target.name = t_name target.position = pos parent_node.add_child(target) return target func _create_remote_transform(rt_name: String, parent_node: Node, target_path: String, pos: Vector2 = Vector2.ZERO, rot: float = 0.0) -> RemoteTransform2D: var rt := RemoteTransform2D.new() rt.name = rt_name rt.position = pos rt.rotation = rot rt.remote_path = NodePath(target_path) parent_node.add_child(rt) return rt func _set_owners(node: Node, scene_root: Node) -> void: for child in node.get_children(): child.owner = scene_root _set_owners(child, scene_root)