|  |  |  | extends RigidBody3D | 
					
						
							|  |  |  | class_name PT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @export var follow_speed_curve: Curve | 
					
						
							|  |  |  | @export var color_hp: Color = Color.WHITE | 
					
						
							|  |  |  | @export var color_mp: Color = Color.WHITE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var type: Enum.EPtType | 
					
						
							|  |  |  | var value: int             = 1 | 
					
						
							|  |  |  | var velocity_min: Vector2  = Vector2(0, 3) | 
					
						
							|  |  |  | var velocity_max: Vector2  = Vector2(3, 6) | 
					
						
							|  |  |  | var born_time: float       = 0.5 #生成时间,无法收集 | 
					
						
							|  |  |  | var alive_time: float      = 10.0 #存活时间 | 
					
						
							|  |  |  | var is_born: bool          = false | 
					
						
							|  |  |  | var is_init: bool          = false | 
					
						
							|  |  |  | var is_collect: bool       = false | 
					
						
							|  |  |  | var collect_range: float   = 2.0 | 
					
						
							|  |  |  | var follow_dist_max: float = 5.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @onready var sprite3D: Sprite3D = %Sprite3D as Sprite3D | 
					
						
							|  |  |  | @onready var collision_shape: CollisionShape3D = %CollisionShape3D as CollisionShape3D | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var frame_rate: float = 0.1 | 
					
						
							|  |  |  | var frame_time: float = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func _ready(): | 
					
						
							|  |  |  | 	var velocity_xz: Vector2 = Util.angle_dir(randf_range(0, 360)) * randf_range(velocity_min.x, velocity_max.x) | 
					
						
							|  |  |  | 	var velocity: Vector3    = Vector3(velocity_xz.x, randf_range(velocity_min.y, velocity_max.y), velocity_xz.y) | 
					
						
							|  |  |  | 	set_linear_velocity(velocity) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func _process(delta: float) -> void: | 
					
						
							|  |  |  | 	if not is_init: | 
					
						
							|  |  |  | 		var pt_scale: Vector3 = Vector3.ONE * sqrt(sqrt(sqrt(value))) | 
					
						
							|  |  |  | 		sprite3D.scale = pt_scale | 
					
						
							|  |  |  | 		collision_shape.scale = pt_scale | 
					
						
							|  |  |  | 		var color: Color      = Color.WHITE | 
					
						
							|  |  |  | 		match type: | 
					
						
							|  |  |  | 			Enum.EPtType.HP: color = color_hp | 
					
						
							|  |  |  | 			Enum.EPtType.MP: color = color_mp | 
					
						
							|  |  |  | 			_: pass | 
					
						
							|  |  |  | 		#随机色移 | 
					
						
							|  |  |  | 		color.r += randf_range(0, 0.1) | 
					
						
							|  |  |  | 		color.g += randf_range(0, 0.1) | 
					
						
							|  |  |  | 		color.b += randf_range(0, 0.1) | 
					
						
							|  |  |  | 		color.clamp() | 
					
						
							|  |  |  | 		sprite3D.modulate = color | 
					
						
							|  |  |  | 		sprite3D.rotation.z = randf_range(0, 360) | 
					
						
							|  |  |  | 		is_init = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var velocity: Vector3 = get_linear_velocity() | 
					
						
							|  |  |  | 	if velocity.y > 0.01: | 
					
						
							|  |  |  | 		var frame_count: int      = sprite3D.hframes * sprite3D.vframes | 
					
						
							|  |  |  | 		var frame_time_all: float = frame_rate * frame_count | 
					
						
							|  |  |  | 		frame_time += delta | 
					
						
							|  |  |  | 		sprite3D.frame = int(frame_time / frame_rate) % frame_count | 
					
						
							|  |  |  | 		frame_time = fmod(frame_time, frame_time_all) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#生成 | 
					
						
							|  |  |  | 	if not is_born: | 
					
						
							|  |  |  | 		if born_time <= 0: | 
					
						
							|  |  |  | 			is_born = true | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			born_time -= delta | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#收集激活 | 
					
						
							|  |  |  | 	if not is_collect: | 
					
						
							|  |  |  | 		var target: Character = Global.character_mgr.get_player() | 
					
						
							|  |  |  | 		if not target: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		var dir: Vector3 = target.view_pos() - global_position | 
					
						
							|  |  |  | 		var dist: float  = dir.length() | 
					
						
							|  |  |  | 		if dist < collect_range: | 
					
						
							|  |  |  | 			is_collect = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#存活时间 | 
					
						
							|  |  |  | 	if not is_collect: | 
					
						
							|  |  |  | 		if alive_time <= 0: | 
					
						
							|  |  |  | 			queue_free() | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			alive_time -= delta | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#收集 | 
					
						
							|  |  |  | 	if is_collect: | 
					
						
							|  |  |  | 		var target: Character = Global.character_mgr.get_player() | 
					
						
							|  |  |  | 		if not target: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		var dir: Vector3 = target.view_pos() - global_position | 
					
						
							|  |  |  | 		var dist: float  = dir.length() | 
					
						
							|  |  |  | 		if dist > 0.1: | 
					
						
							|  |  |  | 			var dist_rate    = clamp(dist / follow_dist_max, 0, 1) | 
					
						
							|  |  |  | 			var speed: float = follow_speed_curve.sample(dist_rate) | 
					
						
							|  |  |  | 			set_linear_velocity(dir.normalized() * speed) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			collect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func collect() -> void: | 
					
						
							|  |  |  | 	var target: Character = Global.character_mgr.get_player() | 
					
						
							|  |  |  | 	if not target: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	match type: | 
					
						
							|  |  |  | 		Enum.EPtType.HP: target.add_hp(value) | 
					
						
							|  |  |  | 		Enum.EPtType.MP: target.add_mp_sub(value, true) | 
					
						
							|  |  |  | 		_: pass | 
					
						
							|  |  |  | 	target.cast_particle(ResourceManager.particle_pt_collect, true) | 
					
						
							|  |  |  | 	queue_free() |