- Updated BUGS.md with new issues related to selection bounding box, touchpad panning speed, and zooming behavior. - Enhanced PROJECT.md with detailed specifications for touchpad controls, recent colors in the color picker, and a status bar for project information. - Modified project.godot to update compatibility version to 4.7. - Added a status bar in stickman_editor.tscn to display cursor coordinates and snap status. - Updated body_part_panel.gd to handle recent colors and cursor detection over drawing areas. - Enhanced stickman_editor.gd to manage cursor coordinates display and recent colors tracking. - Improved whole_stickman_preview.gd to render selection gizmos on top of other parts. - Created master_rig.tscn for the stickman rig structure with bones and IK targets. - Developed master_rig_builder.gd to automate the rig building process with remote transforms and IK modifications.
208 lines
7.5 KiB
GDScript
208 lines
7.5 KiB
GDScript
# 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)
|