class_name Character extends CharacterBody2D const GRAVITY := 1200.0 @export var speed := 180.0 @export var jump_intensity := 304.056 @export var attack_duration := 0.4 @export var attack_lunge_duration := 0.18 @export var attack_lunge_speed := 220.0 @export var air_attack_duration := 0.45 @export var air_attack_lunge_duration := 0.22 @export var air_attack_lunge_speed := 260.0 @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var character_sprite: Sprite2D = $CharacterSprite enum State { IDLE, WALK, JUMP, LAND, ATTACK, AIR_ATTACK } var anim_map := { State.IDLE: "warrior_idle", State.WALK: "warrior_idle", State.JUMP: "warrior_w", State.LAND: "warrior_idle", State.ATTACK: "warrior_a", State.AIR_ATTACK: "warrior_a", } var attack_direction := Vector2.RIGHT var attack_lunge_time_left := 0.0 var attack_time_left := 0.0 var heading := Vector2.RIGHT var height := 0.0 var height_speed := 0.0 var state := State.IDLE func _physics_process(delta: float) -> void: handle_input() handle_air_time(delta) handle_attack_time(delta) handle_movement() handle_animations() set_sprite_height_position() set_heading() flip_sprites() move_and_slide() func handle_input() -> void: pass func handle_air_time(delta: float) -> void: if state != State.JUMP: return height += height_speed * delta if height <= 0.0 and height_speed < 0.0: height = 0.0 height_speed = 0.0 state = State.LAND else: height_speed -= GRAVITY * delta func handle_attack_time(delta: float) -> void: if state != State.ATTACK and state != State.AIR_ATTACK: return velocity.y = 0.0 attack_time_left -= delta if attack_time_left <= 0.0: state = State.IDLE velocity = Vector2.ZERO return attack_lunge_time_left -= delta if attack_lunge_time_left <= 0.0: velocity.x = 0.0 func handle_movement() -> void: if state == State.JUMP or state == State.ATTACK or state == State.AIR_ATTACK: return if absf(velocity.x) > 0.0: state = State.WALK else: state = State.IDLE if state == State.LAND: state = State.IDLE func handle_animations() -> void: var animation_name: String = anim_map[state] if animation_player.has_animation(animation_name) and animation_player.current_animation != animation_name: animation_player.play(animation_name) func set_sprite_height_position() -> void: character_sprite.position = Vector2.UP * height func set_heading() -> void: pass func flip_sprites() -> void: character_sprite.flip_h = heading == Vector2.LEFT func can_jump() -> bool: return state == State.IDLE or state == State.WALK func can_attack() -> bool: return state == State.IDLE or state == State.WALK func can_air_attack() -> bool: return state == State.IDLE or state == State.WALK func start_jump() -> void: state = State.JUMP height_speed = jump_intensity func start_attack() -> void: start_directional_attack(heading) func start_directional_attack(direction: Vector2) -> void: var attack_x := -1.0 if direction.x < 0.0 else 1.0 attack_direction = Vector2(attack_x, 0.0) heading = Vector2.RIGHT if attack_x > 0.0 else Vector2.LEFT state = State.ATTACK attack_time_left = attack_duration attack_lunge_time_left = attack_lunge_duration velocity = Vector2(attack_x * attack_lunge_speed, 0.0) func start_air_attack() -> void: start_directional_air_attack(heading) func start_directional_air_attack(direction: Vector2) -> void: var attack_x := -1.0 if direction.x < 0.0 else 1.0 attack_direction = Vector2(attack_x, 0.0) heading = Vector2.RIGHT if attack_x > 0.0 else Vector2.LEFT state = State.AIR_ATTACK attack_time_left = air_attack_duration attack_lunge_time_left = air_attack_lunge_duration velocity = Vector2(attack_x * air_attack_lunge_speed, 0.0)