|  |  |  | @tool | 
					
						
							|  |  |  | extends Node3D | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_resource_name(resource:Resource) -> String:return resource.resource_path.get_file().trim_suffix('.tres') #todo 性能 | 
					
						
							|  |  |  | func snap_vector3(value:Vector3) -> Vector3:return Vector3(snap_float(value.x),snap_float(value.y),snap_float(value.z)) | 
					
						
							|  |  |  | func snap_float(value:float) -> float:return floor(value/Setting.pixel_size) * Setting.pixel_size | 
					
						
							|  |  |  | func grid_vector3(value:Vector3) -> Vector3:return Vector3(grid_float(value.x),grid_float(value.y),grid_float(value.z)) | 
					
						
							|  |  |  | func grid_vector2(value:Vector2) -> Vector2:return Vector2(grid_float(value.x),grid_float(value.y)) | 
					
						
							|  |  |  | func grid_float(value:float) -> float:return Setting.pixel_size * Setting.grid_pixel_size * value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func vector_reduce(vector:Vector2,reduce:float) -> Vector2: | 
					
						
							|  |  |  | 	var len = vector.length() | 
					
						
							|  |  |  | 	if len == 0: | 
					
						
							|  |  |  | 		return vector | 
					
						
							|  |  |  | 	var new_len = max(len - reduce,0) | 
					
						
							|  |  |  | 	var scale_rate = new_len / len | 
					
						
							|  |  |  | 	return vector * scale_rate | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func raycast_wall(from:Vector3,to:Vector3) -> bool: | 
					
						
							|  |  |  | 	var space_state = get_world_3d().direct_space_state | 
					
						
							|  |  |  | 	var query = PhysicsRayQueryParameters3D.create(from,to,1) | 
					
						
							|  |  |  | 	var result = space_state.intersect_ray(query) | 
					
						
							|  |  |  | 	return result.size()>0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func attack_detection(pos:Vector3,target_pos:Vector3,target_radius:float,target_height:float,attack_dir:Vector2,attack_height:float,attack_size:Vector2,attack_radius:float) -> bool: | 
					
						
							|  |  |  | 	# 检查Y | 
					
						
							|  |  |  | 	var attack_y_min = pos.y | 
					
						
							|  |  |  | 	var attack_y_max = pos.y + attack_height | 
					
						
							|  |  |  | 	var target_y_min = target_pos.y | 
					
						
							|  |  |  | 	var target_y_max = target_pos.y + target_height | 
					
						
							|  |  |  | 	if attack_y_min > target_y_max || attack_y_max < target_y_min: | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	# 保底距离 | 
					
						
							|  |  |  | 	if pos.distance_to(target_pos) < 0.01: | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	# 2d距离 | 
					
						
							|  |  |  | 	var dist_2d = Vector2(pos.x,pos.z).distance_to(Vector2(target_pos.x,target_pos.z)) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	# 如果是圆形 | 
					
						
							|  |  |  | 	if attack_radius: | 
					
						
							|  |  |  | 		return dist_2d <= attack_radius + target_radius | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	# 旋转target | 
					
						
							|  |  |  | 	var angle = attack_dir.angle_to(Vector2.RIGHT) | 
					
						
							|  |  |  | 	target_pos = target_pos - pos | 
					
						
							|  |  |  | 	target_pos = target_pos.rotated(Vector3.UP,angle) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	var dist_x = abs(target_pos.x) - attack_size.x | 
					
						
							|  |  |  | 	var dist_y = abs(target_pos.z) - attack_size.y | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if dist_x <= target_radius && dist_y <= target_radius: | 
					
						
							|  |  |  | 		if (dist_x <= 0 || dist_y <= 0): | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		var dist_squared = pow(dist_x, 2) + pow(dist_y, 2) | 
					
						
							|  |  |  | 		return dist_squared <= pow(target_radius, 2) | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_animation_lib(): | 
					
						
							|  |  |  | 	var animation_library_path = "res://resource/skill_animation_library/animation_library.tres" | 
					
						
							|  |  |  | 	var animation_library = load(animation_library_path) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	var dir_path = "res://resource/skill_animation" | 
					
						
							|  |  |  | 	var dir = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file in dir.get_files(): | 
					
						
							|  |  |  | 		var path = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is Animation: | 
					
						
							|  |  |  | 			var animation = res as Animation | 
					
						
							|  |  |  | 			var animation_name = Util.get_resource_name(animation) | 
					
						
							|  |  |  | 			print("refresh_animation_lib: ",animation_name) | 
					
						
							|  |  |  | 			animation_library.add_animation(animation_name,animation) | 
					
						
							|  |  |  | 			animation_library.animation_added.emit(animation_name) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ResourceSaver.save(animation_library,animation_library_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_mesh_library(path_list:Array): | 
					
						
							|  |  |  | 	var default_shape_full = [load("res://resource/mesh_library/default_shape_full.tres") as Shape3D,Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_half = [load("res://resource/mesh_library/default_shape_half.tres") as Shape3D,Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var mesh_library = load("res://resource/mesh_library/mesh_library.tres") as MeshLibrary | 
					
						
							|  |  |  | 	for file_name_full in path_list: | 
					
						
							|  |  |  | 		var mesh_name = file_name_full.get_file().split('-')[0].trim_suffix('.vox') | 
					
						
							|  |  |  | 		print(mesh_name) | 
					
						
							|  |  |  | 		var mesh = load(file_name_full) as Mesh | 
					
						
							|  |  |  | 		var mesh_id = mesh_library.find_item_by_name(mesh_name) | 
					
						
							|  |  |  | 		if mesh_id == -1: | 
					
						
							|  |  |  | 			mesh_id = mesh_library.get_last_unused_item_id() | 
					
						
							|  |  |  | 			mesh_library.create_item(mesh_id) | 
					
						
							|  |  |  | 		mesh_library.set_item_name(mesh_id,mesh_name) | 
					
						
							|  |  |  | 		mesh_library.set_item_mesh(mesh_id,mesh) | 
					
						
							|  |  |  | 		if mesh_name.begins_with("f_"): | 
					
						
							|  |  |  | 			mesh_library.set_item_shapes(mesh_id,default_shape_full) | 
					
						
							|  |  |  | 		elif mesh_name.begins_with("h_"): | 
					
						
							|  |  |  | 			mesh_library.set_item_shapes(mesh_id,default_shape_half) | 
					
						
							|  |  |  | 		elif mesh_name.begins_with("s_"): | 
					
						
							|  |  |  | 			var new_shape = [mesh.create_convex_shape(),Transform3D.IDENTITY] | 
					
						
							|  |  |  | 			mesh_library.set_item_shapes(mesh_id,new_shape) | 
					
						
							|  |  |  | 	var ids = mesh_library.get_item_list() | 
					
						
							|  |  |  | 	var meshes = [] | 
					
						
							|  |  |  | 	for id in ids: | 
					
						
							|  |  |  | 		meshes.append(mesh_library.get_item_mesh(id)) | 
					
						
							|  |  |  | 	var previews = EditorInterface.make_mesh_previews(meshes, 64) | 
					
						
							|  |  |  | 	for i in range(len(ids)): | 
					
						
							|  |  |  | 		mesh_library.set_item_preview(ids[i],previews[i]) | 
					
						
							|  |  |  | 	ResourceSaver.save(mesh_library) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | func refresh_all_animation_by_sprite_frames(sprite_frames:SpriteFrames): | 
					
						
							|  |  |  | 	var dir_path = "res://resource/skill_animation" | 
					
						
							|  |  |  | 	var dir = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	var sprite_frames_name = sprite_frames.resource_path.get_file().split('-')[0] | 
					
						
							|  |  |  | 	for file in dir.get_files(): | 
					
						
							|  |  |  | 		var path = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if not res is Animation: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation = res as Animation | 
					
						
							|  |  |  | 		var sprite_frames_track = animation.find_track(NodePath("View:sprite_frames"),Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		if sprite_frames_track < 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var sprite_frames_track_key_count = animation.track_get_key_count(sprite_frames_track) | 
					
						
							|  |  |  | 		if sprite_frames_track_key_count == 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var sprite_frames_value = animation.track_get_key_value(sprite_frames_track,0) as SpriteFrames | 
					
						
							|  |  |  | 		var target_sprite_frames_name = sprite_frames_value.resource_path.get_file().split('-')[0] | 
					
						
							|  |  |  | 		if sprite_frames_name != target_sprite_frames_name: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation_track = animation.find_track(NodePath("View:animation"),Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		if animation_track < 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation_track_key_count = animation.track_get_key_count(animation_track) | 
					
						
							|  |  |  | 		if animation_track_key_count == 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation_value = animation.track_get_key_value(animation_track,0) as String | 
					
						
							|  |  |  | 		refresh_animation_by_sprite_frames(path,sprite_frames,animation_value,animation) | 
					
						
							|  |  |  | 	Util.refresh_animation_lib() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_animation_by_sprite_frames(animation_path:String,sprite_frames:SpriteFrames,animation_name:String,animation:Animation): | 
					
						
							|  |  |  | 	if not sprite_frames.has_animation(animation_name): | 
					
						
							|  |  |  | 		print("动画不存在: ",animation_name) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var track_sprite_frames = animation.find_track(NodePath("View:sprite_frames"),Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	if track_sprite_frames < 0: | 
					
						
							|  |  |  | 		track_sprite_frames = animation.add_track(Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		animation.track_set_path(track_sprite_frames,"View:sprite_frames") | 
					
						
							|  |  |  | 		animation.track_insert_key(track_sprite_frames,0,sprite_frames) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	var track_animation = animation.find_track(NodePath("View:animation"),Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	if track_animation < 0: | 
					
						
							|  |  |  | 		track_animation = animation.add_track(Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		animation.track_set_path(track_animation,"View:animation") | 
					
						
							|  |  |  | 		animation.track_insert_key(track_animation,0,animation_name) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	var track_frame = animation.find_track(NodePath("View:frame"),Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	if track_frame >= 0: | 
					
						
							|  |  |  | 		animation.remove_track(track_frame) | 
					
						
							|  |  |  | 	track_frame = animation.add_track(Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	animation.track_set_path(track_frame,"View:frame") | 
					
						
							|  |  |  | 	var animation_speed = Setting.animation_frame_rate | 
					
						
							|  |  |  | 	var animation_frame_count = sprite_frames.get_frame_count(animation_name) | 
					
						
							|  |  |  | 	animation.length = animation_speed*animation_frame_count | 
					
						
							|  |  |  | 	for i in range(0,animation_frame_count): | 
					
						
							|  |  |  | 		var time = i * animation_speed | 
					
						
							|  |  |  | 		animation.track_insert_key(track_frame,time,i) | 
					
						
							|  |  |  | 	animation.value_track_set_update_mode(track_sprite_frames,Animation.UPDATE_DISCRETE) | 
					
						
							|  |  |  | 	animation.value_track_set_update_mode(track_animation,Animation.UPDATE_DISCRETE) | 
					
						
							|  |  |  | 	animation.value_track_set_update_mode(track_frame,Animation.UPDATE_DISCRETE) | 
					
						
							|  |  |  | 	print("refresh_animation: ",animation_name ,"(",animation_frame_count, " frames)") | 
					
						
							|  |  |  | 	ResourceSaver.save(animation,animation_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_all_skill_player_weapon(): | 
					
						
							|  |  |  | 	var ret = [] | 
					
						
							|  |  |  | 	var dir_path = "res://config/skill_player_weapon" | 
					
						
							|  |  |  | 	var dir = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file in dir.get_files(): | 
					
						
							|  |  |  | 		var path = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is SkillPlayerCfg: | 
					
						
							|  |  |  | 			ret.append(res) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_skill_player_weapon_by_weapon(weapon:WeaponCfg): | 
					
						
							|  |  |  | 	var ret = [] | 
					
						
							|  |  |  | 	var dir_path = "res://config/skill_player_weapon" | 
					
						
							|  |  |  | 	var dir = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file in dir.get_files(): | 
					
						
							|  |  |  | 		var path = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is SkillPlayerCfg: | 
					
						
							|  |  |  | 			if res.weapon == weapon: | 
					
						
							|  |  |  | 				ret.append(res) | 
					
						
							|  |  |  | 	return ret |