class_name Player extends CharacterBody2D @onready var raycast: RayCast2D = $RayCast2D @onready var sprite: AnimatedSprite2D = $AnimatedSprite2D @onready var map: MainLevel = get_tree().root.get_child(0).get_node("TileMap") @onready var tile_map: TileMapLayer = get_tree().root.get_child(0).get_node("TileMap/TileMapLayer") @onready var camera: Camera2D = $Sprite2D/Camera2D @onready var start_point: Node2D = get_tree().root.get_child(0).get_node("Start") const TILE_SIZE = 8 @export var speed: float = 40 @export var checkpoints: Array[Node2D] @export var current_checkpoint := 0 var is_moving = false var should_move = false var is_dead = false var input_dir: Vector2 var respawn_time: int = 10 var can_teleport := true var rng := RandomNumberGenerator.new() var camera_shake: float = 0.0 var camera_shake_fade: float = 0.0 var attack_frame := 0 func _ready(): _respawn() pass func _process(delta): if not is_dead: _try_get_input() _try_interact() _shake_camera(delta) if is_dead: if respawn_time > 0: respawn_time -= 1 elif respawn_time <= 0: _respawn() func _physics_process(delta): _try_move(delta) func _respawn(): sprite.stop() sprite.frame = 0 if checkpoints.size() > 0 and checkpoints[current_checkpoint]: position = checkpoints[current_checkpoint].position else: position = start_point.position sprite.global_position = position is_dead = false is_moving = false should_move = false func _try_get_input(): should_move = false if Input.is_action_pressed("move_up"): input_dir = Vector2.UP should_move = true elif Input.is_action_pressed("move_right"): input_dir = Vector2.RIGHT should_move = true elif Input.is_action_pressed("move_down"): input_dir = Vector2.DOWN should_move = true elif Input.is_action_pressed("move_left"): input_dir = Vector2.LEFT should_move = true _change_sprite() if attack_frame > 0: attack_frame -= 1 if not should_move and not is_moving and attack_frame <= 0: sprite.frame = 0 sprite.stop() if should_move and not is_moving: sprite.play() raycast.target_position = input_dir * 8 raycast.force_raycast_update() if raycast.is_colliding(): return var current_tile: Vector2i = tile_map.local_to_map(global_position) var target_tile: Vector2i = Vector2i( current_tile.x + input_dir.x, current_tile.y + input_dir.y ) global_position = tile_map.map_to_local(target_tile) var is_death_tile = map.is_death_tile(global_position) if is_death_tile: die() return is_moving = true sprite.global_position = tile_map.map_to_local(current_tile) func _change_sprite(): var is_attacking = attack_frame > 0 if not is_attacking: if input_dir == Vector2.UP: sprite.animation = &"move_up" elif input_dir == Vector2.RIGHT: sprite.animation = &"move_right" sprite.flip_h = false elif input_dir == Vector2.DOWN: sprite.animation = &"move_down" elif input_dir == Vector2.LEFT: sprite.animation = &"move_right" sprite.flip_h = true func _try_move(delta: int): if not is_moving or is_dead: return sprite.global_position = sprite.global_position.move_toward(global_position, 0.5) if global_position == sprite.global_position: is_moving = false return func die(): is_dead = true is_moving = false respawn_time = 10 func apply_camera_shake(strength: float = 10.0, fade: float = 5.0): camera_shake = strength camera_shake_fade = fade func _try_interact(): raycast.target_position = input_dir * 8 raycast.force_raycast_update() if Input.is_action_just_pressed("attack"): sprite.play(&"spin") attack_frame = 50 var collider = raycast.get_collider() if collider and collider is PuzzleElement: (collider as PuzzleElement).interact(self) func teleport(pos: Vector2i): global_position = pos can_teleport = false func _shake_camera(delta): if camera_shake > 0: camera_shake = lerpf(camera_shake, 0, camera_shake_fade * delta) camera.offset = Vector2(rng.randf_range(-camera_shake, camera_shake), rng.randf_range(-camera_shake, camera_shake)) func _on_area_entered(area: Area2D): if area.is_in_group("death"): die()