extends Node3D class_name AnimeMechaKit ## High-detail, game-native anime mecha frame layered over an authored pilot. ## ## Each equipment group is built from many small mechanical forms, then merged ## into one ArrayMesh surface per material. The result keeps panel seams, ## vents, pistons, cabling, fasteners and nested thruster hardware without ## turning every visual detail into a draw call. Bone-rest correction makes the ## same frame fit Mixamo, Auto-Rig Pro and Rigify-style skeleton axes. const ARMOR := 0 const ARMOR_ALT := 1 const FRAME := 2 const ACCENT := 3 const GLOW := 4 const METAL := 5 const THEMES := { "sakura": { "armor": Color("e8edf4"), "armor_alt": Color("737d9e"), "frame": Color("303852"), "accent": Color("d95291"), "glow": Color("ff9fd0"), "metal": Color("171b2e"), }, "akiba": { "armor": Color("242a3a"), "armor_alt": Color("dfe7ef"), "frame": Color("111622"), "accent": Color("20c9df"), "glow": Color("ff45ba"), "metal": Color("080b12"), }, } class Assembly: var parent: Node3D var surfaces: Dictionary = {} var materials: Dictionary = {} var part_count := 0 func _init(target: Node3D) -> void: parent = target func add(mesh: Mesh, transform: Transform3D, slot: int, material: Material) -> void: var surface: SurfaceTool = surfaces.get(slot) if surface == null: surface = SurfaceTool.new() surfaces[slot] = surface materials[slot] = material surface.append_from(mesh, 0, transform) part_count += 1 func commit(node_name: String) -> MeshInstance3D: var combined := ArrayMesh.new() var slots: Array = surfaces.keys() slots.sort() for slot in slots: var surface: SurfaceTool = surfaces[slot] surface.set_material(materials[slot]) surface.commit(combined) var instance := MeshInstance3D.new() instance.name = node_name instance.mesh = combined parent.add_child(instance) return instance var _skeleton: Skeleton3D var _roles: Dictionary = {} var _theme: Dictionary = {} var _materials: Dictionary = {} var _nozzles: Array[Node3D] = [] var _attachments: Array[BoneAttachment3D] = [] var _detail_parts := 0 var _helmet_progress := 0.0 var _helmet_target := 0.0 var _helmet_fx_left := 0.0 var _visor_left: MeshInstance3D var _visor_right: MeshInstance3D var _jaw_left: MeshInstance3D var _jaw_right: MeshInstance3D var _helmet_scan: MeshInstance3D var _helmet_sweep: MeshInstance3D var _helmet_light: OmniLight3D var _helmet_fx_material: StandardMaterial3D func setup(skeleton: Skeleton3D, roles: Dictionary, theme_name: String) -> void: _skeleton = skeleton _roles = roles _theme = THEMES.get(theme_name, THEMES["sakura"]) _build_materials() if theme_name == "sakura": # The hero pilot is one continuous robotic second skin. Its thin shells # follow the authored anatomy instead of hanging equipment boxes from it. _build_second_skin_torso() _build_second_skin_waist() _build_second_skin_limbs() _build_second_skin_nozzles() _build_deployable_helmet() else: # Preserve the alternate skin while the hero design is being focused. _build_torso() _build_waist() _build_limbs() _build_nozzles() set_process(true) func _process(delta: float) -> void: if not is_instance_valid(_visor_left): return var blend := 1.0 - exp(-12.0 * delta) _helmet_progress = lerpf(_helmet_progress, _helmet_target, blend) if absf(_helmet_progress - _helmet_target) < 0.001: _helmet_progress = _helmet_target _update_helmet_parts(_helmet_progress) if _helmet_fx_left <= 0.0: _helmet_scan.visible = false _helmet_sweep.visible = false _helmet_light.light_energy = 0.0 return _helmet_fx_left = maxf(0.0, _helmet_fx_left - delta) var phase := 1.0 - _helmet_fx_left / 0.38 var flash := sin(phase * PI) _helmet_scan.visible = true _helmet_scan.scale = Vector3.ONE * lerpf(0.55, 1.65, phase) _helmet_scan.rotation.z = phase * PI * 0.65 _helmet_sweep.visible = true _helmet_sweep.position.x = lerpf(-0.105, 0.105, phase) _helmet_light.light_energy = 2.8 * flash var alpha := flash * 0.82 _helmet_fx_material.albedo_color.a = alpha func set_helmet_closed(closed: bool, immediate: bool = false) -> void: var wanted := 1.0 if closed else 0.0 if is_equal_approx(wanted, _helmet_target) and not immediate: return _helmet_target = wanted if immediate: _helmet_progress = wanted _update_helmet_parts(wanted) return _helmet_fx_left = 0.38 func toggle_helmet() -> void: set_helmet_closed(_helmet_target < 0.5) func helmet_closed() -> bool: return _helmet_target > 0.5 func helmet_progress_debug() -> float: return _helmet_progress func _build_second_skin_torso() -> void: var chest := _attachment(_chest_bone(), "SecondSkinTorso") if chest == null: return var a := Assembly.new(chest) # A continuous dermal chassis sits only millimetres outside the authored # bodysuit. Broad ellipsoids preserve the waist/chest curves; all brighter # geometry below is inset-looking surfacing rather than a floating breastplate. _ellipsoid(a, Vector3(0.335, 0.350, 0.176), Vector3(0.0, -0.030, 0.0), FRAME) _ellipsoid(a, Vector3(0.300, 0.265, 0.220), Vector3(0.0, -0.235, -0.018), FRAME) _capsule_plate(a, Vector3(0.046, 0.225, 0.010), Vector3(0.0, -0.018, -0.095), METAL) _capsule_plate(a, Vector3(0.012, 0.178, 0.005), Vector3(0.0, -0.010, -0.103), GLOW) for side in [-1.0, 1.0]: # Three flexible pectoral laminates follow muscle flow into the ribs. for panel in 3: var y := 0.072 - panel * 0.067 var width := 0.128 - panel * 0.018 _capsule_plate(a, Vector3(width, 0.043, 0.009), Vector3((0.070 + width * 0.14) * side, y, -0.092), ARMOR if panel == 0 else ARMOR_ALT, Vector3(0.0, 0.0, (-0.16 + panel * 0.035) * side)) _capsule_plate(a, Vector3(width * 0.62, 0.005, 0.004), Vector3((0.078 + width * 0.10) * side, y - 0.024, -0.100), ACCENT, Vector3(0.0, 0.0, -0.13 * side)) # Collar laminates grow out of the chest shell and terminate at the arm. _capsule_plate(a, Vector3(0.142, 0.036, 0.012), Vector3(0.078 * side, 0.142, -0.062), ARMOR, Vector3(0.0, 0.0, -0.20 * side)) _capsule_plate(a, Vector3(0.090, 0.006, 0.004), Vector3(0.084 * side, 0.151, -0.073), GLOW, Vector3(0.0, 0.0, -0.20 * side)) # The rear reads as an artificial spinal system, not a backpack. _capsule_plate(a, Vector3(0.052, 0.270, 0.014), Vector3(0.0, -0.018, 0.096), METAL) for vertebra in 7: var y := 0.108 - vertebra * 0.037 _ellipsoid(a, Vector3(0.054, 0.022, 0.015), Vector3(0.0, y, 0.105), ARMOR_ALT) _sphere(a, 0.0045, Vector3(0.0, y, 0.115), GLOW, 8) for side in [-1.0, 1.0]: for rail in 4: _capsule_plate(a, Vector3(0.012, 0.040, 0.008), Vector3((0.070 + rail * 0.022) * side, 0.075 - rail * 0.052, 0.091), ACCENT, Vector3(0.0, 0.0, 0.16 * side)) _detail_parts += a.part_count a.commit("SecondSkinTorsoCombined") func _build_second_skin_waist() -> void: var hips := _attachment(_role_bone("hips"), "SecondSkinWaist") if hips == null: return var a := Assembly.new(hips) _ellipsoid(a, Vector3(0.310, 0.320, 0.205), Vector3(0.0, 0.115, 0.0), FRAME) _capsule_plate(a, Vector3(0.095, 0.060, 0.018), Vector3(0.0, 0.012, -0.067), ARMOR_ALT) _capsule_plate(a, Vector3(0.038, 0.038, 0.008), Vector3(0.0, 0.014, -0.080), GLOW) for side in [-1.0, 1.0]: _ellipsoid(a, Vector3(0.112, 0.145, 0.094), Vector3(0.120 * side, -0.060, -0.002), FRAME) _capsule_plate(a, Vector3(0.060, 0.105, 0.008), Vector3(0.145 * side, -0.052, -0.044), ARMOR_ALT, Vector3(0.0, 0.0, 0.10 * side)) _capsule_plate(a, Vector3(0.010, 0.090, 0.005), Vector3(0.158 * side, -0.050, -0.053), ACCENT, Vector3(0.0, 0.0, 0.10 * side)) for seam in 3: _sphere(a, 0.006, Vector3((0.094 + seam * 0.024) * side, -0.002, 0.060), GLOW, 8) _detail_parts += a.part_count a.commit("SecondSkinWaistCombined") func _build_second_skin_limbs() -> void: for side_name in ["L", "R"]: var side := -1.0 if side_name == "L" else 1.0 _build_second_skin_shoulder(side_name, side) _build_second_skin_segment("upper_arm.%s" % side_name, "UpperArm%s" % side_name, 0.165, 0.130, 0.245, 0.145, side) _build_second_skin_segment("forearm.%s" % side_name, "Forearm%s" % side_name, 0.158, 0.112, 0.265, 0.138, side) _build_second_skin_hand(side_name, side) _build_second_skin_segment("thigh.%s" % side_name, "Thigh%s" % side_name, 0.195, 0.148, 0.315, 0.178, side, true) _build_second_skin_segment("shin.%s" % side_name, "Shin%s" % side_name, 0.158, 0.112, 0.350, 0.142, side, true) _build_second_skin_boot(side_name, side) func _build_second_skin_shoulder(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("upper_arm.%s" % side_name), "SecondSkinShoulder%s" % side_name) if mount == null: return var a := Assembly.new(mount) # A soft deltoid shell, continuous with the upper-arm membrane. The only # hard edge is the clavicle seam; there is no independent shoulder pauldron. _ellipsoid(a, Vector3(0.172, 0.112, 0.148), Vector3(0.0, -0.010, 0.0), FRAME) _capsule_plate(a, Vector3(0.128, 0.040, 0.009), Vector3(0.0, 0.032, -0.071), ARMOR_ALT) _capsule_plate(a, Vector3(0.090, 0.006, 0.004), Vector3(0.0, 0.042, -0.078), GLOW) for seam in [-1.0, 1.0]: _capsule_plate(a, Vector3(0.008, 0.062, 0.004), Vector3(0.044 * seam, -0.005, -0.073), ACCENT, Vector3(0.0, 0.0, 0.15 * seam * side)) _detail_parts += a.part_count a.commit("SecondSkinShoulderCombined") func _build_second_skin_segment(role: String, node_name: String, top_width: float, bottom_width: float, length: float, depth: float, side: float, leg: bool = false) -> void: var mount := _attachment(_role_bone(role), "SecondSkin%s" % node_name) if mount == null: return var a := Assembly.new(mount) var center := -length * (0.25 if node_name.begins_with("Thigh") \ else (0.47 if leg else 0.47)) # One smooth dermal sleeve. A rounded anatomical volume avoids the flat ends # and ruler-straight sides that make a tapered cylinder read as a strapped-on # greave; the authored animation still supplies the underlying muscle motion. _ellipsoid(a, Vector3((top_width + bottom_width) * 0.54, length, depth), Vector3(0.0, center, 0.0), FRAME) # Flush pearlescent laminates occupy only the front/outer quadrant and share # the underlying limb curvature instead of forming a box around it. _capsule_plate(a, Vector3(top_width * 0.30, length * 0.48, 0.007), Vector3(0.0, center, -depth * 0.515), ARMOR) _capsule_plate(a, Vector3(top_width * 0.15, length * 0.34, 0.005), Vector3(top_width * 0.20 * side, center - length * 0.02, -depth * 0.53), ARMOR_ALT) _capsule_plate(a, Vector3(0.007, length * 0.70, 0.004), Vector3(top_width * 0.13 * side, center, -depth * 0.56), GLOW) # Two transverse flex seams articulate the synthetic muscle without adding # rings around the silhouette. for seam_at in [0.34, 0.68]: var seam_y: float = -length * float(seam_at) _capsule_plate(a, Vector3(top_width * 0.40, 0.005, 0.0035), Vector3(-top_width * 0.05 * side, seam_y, -depth * 0.545), METAL, Vector3(0.0, 0.0, 0.08 * side)) _sphere(a, 0.0045 if leg else 0.0038, Vector3(top_width * 0.37 * side, seam_y, -depth * 0.40), ACCENT, 8) # A calf/thigh rear tendon gives the long leg a technological line without # broadening it into greaves. if leg: _capsule_plate(a, Vector3(0.010, length * 0.60, 0.006), Vector3(-top_width * 0.28 * side, center, depth * 0.49), ACCENT) _detail_parts += a.part_count a.commit("SecondSkin%sCombined" % node_name) func _build_second_skin_hand(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("hand.%s" % side_name), "SecondSkinHand%s" % side_name) if mount == null: return var a := Assembly.new(mount) # A flexible palm/knuckle membrane leaves finger articulation readable while # visually continuing the forearm shell through the wrist. _ellipsoid(a, Vector3(0.092, 0.118, 0.050), Vector3(0.0, -0.043, 0.0), FRAME) _capsule_plate(a, Vector3(0.050, 0.070, 0.005), Vector3(0.010 * side, -0.048, -0.028), ARMOR_ALT, Vector3(0.0, 0.0, 0.10 * side)) _capsule_plate(a, Vector3(0.005, 0.068, 0.003), Vector3(-0.020 * side, -0.048, -0.032), GLOW) _detail_parts += a.part_count a.commit("SecondSkinHandCombined%s" % side_name) func _build_second_skin_boot(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("foot.%s" % side_name), "SecondSkinBoot%s" % side_name) if mount == null: return var a := Assembly.new(mount) _ellipsoid(a, Vector3(0.138, 0.086, 0.214), Vector3(0.0, -0.012, -0.050), FRAME) _ellipsoid(a, Vector3(0.116, 0.032, 0.166), Vector3(0.0, 0.024, -0.069), ARMOR) _capsule_plate(a, Vector3(0.010, 0.008, 0.112), Vector3(0.026 * side, 0.034, -0.070), GLOW) for tread in 4: _capsule_plate(a, Vector3(0.074, 0.007, 0.016), Vector3(0.0, -0.047, -0.116 + tread * 0.039), METAL) _detail_parts += a.part_count a.commit("SecondSkinBootCombined") func _build_second_skin_nozzles() -> void: for i in 4: var nozzle := Node3D.new() nozzle.name = "DorsalVectorJet%s" % ("L" if i == 0 else "R") \ if i < 2 else "HeelVectorJet%s" % ("L" if i == 2 else "R") nozzle.set_meta("mecha_thruster", true) add_child(nozzle) _nozzles.append(nozzle) var a := Assembly.new(nozzle) var k := 1.0 if i < 2 else 0.66 # A compact vector nozzle is the one unapologetically external tool. Its # tapered root appears to grow through a reinforced pore in the second skin; # no flower ring or floating satellite housing competes with the body. _ellipsoid(a, Vector3(0.082, 0.064, 0.108) * k, Vector3(0.0, 0.0, 0.050 * k), FRAME) _cylinder(a, 0.042 * k, 0.032 * k, 0.072 * k, Vector3(0.0, 0.0, 0.025 * k), Vector3(PI * 0.5, 0.0, 0.0), METAL, 16) _torus(a, 0.022 * k, 0.043 * k, Vector3.ZERO, Vector3(PI * 0.5, 0.0, 0.0), ACCENT, 16, 6) _cylinder(a, 0.022 * k, 0.016 * k, 0.040 * k, Vector3(0.0, 0.0, 0.018 * k), Vector3(PI * 0.5, 0.0, 0.0), METAL, 16) _cylinder(a, 0.015 * k, 0.015 * k, 0.006 * k, Vector3.ZERO, Vector3(PI * 0.5, 0.0, 0.0), GLOW, 16) for shroud in 3: var angle := shroud * TAU / 3.0 + PI * 0.5 _capsule_plate(a, Vector3(0.010, 0.034, 0.006) * k, Vector3(cos(angle) * 0.039 * k, sin(angle) * 0.039 * k, 0.052 * k), ARMOR, Vector3(0.0, 0.0, angle)) _sphere(a, 0.004 * k, Vector3(cos(angle) * 0.032 * k, sin(angle) * 0.032 * k, 0.074 * k), GLOW, 8) _detail_parts += a.part_count a.commit("VectorJetCombined") func _build_deployable_helmet() -> void: var head := _attachment(_role_bone("head"), "DeployableHelmet") if head == null: return var shell := Assembly.new(head) # Rear crown, temple rails, and cheek hinges stay visible when open; they # make the visor feel stored inside a robotic cranial frame. # Open-sided crown rails leave hair and face readable. A full ellipsoid here # would become a solid mask under cel rendering even while the visor is open. for side in [-1.0, 1.0]: _capsule_plate(shell, Vector3(0.034, 0.135, 0.020), Vector3(0.074 * side, 0.062, 0.080), FRAME, Vector3(0.10, 0.0, 0.18 * side)) _capsule_plate(shell, Vector3(0.022, 0.105, 0.012), Vector3(0.058 * side, 0.100, 0.094), ARMOR, Vector3(0.14, 0.0, 0.28 * side)) _capsule_plate(shell, Vector3(0.060, 0.082, 0.015), Vector3(0.0, 0.104, -0.070), ARMOR_ALT) _capsule_plate(shell, Vector3(0.013, 0.066, 0.006), Vector3(0.0, 0.108, -0.081), GLOW) for side in [-1.0, 1.0]: _capsule_plate(shell, Vector3(0.027, 0.110, 0.018), Vector3(0.091 * side, 0.018, -0.006), ARMOR_ALT, Vector3(0.0, 0.0, 0.12 * side)) _torus(shell, 0.013, 0.030, Vector3(0.095 * side, 0.002, -0.050), Vector3(PI * 0.5, 0.0, 0.0), ACCENT, 12, 5) for port in 3: _sphere(shell, 0.005, Vector3(0.096 * side, 0.067 - port * 0.028, -0.054), GLOW, 8) _detail_parts += shell.part_count shell.commit("HelmetCranialFrameCombined") var visor_mat := _visor_material(_theme["glow"]) _visor_left = _helmet_ellipsoid(head, "VisorLeft", visor_mat) _visor_right = _helmet_ellipsoid(head, "VisorRight", visor_mat) _jaw_left = _helmet_ellipsoid(head, "JawSealLeft", _materials[FRAME]) _jaw_right = _helmet_ellipsoid(head, "JawSealRight", _materials[FRAME]) _helmet_fx_material = _visor_material(_theme["glow"]) _helmet_fx_material.albedo_color = Color(_theme["glow"], 0.78) _helmet_fx_material.emission_energy_multiplier = 4.0 _helmet_scan = MeshInstance3D.new() _helmet_scan.name = "HelmetDeployRing" var ring := TorusMesh.new() ring.inner_radius = 0.072 ring.outer_radius = 0.078 ring.rings = 24 ring.ring_segments = 5 _helmet_scan.mesh = ring _helmet_scan.material_override = _helmet_fx_material _helmet_scan.rotation.x = PI * 0.5 _helmet_scan.position = Vector3(0.0, 0.120, 0.235) _helmet_scan.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF head.add_child(_helmet_scan) _helmet_sweep = MeshInstance3D.new() _helmet_sweep.name = "HelmetVisorSweep" var sweep_mesh := CapsuleMesh.new() sweep_mesh.radius = 0.004 sweep_mesh.height = 0.080 sweep_mesh.radial_segments = 8 _helmet_sweep.mesh = sweep_mesh _helmet_sweep.material_override = _helmet_fx_material _helmet_sweep.position = Vector3(0.0, 0.120, 0.242) _helmet_sweep.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF head.add_child(_helmet_sweep) _helmet_light = OmniLight3D.new() _helmet_light.name = "HelmetDeployFlash" _helmet_light.light_color = _theme["glow"] _helmet_light.omni_range = 1.25 _helmet_light.shadow_enabled = false _helmet_light.position = Vector3(0.0, 0.120, 0.275) head.add_child(_helmet_light) _detail_parts += 8 _update_helmet_parts(0.0) func _helmet_ellipsoid(parent: Node3D, node_name: String, material: Material) -> MeshInstance3D: var node := MeshInstance3D.new() node.name = node_name var mesh := SphereMesh.new() mesh.radius = 0.5 mesh.height = 1.0 mesh.radial_segments = 16 mesh.rings = 8 node.mesh = mesh node.material_override = material node.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF parent.add_child(node) return node func _update_helmet_parts(amount: float) -> void: var t := smoothstep(0.0, 1.0, amount) # Two translucent robotic lenses iris out from the temples and lock on the # centerline. Opening reverses the same physical path into the crown rails. _visor_left.position = Vector3(lerpf(-0.082, -0.026, t), lerpf(0.105, 0.142, t), lerpf(-0.040, 0.205, t)) _visor_right.position = Vector3(lerpf(0.082, 0.026, t), lerpf(0.105, 0.142, t), lerpf(-0.040, 0.205, t)) _visor_left.scale = Vector3(0.060, lerpf(0.009, 0.022, t), 0.014) _visor_right.scale = Vector3(0.060, lerpf(0.009, 0.022, t), 0.014) _visor_left.rotation.z = lerpf(-0.72, -0.24, t) _visor_right.rotation.z = lerpf(0.72, 0.24, t) _jaw_left.position = Vector3(lerpf(-0.110, -0.075, t), lerpf(-0.010, 0.018, t), lerpf(-0.025, 0.205, t)) _jaw_right.position = Vector3(lerpf(0.110, 0.075, t), lerpf(-0.010, 0.018, t), lerpf(-0.025, 0.205, t)) _jaw_left.scale = Vector3(0.038, lerpf(0.030, 0.082, t), 0.018) _jaw_right.scale = Vector3(0.038, lerpf(0.030, 0.082, t), 0.018) _jaw_left.rotation.z = lerpf(-0.65, -0.28, t) _jaw_right.rotation.z = lerpf(0.65, 0.28, t) func _visor_material(color: Color) -> StandardMaterial3D: var material := StandardMaterial3D.new() material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA material.blend_mode = BaseMaterial3D.BLEND_MODE_MIX material.cull_mode = BaseMaterial3D.CULL_DISABLED material.albedo_color = Color(_theme["frame"], 0.84) material.emission_enabled = true material.emission = _theme["accent"] material.emission_energy_multiplier = 1.15 return material func _build_materials() -> void: _materials = { ARMOR: _armor_material(_theme["armor"]), ARMOR_ALT: _armor_material(_theme["armor_alt"]), FRAME: _armor_material(_theme["frame"]), ACCENT: _armor_material(_theme["accent"]), GLOW: _glow_material(_theme["glow"]), METAL: _armor_material(_theme["metal"]), } func _build_torso() -> void: var chest := _attachment(_chest_bone(), "MechaTorso") if chest == null: return var a := Assembly.new(chest) # Body-hugging backpack frame and central reactor spine. Rounded capsules # overlap like vertebral armor instead of reading as a refrigerator slab. _capsule_plate(a, Vector3(0.235, 0.255, 0.052), Vector3(0.0, 0.0, 0.112), FRAME) _capsule_plate(a, Vector3(0.195, 0.215, 0.027), Vector3(0.0, 0.0, 0.157), ARMOR_ALT) _capsule_plate(a, Vector3(0.075, 0.175, 0.025), Vector3(0.0, 0.012, 0.180), ARMOR) _capsule_plate(a, Vector3(0.026, 0.135, 0.010), Vector3(0.0, 0.015, 0.200), ACCENT) _cylinder(a, 0.044, 0.050, 0.026, Vector3(0.0, 0.025, 0.213), Vector3(PI * 0.5, 0.0, 0.0), FRAME, 16) _torus(a, 0.023, 0.046, Vector3(0.0, 0.025, 0.229), Vector3(PI * 0.5, 0.0, 0.0), ACCENT) _cylinder(a, 0.021, 0.021, 0.007, Vector3(0.0, 0.025, 0.236), Vector3(PI * 0.5, 0.0, 0.0), GLOW, 16) # Radiator vanes make the backpack read at distance and break up the slab. for vane in 7: var y := -0.090 + vane * 0.030 _capsule_plate(a, Vector3(0.165, 0.009, 0.016), Vector3(0.0, y, 0.205), METAL) for side in [-1.0, 1.0]: # Shoulder-side power modules, coolant bottles and exposed conduits. _tapered_shell(a, 0.070, 0.050, 0.170, 0.056, Vector3(0.145 * side, -0.005, 0.126), FRAME, Vector3(0.0, 0.0, -0.08 * side)) _capsule_plate(a, Vector3(0.058, 0.145, 0.020), Vector3(0.147 * side, 0.0, 0.169), ARMOR, Vector3(0.0, 0.0, -0.08 * side)) _capsule_plate(a, Vector3(0.025, 0.095, 0.009), Vector3(0.149 * side, 0.005, 0.186), ACCENT) _cylinder(a, 0.021, 0.021, 0.135, Vector3(0.116 * side, -0.020, 0.190), Vector3(0.0, 0.0, 0.0), METAL, 10) _cylinder(a, 0.014, 0.014, 0.112, Vector3(0.178 * side, -0.025, 0.178), Vector3(0.0, 0.0, 0.0), ACCENT, 10) for bolt_y in [-0.072, 0.072]: _cylinder(a, 0.010, 0.010, 0.008, Vector3(0.178 * side, bolt_y, 0.194), Vector3(PI * 0.5, 0.0, 0.0), METAL, 8) # Front chest armor: floating plate, inset seam and collar latch. _capsule_plate(a, Vector3(0.105, 0.125, 0.025), Vector3(0.060 * side, -0.020, -0.076), ARMOR, Vector3(0.0, 0.0, 0.10 * side)) _capsule_plate(a, Vector3(0.072, 0.080, 0.010), Vector3(0.056 * side, -0.018, -0.094), ARMOR_ALT, Vector3(0.0, 0.0, 0.10 * side)) _capsule_plate(a, Vector3(0.056, 0.010, 0.006), Vector3(0.052 * side, 0.004, -0.103), ACCENT, Vector3(0.0, 0.0, 0.10 * side)) _capsule_plate(a, Vector3(0.015, 0.045, 0.006), Vector3(0.015 * side, 0.045, -0.104), GLOW, Vector3(0.0, 0.0, 0.10 * side)) # Articulated-looking dorsal fin: spar, armor leaves and luminous edge. _capsule_plate(a, Vector3(0.018, 0.195, 0.016), Vector3(0.195 * side, 0.015, 0.137), METAL, Vector3(0.0, 0.0, -0.18 * side)) for segment in 3: var sy := -0.058 + segment * 0.058 var reach := 0.064 - segment * 0.008 _capsule_plate(a, Vector3(reach, 0.040, 0.014), Vector3((0.211 + reach * 0.28) * side, sy, 0.137), ARMOR if segment % 2 == 0 else ARMOR_ALT, Vector3(0.0, 0.0, -0.22 * side)) _capsule_plate(a, Vector3(0.008, 0.172, 0.007), Vector3(0.230 * side, 0.014, 0.148), ACCENT, Vector3(0.0, 0.0, -0.18 * side)) _detail_parts += a.part_count a.commit("TorsoFrameCombined") func _build_waist() -> void: var hips := _attachment(_role_bone("hips"), "MechaWaist") if hips == null: return var a := Assembly.new(hips) _capsule_plate(a, Vector3(0.245, 0.060, 0.072), Vector3(0.0, 0.015, 0.0), FRAME) _capsule_plate(a, Vector3(0.082, 0.072, 0.022), Vector3(0.0, 0.015, -0.052), ARMOR) _capsule_plate(a, Vector3(0.042, 0.035, 0.008), Vector3(0.0, 0.018, -0.068), ACCENT) _sphere(a, 0.010, Vector3(0.0, 0.018, -0.075), GLOW, 8) for side in [-1.0, 1.0]: _capsule_plate(a, Vector3(0.066, 0.165, 0.025), Vector3(0.150 * side, -0.078, 0.012), ARMOR, Vector3(0.04, 0.0, 0.15 * side)) _capsule_plate(a, Vector3(0.044, 0.118, 0.011), Vector3(0.153 * side, -0.074, -0.004), ARMOR_ALT, Vector3(0.04, 0.0, 0.15 * side)) _capsule_plate(a, Vector3(0.010, 0.096, 0.006), Vector3(0.174 * side, -0.072, -0.012), ACCENT, Vector3(0.04, 0.0, 0.15 * side)) _cylinder(a, 0.014, 0.014, 0.090, Vector3(0.116 * side, -0.072, 0.028), Vector3(0.0, 0.0, 0.12 * side), METAL, 8) for seam in 3: _capsule_plate(a, Vector3(0.050, 0.006, 0.005), Vector3(0.153 * side, -0.118 + seam * 0.048, -0.020), METAL, Vector3(0.04, 0.0, 0.15 * side)) _detail_parts += a.part_count a.commit("WaistFrameCombined") func _build_limbs() -> void: for side_name in ["L", "R"]: var side := -1.0 if side_name == "L" else 1.0 _build_shoulder(side_name, side) _build_forearm(side_name, side) _build_thigh(side_name, side) _build_shin(side_name, side) _build_boot(side_name, side) func _build_shoulder(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("upper_arm.%s" % side_name), "MechaShoulder%s" % side_name) if mount == null: return var a := Assembly.new(mount) _ellipsoid(a, Vector3(0.145, 0.080, 0.125), Vector3(0.0, 0.025, 0.0), FRAME) _ellipsoid(a, Vector3(0.165, 0.052, 0.100), Vector3(0.0, 0.062, 0.0), ARMOR) _capsule_plate(a, Vector3(0.120, 0.017, 0.060), Vector3(0.0, 0.094, 0.0), ARMOR_ALT) _capsule_plate(a, Vector3(0.080, 0.008, 0.010), Vector3(0.0, 0.108, -0.025), ACCENT) _cylinder(a, 0.027, 0.027, 0.180, Vector3.ZERO, Vector3(0.0, 0.0, PI * 0.5), METAL, 12) _torus(a, 0.018, 0.036, Vector3(0.090 * side, 0.0, 0.0), Vector3(0.0, 0.0, PI * 0.5), ACCENT) for vent in 4: _capsule_plate(a, Vector3(0.010, 0.006, 0.038), Vector3(-0.038 + vent * 0.025, 0.118, 0.018), METAL) for bolt_x in [-0.060, 0.060]: for bolt_z in [-0.040, 0.040]: _sphere(a, 0.008, Vector3(bolt_x, 0.137, bolt_z), ACCENT, 8) _detail_parts += a.part_count a.commit("ShoulderFrameCombined") func _build_forearm(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("forearm.%s" % side_name), "MechaForearm%s" % side_name) if mount == null: return var a := Assembly.new(mount) _tapered_shell(a, 0.100, 0.074, 0.215, 0.080, Vector3(0.0, -0.105, 0.0), FRAME) _capsule_plate(a, Vector3(0.088, 0.145, 0.025), Vector3(0.0, -0.105, -0.060), ARMOR) _capsule_plate(a, Vector3(0.055, 0.100, 0.011), Vector3(0.0, -0.095, -0.078), ARMOR_ALT) _capsule_plate(a, Vector3(0.011, 0.105, 0.006), Vector3(0.026 * side, -0.095, -0.087), ACCENT) _capsule_plate(a, Vector3(0.014, 0.038, 0.007), Vector3(-0.019 * side, -0.125, -0.089), GLOW) for rib in 4: _torus(a, 0.045, 0.060, Vector3(0.0, -0.035 - rib * 0.052, 0.0), Vector3.ZERO, METAL, 10, 5) for bolt_side in [-1.0, 1.0]: for bolt_y in [-0.055, -0.155]: _sphere(a, 0.006, Vector3(0.049 * bolt_side, bolt_y, -0.060), ACCENT, 8) _detail_parts += a.part_count a.commit("ForearmFrameCombined") func _build_thigh(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("thigh.%s" % side_name), "MechaThigh%s" % side_name) if mount == null: return var a := Assembly.new(mount) _tapered_shell(a, 0.120, 0.088, 0.235, 0.082, Vector3(0.0, -0.115, 0.0), FRAME) _capsule_plate(a, Vector3(0.086, 0.175, 0.025), Vector3(0.0, -0.105, -0.060), ARMOR) _capsule_plate(a, Vector3(0.018, 0.140, 0.007), Vector3(0.029 * side, -0.105, -0.078), ACCENT) _capsule_plate(a, Vector3(0.036, 0.090, 0.018), Vector3(0.070 * side, -0.115, 0.0), ARMOR_ALT) _cylinder(a, 0.018, 0.018, 0.165, Vector3(-0.075 * side, -0.110, 0.025), Vector3.ZERO, METAL, 8) for seam in 3: _capsule_plate(a, Vector3(0.060, 0.006, 0.006), Vector3(0.0, -0.055 - seam * 0.062, -0.079), METAL) for bolt_y in [-0.055, -0.175]: _sphere(a, 0.008, Vector3(0.070 * side, bolt_y, -0.090), ACCENT, 8) _detail_parts += a.part_count a.commit("ThighFrameCombined") func _build_shin(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("shin.%s" % side_name), "MechaShin%s" % side_name) if mount == null: return var a := Assembly.new(mount) _tapered_shell(a, 0.118, 0.082, 0.305, 0.086, Vector3(0.0, -0.155, 0.012), FRAME) _capsule_plate(a, Vector3(0.096, 0.235, 0.026), Vector3(0.0, -0.155, -0.062), ARMOR) _capsule_plate(a, Vector3(0.056, 0.180, 0.011), Vector3(0.0, -0.150, -0.081), ARMOR_ALT) _capsule_plate(a, Vector3(0.013, 0.205, 0.006), Vector3(0.029 * side, -0.150, -0.090), ACCENT) _capsule_plate(a, Vector3(0.013, 0.062, 0.007), Vector3(-0.022 * side, -0.195, -0.092), GLOW) # Calf actuator, protective rail and vent bank. _cylinder(a, 0.022, 0.022, 0.230, Vector3(-0.080 * side, -0.150, 0.035), Vector3.ZERO, METAL, 10) _cylinder(a, 0.011, 0.011, 0.175, Vector3(-0.080 * side, -0.150, 0.067), Vector3.ZERO, ACCENT, 8) for vent in 5: _capsule_plate(a, Vector3(0.038, 0.007, 0.010), Vector3(0.060 * side, -0.255 + vent * 0.042, 0.030), METAL, Vector3(0.0, 0.0, 0.10 * side)) for bolt_y in [-0.055, -0.255]: for bolt_x in [-0.045, 0.045]: _sphere(a, 0.006, Vector3(bolt_x, bolt_y, -0.080), ACCENT, 8) _detail_parts += a.part_count a.commit("ShinFrameCombined") func _build_boot(side_name: String, side: float) -> void: var mount := _attachment(_role_bone("foot.%s" % side_name), "MechaBoot%s" % side_name) if mount == null: return var a := Assembly.new(mount) _ellipsoid(a, Vector3(0.120, 0.072, 0.205), Vector3(0.0, -0.020, -0.058), FRAME) _ellipsoid(a, Vector3(0.108, 0.038, 0.165), Vector3(0.0, 0.020, -0.068), ARMOR) _capsule_plate(a, Vector3(0.074, 0.015, 0.080), Vector3(0.0, 0.043, -0.092), ARMOR_ALT) _capsule_plate(a, Vector3(0.012, 0.008, 0.105), Vector3(0.031 * side, 0.052, -0.068), ACCENT) for tread in 4: _capsule_plate(a, Vector3(0.088, 0.010, 0.019), Vector3(0.0, -0.061, -0.130 + tread * 0.047), METAL) for bolt_x in [-0.045, 0.045]: _sphere(a, 0.007, Vector3(bolt_x, 0.060, -0.155), ACCENT, 8) _detail_parts += a.part_count a.commit("BootFrameCombined") func _build_nozzles() -> void: for i in 4: var nozzle := Node3D.new() nozzle.name = "ShoulderThruster%s" % ("L" if i == 0 else "R") \ if i < 2 else "HeelThruster%s" % ("L" if i == 2 else "R") nozzle.set_meta("mecha_thruster", true) add_child(nozzle) _nozzles.append(nozzle) var a := Assembly.new(nozzle) var k := 1.0 if i < 2 else 0.72 # Gimbal neck and nested convergent nozzle. _cylinder(a, 0.052 * k, 0.052 * k, 0.060 * k, Vector3(0.0, 0.0, 0.090 * k), Vector3(PI * 0.5, 0.0, 0.0), METAL, 16) _torus(a, 0.038 * k, 0.066 * k, Vector3(0.0, 0.0, 0.075 * k), Vector3(PI * 0.5, 0.0, 0.0), FRAME, 14, 6) _cylinder(a, 0.070 * k, 0.052 * k, 0.115 * k, Vector3(0.0, 0.0, 0.015 * k), Vector3(PI * 0.5, 0.0, 0.0), FRAME, 16) _cylinder(a, 0.051 * k, 0.035 * k, 0.092 * k, Vector3(0.0, 0.0, -0.010 * k), Vector3(PI * 0.5, 0.0, 0.0), METAL, 16) _torus(a, 0.035 * k, 0.072 * k, Vector3(0.0, 0.0, -0.052 * k), Vector3(PI * 0.5, 0.0, 0.0), ACCENT, 16, 6) _cylinder(a, 0.032 * k, 0.032 * k, 0.008 * k, Vector3(0.0, 0.0, -0.060 * k), Vector3(PI * 0.5, 0.0, 0.0), GLOW, 16) # Four armored petals, actuator rods and fasteners around each mouth. for petal in 4: var angle := petal * TAU / 4.0 var x := cos(angle) * 0.082 * k var y := sin(angle) * 0.082 * k _capsule_plate(a, Vector3(0.028, 0.065, 0.016) * k, Vector3(x, y, -0.005 * k), ARMOR if petal % 2 == 0 else ARMOR_ALT, Vector3(0.0, 0.0, angle)) _cylinder(a, 0.007 * k, 0.007 * k, 0.080 * k, Vector3(x * 0.72, y * 0.72, 0.035 * k), Vector3(PI * 0.5, 0.0, angle), METAL, 8) _sphere(a, 0.009 * k, Vector3(x, y, -0.026 * k), ACCENT, 8) # Cooling slots around the outer housing. for slot in 8: var angle := slot * TAU / 8.0 _capsule_plate(a, Vector3(0.008, 0.024, 0.012) * k, Vector3(cos(angle) * 0.105 * k, sin(angle) * 0.105 * k, 0.040 * k), METAL, Vector3(0.0, 0.0, angle)) _detail_parts += a.part_count a.commit("ThrusterHardwareCombined") func update_nozzles(world_positions: Array[Vector3], body_basis: Basis) -> void: if world_positions.size() != _nozzles.size(): return for i in _nozzles.size(): _nozzles[i].global_transform = Transform3D(body_basis.orthonormalized(), world_positions[i]) func nozzle_world_positions() -> Array[Vector3]: var result: Array[Vector3] = [] for nozzle in _nozzles: result.append(nozzle.global_position) return result func nozzle_count() -> int: return _nozzles.size() func detail_part_count_debug() -> int: return _detail_parts func _attachment(bone: int, node_name: String) -> BoneAttachment3D: if bone < 0 or not is_instance_valid(_skeleton): return null var attachment := BoneAttachment3D.new() attachment.name = node_name attachment.bone_idx = bone # Cancel each rig's authored rest-bone roll. Equipment is modeled in a # consistent character-local frame, then follows only the animated delta. var rest := _skeleton.get_bone_global_rest(bone) attachment.transform = Transform3D(rest.basis.inverse(), Vector3.ZERO) _skeleton.add_child(attachment) _attachments.append(attachment) return attachment func _role_bone(role: String) -> int: if not is_instance_valid(_skeleton): return -1 var name := String(_roles.get(role, "")) return RigRoles.find_imported_bone(_skeleton, name) func _chest_bone() -> int: var spine: Array = _roles.get("spine", []) var neck_name := String(_roles.get("neck", "")) var neck_index := spine.find(neck_name) if neck_index > 0: return _skeleton.find_bone(String(spine[neck_index - 1])) for i in range(spine.size() - 1, -1, -1): var name := String(spine[i]) if name.findn("chest") >= 0 or name.findn("spine_03") >= 0: return _skeleton.find_bone(name) return _role_bone("neck") func _box(a: Assembly, size: Vector3, pos: Vector3, slot: int, rotation: Vector3 = Vector3.ZERO) -> void: var mesh := BoxMesh.new() mesh.size = size a.add(mesh, Transform3D(Basis.from_euler(rotation), pos), slot, _materials[slot]) ## A flattened capsule used as a close-fitting armor plate. Its rounded ends ## and elliptical cross-section keep the silhouette continuous with the pilot ## beneath it while still accepting the same panel/vent overlays as a box. func _capsule_plate(a: Assembly, size: Vector3, pos: Vector3, slot: int, rotation: Vector3 = Vector3.ZERO) -> void: var mesh := CapsuleMesh.new() var vertical := size.y >= size.x var diameter := maxf(minf(size.x, size.y), 0.002) mesh.radius = diameter * 0.5 mesh.height = maxf(maxf(size.x, size.y), diameter) mesh.radial_segments = 10 mesh.rings = 2 var flatten := maxf(size.z / diameter, 0.04) var axis := Basis.IDENTITY if vertical \ else Basis.from_euler(Vector3(0.0, 0.0, PI * 0.5)) var basis := Basis.from_euler(rotation) * axis \ * Basis.from_scale(Vector3(1.0, 1.0, flatten)) a.add(mesh, Transform3D(basis, pos), slot, _materials[slot]) ## Faceted tapered shell around an arm or leg. Ten sides preserve the graphic ## mecha language, but the changing radius follows natural limb taper instead ## of placing a rectangular crate around every joint. func _tapered_shell(a: Assembly, top_width: float, bottom_width: float, height: float, depth: float, pos: Vector3, slot: int, rotation: Vector3 = Vector3.ZERO) -> void: var mesh := CylinderMesh.new() mesh.top_radius = top_width * 0.5 mesh.bottom_radius = bottom_width * 0.5 mesh.height = height mesh.radial_segments = 10 var average_width := maxf((top_width + bottom_width) * 0.5, 0.002) var basis := Basis.from_euler(rotation) \ * Basis.from_scale(Vector3(1.0, 1.0, depth / average_width)) a.add(mesh, Transform3D(basis, pos), slot, _materials[slot]) ## Smooth joint/boot housing. The mesh is deliberately low-ring rather than a ## perfect sphere so it remains anime-mechanical instead of looking organic. func _ellipsoid(a: Assembly, size: Vector3, pos: Vector3, slot: int, rotation: Vector3 = Vector3.ZERO) -> void: var mesh := SphereMesh.new() mesh.radius = 0.5 mesh.height = 1.0 mesh.radial_segments = 12 mesh.rings = 6 var basis := Basis.from_euler(rotation) * Basis.from_scale(size) a.add(mesh, Transform3D(basis, pos), slot, _materials[slot]) func _cylinder(a: Assembly, top_radius: float, bottom_radius: float, height: float, pos: Vector3, rotation: Vector3, slot: int, segments: int = 12) -> void: var mesh := CylinderMesh.new() mesh.top_radius = top_radius mesh.bottom_radius = bottom_radius mesh.height = height mesh.radial_segments = segments a.add(mesh, Transform3D(Basis.from_euler(rotation), pos), slot, _materials[slot]) func _torus(a: Assembly, inner_radius: float, outer_radius: float, pos: Vector3, rotation: Vector3, slot: int, rings: int = 12, segments: int = 6) -> void: var mesh := TorusMesh.new() mesh.inner_radius = inner_radius mesh.outer_radius = outer_radius mesh.rings = rings mesh.ring_segments = segments a.add(mesh, Transform3D(Basis.from_euler(rotation), pos), slot, _materials[slot]) func _sphere(a: Assembly, radius: float, pos: Vector3, slot: int, segments: int = 10) -> void: var mesh := SphereMesh.new() mesh.radius = radius mesh.height = radius * 2.0 mesh.radial_segments = segments mesh.rings = max(4, segments / 2) a.add(mesh, Transform3D(Basis.IDENTITY, pos), slot, _materials[slot]) func _glow_material(color: Color) -> StandardMaterial3D: var material := StandardMaterial3D.new() material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED material.albedo_color = color material.emission_enabled = true material.emission = color material.emission_energy_multiplier = 3.0 return material func _armor_material(color: Color) -> Material: if DisplayServer.get_name() == "headless": return LevelMaterials.unlit(color) return LevelMaterials.cel(color, LevelMaterials.RAMP_3, Color(0.72, 0.76, 0.90))