godot-plateformer/_player/player_locomotion.gd

283 lines
7.8 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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_position2D 常見)
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()