class_name CelesteLocomotionComponent extends JumpLocomotionComponent #region 冲刺相关参数 @export_category("Dash Properties") ##最大的冲刺次数 @export var maxium_dash_count:int = 1 ##Dash时的速度 @export var dash_speed: float = 240 ##结束Dash的速度 @export var end_dash_speed: float = 160 ##Dash的冷却时间 @export var dash_cold_down: float = .2 ##是否在组件ready时自动补充所有的Dash次数 @export var auto_recover_dash_count_at_ready: bool = true #endregion #region 攀爬相关参数 @export_category("Climb Properties") ##角色最大耐力 @export var climb_max_stamina: float ##角色向上时的速度 @export var climb_max_speed_upward: float = 45.0 ##角色向下时的速度 @export var climb_max_speed_downward: float = 80.0 ##角色速度变化时的最大加速度 @export var climb_acceleration: float = 900.0 ##攀爬到顶点时候的自动代偿速度X @export var climb_hop_velocity_x: float = 80 ##攀爬到顶点时候的自动代偿速度Y @export var climb_hop_velocity_y: float = 160 ##攀爬跳的速度X @export var climb_jump_velocity_x: float = 160 ##攀爬跳的速度Y @export var climb_jump_velocity_y: float = 160 ##攀爬跳的最大可输入时长 @export var climb_jump_time: float = .14 #endregion #region Custom Move (拉扯移動) @export_category("Custom Move") ##進行自定義運動時,移動的拉力 @export var custom_move_force: float = 25.0 ##進行自定義運動時,移動的最大速度 @export var custom_move_max_speed: float = 420.0 ##進行自定義運動時,如果于目標點小於此距離,則會解除自定義運動 @export var custom_move_stop_distance: float = 4.0 var _custom_move_target_node: Node = null var _is_custom_moving: bool = false signal hook_released #endregion #region 冲刺field var last_dash_count: int ##此变量为总开关,如果关闭,则在物理更新里无论如何也是不会更新Dash的,这里默认为false,因为Dash需要手动触发,最好不要常开 var can_dash: bool = false var _dash_direction: Vector2 #存储Dash的Direction signal dash_count_changed(count: int) signal dash_brusted signal dash_prepared #endregion #region 攀爬field var can_climb: bool = false var _climb_input: float var _climb_hop_flag: bool = false var _is_climb_jumping: bool = false #endregion func _init_component() -> void: super._init_component() if auto_recover_dash_count_at_ready: full_recover_dash_count() func _physics_process(delta: float) -> void: if Engine.is_editor_hint(): return if _is_custom_moving: _update_custom_move(delta) characterbody.move_and_slide() return if can_climb: _update_climb(delta) characterbody.move_and_slide() #移动更新 return if can_dash: characterbody.move_and_slide() return super._physics_process(delta) func _update_climb(delta) -> void: var target_abs: float #更新目标速度 if sign(_climb_input) == .0: target_abs = 0 elif sign(_climb_input) > 0: target_abs = climb_max_speed_downward else: target_abs = climb_max_speed_upward var target = target_abs * _climb_input characterbody.velocity.y = speed_approach(characterbody.velocity.y,target,climb_acceleration * delta) func _update_dash(delta) -> void: return ##特殊移動 func _custom_move_to(target_node: Node) -> bool: if target_node == null: return false # 要求目標至少能提供 global_position(2D 常見) if not ("global_position" in target_node): push_warning("custom_move target_node has no global_position.") return false _custom_move_target_node = target_node _is_custom_moving = true # 進入自定義移動時,關掉其他行為(按你需求可調) can_dash = false can_climb = false return true ## 停止特殊移動(Custom Move) func stop_custom_move( force_stop_velocity: bool = true, clear_target: bool = true ) -> void: if not _is_custom_moving: return _is_custom_moving = false if clear_target: _custom_move_target_node = null if force_stop_velocity: characterbody.velocity = Vector2.ZERO ##預製的保留速度的hook stop func _release_hook_keep_momentum() -> void: stop_custom_move(false) hook_released.emit() ##特殊移動更新函數 func _update_custom_move(delta: float) -> void: if not _is_custom_moving: return # 目標被刪掉/釋放了 if _custom_move_target_node == null or not is_instance_valid(_custom_move_target_node): _is_custom_moving = false _custom_move_target_node = null return var target_pos: Vector2 = _custom_move_target_node.global_position var pos: Vector2 = characterbody.global_position var to_target := target_pos - pos var distance := to_target.length() if distance <= custom_move_stop_distance: _is_custom_moving = false _custom_move_target_node = null characterbody.velocity = Vector2.ZERO return var dir := to_target / distance # 拉扯加速度:距離越遠越快(“被拉過去”的感覺) var acceleration := dir * distance * custom_move_force characterbody.velocity += acceleration * delta # 限制最大速度 var v_len := characterbody.velocity.length() if v_len > custom_move_max_speed: characterbody.velocity = characterbody.velocity / v_len * custom_move_max_speed ##整合之后的函数,如果不需要额外的逻辑,可以直接通过这个触发Dash func integrate_dash(dash_dir: Vector2) -> bool: if not predash(dash_dir): return false await get_tree().process_frame #等待一帧 brust_dash() return true ##dash函数,输入一个Dash的方向,返回是否成功 func brust_dash() -> bool: var old: Vector2 = characterbody.velocity; var burst: Vector2 = _dash_direction.normalized() * dash_speed; if sign(old.x) == sign(burst.x) and abs(old.x) > abs(burst.x): burst.x = old.x characterbody.velocity = burst dash_brusted.emit() return true ##dash准备函数,需要在dash的前一帧触发 func predash(dash_dir: Vector2) -> bool: if not get_can_dash(): return false dash_prepared.emit() last_dash_count = maxi(last_dash_count -1,0) can_dash = true _dash_direction = dash_dir return true ##停止Dash,实际上是关闭Dash标识符 func stop_dash(force_stop: bool = false) -> void: if force_stop: characterbody.velocity = Vector2.ZERO characterbody.move_and_slide() can_dash = false ##完全回复的Dash次数 func full_recover_dash_count() -> void: dash_count_changed.emit(last_dash_count) last_dash_count = maxium_dash_count ##回复指定数量的Dash次数 func recover_dash_count(recover_count : int) -> void: last_dash_count = clampi(last_dash_count+ recover_count, 0,maxium_dash_count) ##子类可以重写此方法以自定义Dash的条件 func get_can_dash() -> bool: return last_dash_count > 0 ##添加攀爬的输入 func add_climb_input(input: float) -> bool: _climb_input = input return true ##开始攀爬 func start_climb(force_reset: bool = false) -> void: if force_reset: characterbody.velocity = Vector2.ZERO characterbody.move_and_slide() can_climb = true ##终止攀爬 func suspend_climb() -> void: can_climb = false ##攀爬补充跳跃 func climb_hop() -> void: _climb_hop_flag = true characterbody.velocity = Vector2(climb_hop_velocity_x * Player.get_direction_vector(characterbody.direction).x,-1 * climb_hop_velocity_y) func start_climb_jump() -> bool: if _is_jumping : return false #给与一个跳跃的补正速度 characterbody.velocity.x = _movement_input * climb_jump_velocity_x # 跳跃的水平补正速度 _jump_timer = climb_jump_time _is_jumping = true _is_climb_jumping = true can_climb = false #取消掉原本的climb,如果后续重新触发climb,则重新判断 characterbody.velocity.y = _get_jump_force() return true func stop_climb_jump() -> void: _is_jumping = false _is_climb_jumping = false func _get_jump_force() -> float: if _is_climb_jumping: return -1 * climb_jump_velocity_y return super._get_jump_force()