tool extends Spatial export(NodePath) var control_skeleton:NodePath setget set_control_skeleton export(NodePath) var edit_animation_player:NodePath setget set_edit_animation_player export(bool) var enabled:bool = true export(bool) var edit_bone_hierarchy : bool = false export(String) var add_bone_name : String = "" export(bool) var add_bone : bool = false setget set_add_bone, get_add_bone export(bool) var set_pose_as_rest : bool = false setget set_set_pose_as_rest, get_add_bone var skeleton:Skeleton = null var animation_player:AnimationPlayer = null var first_call:bool = true var bone_handle_nodes:Array = [] func _ready( ): pass func set_control_skeleton( path:NodePath ): control_skeleton = path if self.first_call: return var node:Node = self.get_node( control_skeleton ) if node is Skeleton: self.skeleton = node else: self.skeleton = null push_error( str(path) + " does not Skeleton!" ) self._generate_bone_handles( ) func set_edit_animation_player( path:NodePath ): edit_animation_player = path if self.first_call: return var node:Node = self.get_node( edit_animation_player ) if node is AnimationPlayer: self.animation_player = node else: self.animation_player = null push_error( str(path) + " does not Animation Player!" ) func _generate_bone_handles( ): for child in self.get_children( ): self.remove_child( child ) if self.skeleton == null: return self.bone_handle_nodes = [] var bone_handle: = preload( "BoneHandle.tscn" ) for bone_id in range( self.skeleton.get_bone_count( ) ): var bone_name:String = self.skeleton.get_bone_name( bone_id ) var bone_handle_node:BoneHandle = bone_handle.instance( ) bone_handle_node.bone_editor = self bone_handle_node.name = bone_name bone_handle_node.skeleton = self.skeleton bone_handle_node.bone_id = bone_id bone_handle_node.bone_name = bone_name var parent_bone_id:int = self.skeleton.get_bone_parent( bone_id ) if parent_bone_id == -1: self.add_child( bone_handle_node ) else: self.bone_handle_nodes[parent_bone_id].add_child( bone_handle_node ) if Engine.editor_hint == true: var tree:SceneTree = self.get_tree( ) if tree != null: if tree.edited_scene_root != null: bone_handle_node.set_owner( tree.edited_scene_root ) self.bone_handle_nodes.append( bone_handle_node ) func _process( delta:float ): if self.first_call: self.first_call = false self.set_control_skeleton( self.control_skeleton ) self.set_edit_animation_player( self.edit_animation_player ) for handle_bone in self.bone_handle_nodes: handle_bone.enabled = self.enabled func init_poses( ): for handle_bone in self.bone_handle_nodes: handle_bone.init_pose( ) func load_poses( ): if self.animation_player == null: push_error( "Animation player is null." ) return var assigned_animation:String = self.animation_player.assigned_animation var animation:Animation = self.animation_player.get_animation( assigned_animation ) var time:float = self.animation_player.current_animation_position for track_idx in animation.get_track_count( ): var target_bone:BoneHandle = null for handle_bone in self.bone_handle_nodes: var path:NodePath = NodePath( "%s:%s" % [ self.get_node( self.animation_player.root_node ).get_path_to( self.skeleton ), handle_bone.name ] ) if animation.track_get_path( track_idx ) == path: target_bone = handle_bone break if target_bone == null: continue var bone:Array = animation.transform_track_interpolate( track_idx, time ) target_bone.set_pose( Basis( bone[1] ), bone[0] ) func save_poses( ): if self.animation_player == null: push_error( "Animation player is null." ) return var assigned_animation:String = self.animation_player.assigned_animation var animation:Animation = self.animation_player.get_animation( assigned_animation ) if animation == null: push_error( "animation does not selected on Animation player." ) return # 足りないボーンがあれば追加する self._add_bone_tracks( animation ) # ポーズを保存 self._save_poses_to_animation( animation ) func _add_bone_tracks( animation:Animation ): var founded_bone_tracks:Array = [] for track_idx in animation.get_track_count( ): founded_bone_tracks.append( animation.track_get_path( track_idx ) ) for handle_bone in self.bone_handle_nodes: var path:NodePath = NodePath( "%s:%s" % [ self.get_node( self.animation_player.root_node ).get_path_to( self.skeleton ), handle_bone.name ] ) if founded_bone_tracks.find( path ) == -1: var new_track_idx:int = animation.add_track( Animation.TYPE_TRANSFORM ) animation.track_set_path( new_track_idx, path ) print( "added new track for ", path ) func _save_poses_to_animation( animation:Animation ): var time:float = self.animation_player.current_animation_position for track_idx in animation.get_track_count( ): var target_bone:BoneHandle = null for handle_bone in self.bone_handle_nodes: var path:NodePath = NodePath( "%s:%s" % [ self.get_node( self.animation_player.root_node ).get_path_to( self.skeleton ), handle_bone.name ] ) if animation.track_get_path( track_idx ) == path: target_bone = handle_bone break if target_bone == null: continue # すでに同じ位置にモノが存在するなら削除する for key_idx in animation.track_get_key_count( track_idx ): if animation.track_get_key_time( track_idx, key_idx ) == time: animation.track_remove_key( track_idx, key_idx ) break animation.transform_track_insert_key( track_idx, time, target_bone.pose.origin, target_bone.pose.basis.get_rotation_quat( ), target_bone.pose.basis.get_scale( ) ) print( "* added new key for ", target_bone.name ) func set_bone_parent(bone_id, parent_bone_id): ensure_nodes() if !skeleton: return skeleton.set_bone_parent(bone_id, parent_bone_id) func ensure_nodes(): if !skeleton: skeleton = get_node(control_skeleton) if !animation_player: animation_player = get_node(edit_animation_player) func set_add_bone(val): if val: if add_bone_name == "": return ensure_nodes() if skeleton == null: return skeleton.add_bone(add_bone_name) var bone_id : int = skeleton.find_bone(add_bone_name) var bone_handle: = preload( "BoneHandle.tscn" ) var bone_name:String = add_bone_name var bone_handle_node:BoneHandle = bone_handle.instance( ) bone_handle_node.bone_editor = self bone_handle_node.name = bone_name bone_handle_node.skeleton = self.skeleton bone_handle_node.bone_id = bone_id bone_handle_node.bone_name = bone_name var parent_bone_id:int = self.skeleton.get_bone_parent( bone_id ) if parent_bone_id == -1: self.add_child( bone_handle_node ) if Engine.editor_hint == true: var tree:SceneTree = self.get_tree( ) if tree != null: if tree.edited_scene_root != null: bone_handle_node.set_owner( tree.edited_scene_root ) self.bone_handle_nodes.append( bone_handle_node ) add_bone_name = "" func get_add_bone(): return false func is_done_editor(): return true func set_set_pose_as_rest(val): if val: for n in bone_handle_nodes: n.set_as_rest_pose() for n in bone_handle_nodes: n._ready() #load_poses()