xiandie/scene/player/main_player.gd

229 lines
6.4 KiB
GDScript

extends CharacterBody2D
class_name MainPlayer
enum MOVEMENT_STATUS {
IDLE,
WALKING,
RUNNING,
LAYING_STAY,
LAYING_MOVING,
CLIMBING_STAY,
CLIMBING,
}
@export var player_movement_rect := Rect2(50, -500, 1400, 1000)
@export var velocity_ratio := 1.0
@export var action_locked := false:
set(val):
action_locked = val
_process_action_lock()
@export var current_status: MOVEMENT_STATUS
@export var facing_direction := Vector2(1.0, -1.0)
@export var is_laying := false:
set(val):
is_laying = val
# reset the facing direction wether the player is laying or not.
_reset_face_direction()
if is_laying:
is_climbing = false
@export var is_climbing := false:
set(val):
is_climbing = val
# reset the facing direction wether the player is climbing or not.
_reset_face_direction()
if is_climbing:
is_laying = false
@export var running_locked := false
@export var speed_walking := 90.0
@export var speed_runnig := 160.0
@export var speed_laying := 60.0
@export var speed_climbing := 60.0
#const JUMP_VELOCITY = -400.0
@export var footstep_base_speed := 60.0
@onready var footstep_timer = %FootstepTimer as Timer
@onready var sprite = %AnimatedSprite2D as AnimatedSprite2D
func _ready() -> void:
# _reset_face_direction()
footstep_timer.timeout.connect(_on_footstep_timer_timeout)
footstep_timer.stop()
func _on_footstep_timer_timeout():
# ground node is sibling of the player node.
var ground_loader = SceneManager.get_ground_loader()
if ground_loader:
ground_loader.play_footstep_sound()
func _reset_face_direction() -> void:
facing_direction = Vector2(1, -1)
func _process_action_lock() -> void:
# reset status to idle or stay
if action_locked:
velocity = Vector2.ZERO
if current_status == MOVEMENT_STATUS.WALKING or current_status == MOVEMENT_STATUS.RUNNING:
current_status = MOVEMENT_STATUS.IDLE
elif current_status == MOVEMENT_STATUS.LAYING_MOVING:
current_status = MOVEMENT_STATUS.LAYING_STAY
elif current_status == MOVEMENT_STATUS.CLIMBING:
current_status = MOVEMENT_STATUS.CLIMBING_STAY
_play_animation()
# return whether the player status or facing direction has changed.
func _check_status(direction) -> bool:
var tmp_status = current_status
var new_facing_direction := facing_direction
if is_laying:
if direction.x:
new_facing_direction.x = direction.x
tmp_status = MOVEMENT_STATUS.LAYING_MOVING
else:
tmp_status = MOVEMENT_STATUS.LAYING_STAY
elif is_climbing:
if direction.y:
new_facing_direction.y = direction.y
tmp_status = MOVEMENT_STATUS.CLIMBING
else:
tmp_status = MOVEMENT_STATUS.CLIMBING_STAY
else:
if direction.x:
new_facing_direction.x = direction.x
tmp_status = MOVEMENT_STATUS.WALKING
if !running_locked and Input.is_action_pressed("run"):
tmp_status = MOVEMENT_STATUS.RUNNING
else:
tmp_status = MOVEMENT_STATUS.IDLE
if new_facing_direction != facing_direction or tmp_status != current_status:
facing_direction = new_facing_direction
current_status = tmp_status
return true
return false
func set_facing_direction(direction: Vector2) -> void:
facing_direction = direction
# update status
_check_status(direction)
func _play_animation() -> void:
match current_status:
MOVEMENT_STATUS.IDLE:
if facing_direction.x > 0.0:
sprite.play(&"idle_r")
else:
sprite.play(&"idle_l")
footstep_timer.stop()
MOVEMENT_STATUS.WALKING:
if facing_direction.x > 0.0:
sprite.play(&"walking_r")
else:
sprite.play(&"walking_l")
footstep_timer.wait_time = footstep_base_speed / speed_walking
footstep_timer.start()
MOVEMENT_STATUS.RUNNING:
if facing_direction.x > 0.0:
sprite.play(&"running_r")
else:
sprite.play(&"running_l")
footstep_timer.wait_time = footstep_base_speed / speed_runnig
footstep_timer.start()
MOVEMENT_STATUS.LAYING_STAY:
if facing_direction.x > 0.0:
sprite.play(&"laying_stay_r")
else:
sprite.play(&"laying_stay_l")
footstep_timer.stop()
MOVEMENT_STATUS.LAYING_MOVING:
if facing_direction.x > 0.0:
sprite.play(&"laying_moving_r")
else:
sprite.play(&"laying_moving_l")
footstep_timer.wait_time = footstep_base_speed / speed_laying
footstep_timer.start()
MOVEMENT_STATUS.CLIMBING_STAY:
sprite.play(&"climbing_stay")
footstep_timer.stop()
MOVEMENT_STATUS.CLIMBING:
if facing_direction.y > 0.0:
sprite.play(&"climbing_down")
else:
sprite.play(&"climbing_up")
footstep_timer.wait_time = footstep_base_speed / speed_climbing
footstep_timer.start()
func _get_speed(direction: Vector2) -> Vector2:
match current_status:
MOVEMENT_STATUS.WALKING:
return Vector2(speed_walking * direction.x, 0.0)
MOVEMENT_STATUS.RUNNING:
return Vector2(speed_runnig * direction.x, 0.0)
MOVEMENT_STATUS.LAYING_MOVING:
return Vector2(speed_laying * direction.x, 0.0)
MOVEMENT_STATUS.CLIMBING:
return Vector2(0, speed_climbing * direction.y)
return Vector2(0, 0)
func _physics_process(_delta: float) -> void:
if action_locked:
velocity = Vector2.ZERO
return
# Add the gravity.
#if not is_on_floor():
#velocity += get_gravity() * delta
#if Input.is_action_just_pressed("jump") and is_on_floor():
#velocity.y = JUMP_VELOCITY
var x_direction := Input.get_axis("left", "right")
var y_direction := Input.get_axis("up", "down")
var direction := Vector2(x_direction, y_direction)
if _check_status(direction):
_play_animation()
var speed := _get_speed(direction) as Vector2
velocity.x = move_toward(velocity.x, speed.x, 300.0) * velocity_ratio
velocity.y = move_toward(velocity.y, speed.y, 300.0) * velocity_ratio
move_and_slide()
position = position.clamp(player_movement_rect.position, player_movement_rect.end)
_tweak_camera_marker()
# drag the camera marker against the player movement
# so there will be a better vision in front of the player.
func _tweak_camera_marker():
var marker = get_node("./CameraFocusMarker") as Node2D
if marker:
marker.tweak_position(velocity, facing_direction)
var note_mutex = Mutex.new()
var note_pending_time = 0.0
var note_viewing = false
func check_note(note_time):
note_mutex.lock()
note_pending_time += note_time
if not note_viewing:
note_viewing = true
# velocity_ratio = 0.2
action_locked = true
get_tree().create_timer(note_time).timeout.connect(_check_slow)
note_mutex.unlock()
func _check_slow():
note_mutex.lock()
note_viewing = false
action_locked = false
# velocity_ratio = 1.0
note_mutex.unlock()
if note_pending_time:
note_pending_time = 0.0
check_note(note_pending_time)