#* #* player.gd #* ============================================================================= #* Copyright (c) 2023-present Serhii Snitsaruk and the LimboAI contributors. #* #* Use of this source code is governed by an MIT-style #* license that can be found in the LICENSE file or at #* https://opensource.org/licenses/MIT. #* ============================================================================= #* extends "res://demo/agents/scripts/agent_base.gd" ## Player. @export var dodge_cooldown: float = 0.4 @onready var hsm: LimboHSM = $LimboHSM @onready var idle_state: LimboState = $LimboHSM/IdleState @onready var move_state: LimboState = $LimboHSM/MoveState @onready var attack_state: LimboState = $LimboHSM/AttackState @onready var dodge_state: LimboState = $LimboHSM/DodgeState var can_dodge: bool = true var attack_pressed: bool = false func _ready() -> void: super._ready() can_dodge = true _init_input_events() _init_state_machine() death.connect(func(): remove_from_group(&"player")) func _unhandled_input(event: InputEvent) -> void: if event.is_echo(): return if event.is_action_pressed("attack"): attack_pressed = true _process_attack_input() if event.is_action_pressed("dodge"): hsm.dispatch("dodge!") func _process_attack_input() -> void: if not attack_pressed or hsm.get_active_state() == attack_state: return hsm.dispatch("attack!") attack_pressed = false func _init_state_machine() -> void: hsm.add_transition(idle_state, move_state, idle_state.EVENT_FINISHED) hsm.add_transition(move_state, idle_state, move_state.EVENT_FINISHED) hsm.add_transition(idle_state, attack_state, "attack!") hsm.add_transition(move_state, attack_state, "attack!") hsm.add_transition(attack_state, move_state, attack_state.EVENT_FINISHED) hsm.add_transition(hsm.ANYSTATE, dodge_state, "dodge!") hsm.add_transition(dodge_state, move_state, dodge_state.EVENT_FINISHED) dodge_state.set_guard(_can_dodge) attack_state.set_guard(attack_state.can_enter) # Process attack input buffer when move_state is entered. # This way we can buffer the attack button presses and chain the attacks. move_state.call_on_enter(_process_attack_input) hsm.initialize(self) hsm.set_active(true) func _init_input_events() -> void: # Note: Ensures that input events are present even if project.godot wasn't imported. _add_action(&"move_left", KEY_A) _add_action(&"move_right", KEY_D) _add_action(&"move_up", KEY_W) _add_action(&"move_down", KEY_S) _add_action(&"dodge", KEY_SPACE) _add_action(&"attack", KEY_ENTER, KEY_F) func _add_action(p_action: StringName, p_key: Key, p_alt: Key = KEY_NONE) -> void: if not InputMap.has_action(p_action): InputMap.add_action(p_action) var event := InputEventKey.new() event.keycode = p_key InputMap.action_add_event(p_action, event) if p_alt != KEY_NONE: var alt := InputEventKey.new() alt.keycode = p_alt InputMap.action_add_event(p_action, alt) func set_victorious() -> void: idle_state.idle_animation = &"dance" func _can_dodge() -> bool: if can_dodge: can_dodge = false get_tree().create_timer(dodge_cooldown).timeout.connect(func(): can_dodge = true) return true return false