ghost-delivery/Ghost/ghost.gd

120 lines
3.3 KiB
GDScript

class_name Ghost extends CharacterBody2D
var move_speed: float = 200.0
var shift_speed: float = 400.0
var held_item: Collectable = null
enum State { Left, Right, Up, Down }
var state: State = State.Right
@onready var animationPlayer = $AnimationPlayer
@onready var interaction_area: Area2D = $InteractionArea
func _ready() -> void:
add_to_group("ghost")
func _process(_delta: float) -> void:
if GameManager.game_over:
velocity = Vector2.ZERO
return
var shift := Input.is_action_pressed("shift")
var direction := Vector2(
Input.get_action_strength("right") - Input.get_action_strength("left"),
Input.get_action_strength("down") - Input.get_action_strength("up")
)
if direction.length() > 0:
direction = direction.normalized()
velocity = direction * (shift_speed if shift else move_speed)
_update_animation()
func _physics_process(_delta: float) -> void:
if GameManager.game_over:
return
move_and_slide()
func _unhandled_input(event: InputEvent) -> void:
if GameManager.game_over:
return
if event.is_action_pressed("interact"):
_interact()
func _interact() -> void:
if held_item == null:
_try_pick_up()
else:
_try_drop()
func _try_pick_up() -> void:
var nearest: Collectable = null
var nearest_dist := INF
for area in interaction_area.get_overlapping_areas():
if area is Collectable and area.can_pick_up():
var d := global_position.distance_squared_to(area.global_position)
if d < nearest_dist:
nearest_dist = d
nearest = area
if nearest != null:
SoundManager.play_key_pickup()
_get_collectable(nearest)
func _try_drop() -> void:
for area in interaction_area.get_overlapping_areas():
if area is DropZone and area.accepts(held_item):
var item := held_item
held_item = null
area.deliver(item)
return
_drop_on_floor()
func _drop_on_floor() -> void:
var item := held_item
held_item = null
var gpos := item.global_position
item.reparent(get_tree().current_scene)
item.global_position = gpos
item.show_behind_parent = false
item.mark_dropped()
func _get_collectable(collectable: Collectable) -> void:
held_item = collectable
held_item.mark_picked_up()
held_item.reparent(self)
_apply_held_item_state()
func _held_item_position() -> Vector2:
match state:
State.Left: return held_item.positionLeft
State.Right: return held_item.positionRight
State.Up: return held_item.positionUp
_: return held_item.positionDown
func _move_held_item(target: Vector2) -> void:
if held_item == null:
return
var tween = create_tween().set_parallel(true)
tween.tween_property(held_item, "position", target, 0.15).set_ease(Tween.EASE_OUT)
func _apply_held_item_state() -> void:
if held_item == null:
return
held_item.show_behind_parent = state == State.Up
_move_held_item(_held_item_position())
func _set_state(new_state: State, animation: String) -> void:
if state == new_state:
return
state = new_state
animationPlayer.play(animation)
_apply_held_item_state()
func _update_animation() -> void:
# Left/right take priority over up/down, preserving the correct animation on diagonals.
if velocity.x < 0:
_set_state(State.Left, "idle_left")
elif velocity.x > 0:
_set_state(State.Right, "idle_right")
elif velocity.y < 0:
_set_state(State.Up, "idle_up")
elif velocity.y > 0:
_set_state(State.Down, "idle_down")