extends Node3D var current: Gizmo var gizmo_holder := Node3D.new() var original_gh_p: Vector3 var original_positions: PackedVector3Array = [] var original_rotations: PackedVector3Array = [] var original_scales: PackedVector3Array = [] @export var target: Node3D @export var gizmo: PackedScene @onready var targets: Array[Node3D] = [target] func _ready() -> void: add_child(gizmo_holder) current = gizmo.instantiate() _position_gizmo_holder() gizmo_holder.add_child(current) _setup_originals() current.finalize.connect(_gizmo_finalize) current.displaced.connect(_gizmo_displace) current.scaled.connect(_gizmo_scale) current.rotated.connect(_gizmo_rotate) func _position_gizmo_holder() -> void: var sum := Vector3.ZERO for node in targets: sum += node.global_position gizmo_holder.global_position = sum / len(targets) func _setup_originals() -> void: original_positions.resize(len(targets)) original_rotations.resize(len(targets)) original_scales.resize(len(targets)) for i in len(targets): var n := targets[i] original_positions[i] = n.global_position original_rotations[i] = n.global_rotation original_scales[i] = n.scale original_gh_p = gizmo_holder.global_position func _gizmo_displace(offset: Vector3): for i in len(targets): targets[i].global_position = original_positions[i] + offset gizmo_holder.global_position = original_gh_p + offset func _gizmo_scale(change: Vector3): for i in len(targets): var n := targets[i] var scl := original_scales[i] + change if scl.x <= 0 || scl.y <= 0: # no flipping allowed scl = Vector3.ONE n.scale = scl func _gizmo_rotate(change: Vector3): for i in len(targets): var n := targets[i] n.global_rotation = original_rotations[i] + change func _gizmo_finalize(): for i in len(targets): var n := targets[i] original_positions[i] = n.global_position original_scales[i] = n.scale original_rotations[i] = n.global_rotation original_gh_p = gizmo_holder.global_position