2025-12-29 11:54:31 +08:00
|
|
|
|
class_name Player extends CharacterBody2D
|
|
|
|
|
|
|
|
|
|
|
|
@onready var locomotion_comp: LocomotionComponent = %LocomotionComponent
|
|
|
|
|
|
@onready var hsm: LimboHSM = %PlayerHSM
|
|
|
|
|
|
@onready var wall_detector: WallDetector = %WallDetector
|
|
|
|
|
|
@onready var hit_box: Area2D = %HitBox
|
|
|
|
|
|
@onready var spawn_hook_comp: SpawnHookComponet = $SpawnHookComponet
|
|
|
|
|
|
|
|
|
|
|
|
@onready var foot_pos_marker: Marker2D = %FootPosMarker
|
2026-01-05 15:28:43 +08:00
|
|
|
|
@onready var ground_companion: Area2D = %GroundCompanion
|
|
|
|
|
|
|
2026-01-11 22:32:09 +08:00
|
|
|
|
@onready var collision_shape_2d: CollisionShape2D = %CollisionShape2D
|
|
|
|
|
|
|
2025-12-29 11:54:31 +08:00
|
|
|
|
|
|
|
|
|
|
enum Direction{LEFT,RIGHT}
|
|
|
|
|
|
var direction: Direction = Direction.RIGHT: set = _player_direction_changed
|
|
|
|
|
|
|
2026-01-11 22:32:09 +08:00
|
|
|
|
var wall_snap_offset: float :
|
|
|
|
|
|
get():
|
|
|
|
|
|
return collision_shape_2d.shape.get_rect().size.x/2
|
|
|
|
|
|
|
2025-12-29 11:54:31 +08:00
|
|
|
|
var m_jump_press: bool = false
|
|
|
|
|
|
var m_dash_press: bool = false
|
|
|
|
|
|
var m_climb_press: bool = false
|
|
|
|
|
|
var m_grap_hook_press: bool = false
|
|
|
|
|
|
|
|
|
|
|
|
##用于记录当前玩家输入的朝向
|
|
|
|
|
|
var m_input_intent_direction: Vector2
|
|
|
|
|
|
|
|
|
|
|
|
var is_dead: bool = false:
|
|
|
|
|
|
set(value):
|
|
|
|
|
|
is_dead = value
|
|
|
|
|
|
if is_dead:
|
|
|
|
|
|
locomotion_comp.is_active = false
|
2026-01-08 14:15:38 +08:00
|
|
|
|
GlobalEvent.boradcast_player_dead_event(self)
|
2025-12-29 11:54:31 +08:00
|
|
|
|
player_dead.emit()
|
|
|
|
|
|
|
|
|
|
|
|
signal player_direction_changed(direction: Direction)
|
|
|
|
|
|
signal player_dead
|
|
|
|
|
|
|
|
|
|
|
|
##落地尘土特效
|
|
|
|
|
|
signal v_land_dust
|
|
|
|
|
|
##奔跑尘土特效
|
|
|
|
|
|
signal v_run_dust
|
|
|
|
|
|
##跳跃尘土特效
|
|
|
|
|
|
signal v_jump_dust
|
|
|
|
|
|
|
|
|
|
|
|
##跳跃声音特效
|
|
|
|
|
|
signal s_jump_sound
|
|
|
|
|
|
|
2026-01-08 14:15:38 +08:00
|
|
|
|
func _enter_tree() -> void:
|
|
|
|
|
|
GlobalEvent.register_player(self)
|
|
|
|
|
|
|
2025-12-29 11:54:31 +08:00
|
|
|
|
func _ready() -> void:
|
|
|
|
|
|
self.player_direction_changed.connect(_handle_direction_changed)
|
|
|
|
|
|
self.hit_box.area_entered.connect(_handle_hit_box_entered)
|
|
|
|
|
|
self.hit_box.body_entered.connect(_handle_hit_box_entered)
|
|
|
|
|
|
|
|
|
|
|
|
func _draw() -> void:
|
|
|
|
|
|
draw_string(ThemeDB.fallback_font,Vector2.ZERO,str(get_wall_normal()))
|
2026-01-05 17:38:43 +08:00
|
|
|
|
|
|
|
|
|
|
var x: float = clampf(abs(velocity.x),1,1000) * .2 * sign(velocity.x)
|
|
|
|
|
|
var y: float = clampf(abs(velocity.y),1,1000) * .2 * sign(velocity.y)
|
|
|
|
|
|
|
2026-01-10 14:04:34 +08:00
|
|
|
|
var a_x: float = clampf(abs(velocity.x),1,2000) * .3 * sign(locomotion_comp._current_acceleration.x)
|
|
|
|
|
|
var a_y: float = clampf(abs(velocity.x),1,2000) * .3 * sign(locomotion_comp._current_acceleration.y)
|
|
|
|
|
|
|
2026-01-05 17:38:43 +08:00
|
|
|
|
draw_line(Vector2.ZERO,Vector2(x, 0),Color.RED,4)
|
|
|
|
|
|
draw_line(Vector2.ZERO,Vector2(0, y),Color.GREEN,4)
|
2026-01-10 14:04:34 +08:00
|
|
|
|
|
|
|
|
|
|
draw_line(Vector2.ZERO,Vector2(a_x, 0),Color.YELLOW,2)
|
|
|
|
|
|
draw_line(Vector2.ZERO,Vector2(0, a_y),Color.PURPLE,2)
|
2025-12-29 11:54:31 +08:00
|
|
|
|
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
|
|
|
|
queue_redraw()
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
|
|
|
|
|
|
func set_move_input(dir: Vector2) -> void:
|
|
|
|
|
|
m_input_intent_direction = dir
|
|
|
|
|
|
|
|
|
|
|
|
func get_move_input() -> Vector2:
|
|
|
|
|
|
return m_input_intent_direction
|
|
|
|
|
|
|
2026-01-05 15:28:43 +08:00
|
|
|
|
## 更宽泛的floor检测
|
|
|
|
|
|
func get_is_on_floor() -> bool:
|
|
|
|
|
|
return self.is_on_floor() or ground_companion.has_overlapping_areas() or ground_companion.has_overlapping_bodies()
|
|
|
|
|
|
|
2025-12-29 11:54:31 +08:00
|
|
|
|
#region 输入处理
|
|
|
|
|
|
'''对于单次的输入触发动作,我们发送一个格式为
|
|
|
|
|
|
want_to_...的事件给hsm,用来尝试触发
|
|
|
|
|
|
'''
|
2025-12-30 10:15:32 +08:00
|
|
|
|
|
|
|
|
|
|
func press_jump() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_jump_press = true
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"trigger_jump")
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
func release_jump() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_jump_press = false
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"completed_jump")
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
func press_dash() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_dash_press = true
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"trigger_dash")
|
|
|
|
|
|
|
2025-12-31 16:24:11 +08:00
|
|
|
|
func release_dash() -> void:
|
|
|
|
|
|
m_dash_press = false
|
|
|
|
|
|
hsm.dispatch(&"completed_dash")
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
func press_climb() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_climb_press = true
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"trigger_climb")
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
func release_climb() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_climb_press = false
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"completed_climb")
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
func press_grap_hook() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_grap_hook_press = true
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"trigger_grap_hook")
|
|
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
func release_grap_hook() -> void:
|
2025-12-31 16:24:11 +08:00
|
|
|
|
m_grap_hook_press = true
|
2025-12-29 11:54:31 +08:00
|
|
|
|
hsm.dispatch(&"completed_grap_hook")
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
##玩家方向改变时更新
|
|
|
|
|
|
func _handle_direction_changed(value: Direction):
|
|
|
|
|
|
match value:
|
|
|
|
|
|
Direction.RIGHT:
|
|
|
|
|
|
wall_detector.flip_h = false
|
|
|
|
|
|
Direction.LEFT:
|
|
|
|
|
|
wall_detector.flip_h = true
|
|
|
|
|
|
|
|
|
|
|
|
func _handle_hit_box_entered(node: Node2D)-> void:
|
|
|
|
|
|
hsm.dispatch(&"try_enter_dead")
|
|
|
|
|
|
|
|
|
|
|
|
func _player_direction_changed(value: Direction):
|
|
|
|
|
|
if self.direction == value:
|
|
|
|
|
|
return
|
|
|
|
|
|
direction = value
|
|
|
|
|
|
player_direction_changed.emit(direction)
|
|
|
|
|
|
|
2026-01-09 18:43:45 +08:00
|
|
|
|
func is_in_ground_state() -> bool:
|
|
|
|
|
|
return %Grounded.is_active()
|
|
|
|
|
|
|
|
|
|
|
|
func is_in_climb_state() -> bool:
|
|
|
|
|
|
return %Climb.is_active()
|
|
|
|
|
|
|
|
|
|
|
|
#region 特效广播
|
2025-12-29 11:54:31 +08:00
|
|
|
|
##播放落地尘土特效
|
|
|
|
|
|
func on_land_dust() -> void:
|
|
|
|
|
|
v_land_dust.emit({"world_pos": foot_pos_marker.global_position})
|
|
|
|
|
|
|
|
|
|
|
|
##播放落地尘土特效
|
|
|
|
|
|
func on_run_dust() -> void:
|
|
|
|
|
|
v_run_dust.emit({"world_pos": foot_pos_marker.global_position})
|
|
|
|
|
|
|
|
|
|
|
|
##播放落地尘土特效
|
|
|
|
|
|
func on_jump() -> void:
|
|
|
|
|
|
v_jump_dust.emit({"world_pos": foot_pos_marker.global_position})
|
|
|
|
|
|
s_jump_sound.emit()
|
2026-01-09 18:43:45 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-29 11:54:31 +08:00
|
|
|
|
|
|
|
|
|
|
##工具函数
|
2026-01-09 18:43:45 +08:00
|
|
|
|
##获取当前state下的目标state
|
|
|
|
|
|
func _get_target_state_in_state(state : LimboState,target: LimboState) -> LimboState:
|
|
|
|
|
|
if state == target:
|
|
|
|
|
|
return target
|
|
|
|
|
|
|
|
|
|
|
|
var active_substate : LimboState = null
|
|
|
|
|
|
|
|
|
|
|
|
# 如果这个状态有 get_active_state() 方法,就调用
|
|
|
|
|
|
if state.has_method("get_active_state"):
|
|
|
|
|
|
active_substate = state.get_active_state()
|
|
|
|
|
|
|
|
|
|
|
|
if active_substate == target:
|
|
|
|
|
|
return target
|
|
|
|
|
|
|
|
|
|
|
|
# 如果没有子状态,返回自己
|
|
|
|
|
|
if active_substate == null:
|
|
|
|
|
|
return null
|
|
|
|
|
|
|
|
|
|
|
|
# 如果有子状态,继续递归
|
|
|
|
|
|
return _get_target_state_in_state(active_substate,target)
|
|
|
|
|
|
|
2025-12-29 11:54:31 +08:00
|
|
|
|
static func get_direction_vector(dir: Direction) -> Vector2:
|
|
|
|
|
|
return Vector2(1,0) if dir == Direction.RIGHT else Vector2(-1,0)
|