Adds enemies
This commit is contained in:
parent
cf8ba8bacb
commit
76e5b1927f
324 changed files with 28447 additions and 106 deletions
103
demo/agents/player/player.gd
Normal file
103
demo/agents/player/player.gd
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#*
|
||||
#* 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
|
||||
53
demo/agents/player/player.tscn
Normal file
53
demo/agents/player/player.tscn
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
[gd_scene load_steps=8 format=3 uid="uid://d07ag5dcje13i"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://ooigbfhfy4wa" path="res://demo/agents/agent_base.tscn" id="1_mswd4"]
|
||||
[ext_resource type="Script" path="res://demo/agents/player/player.gd" id="2_24nyi"]
|
||||
[ext_resource type="Script" path="res://demo/agents/player/states/idle_state.gd" id="3_ekb12"]
|
||||
[ext_resource type="Script" path="res://demo/agents/player/states/move_state.gd" id="4_paikn"]
|
||||
[ext_resource type="Script" path="res://demo/agents/player/states/attack_state.gd" id="5_mpgu6"]
|
||||
[ext_resource type="Script" path="res://demo/agents/player/states/dodge_state.gd" id="6_7o4a6"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_8pofm"]
|
||||
size = Vector2(150, 50)
|
||||
|
||||
[node name="Player" groups=["player"] instance=ExtResource("1_mswd4")]
|
||||
collision_layer = 0
|
||||
collision_mask = 1
|
||||
script = ExtResource("2_24nyi")
|
||||
dodge_cooldown = 0.4
|
||||
|
||||
[node name="Hitbox" parent="Root" index="1"]
|
||||
collision_mask = 8
|
||||
|
||||
[node name="HitboxCollisionShape2D" parent="Root/Hitbox" index="0"]
|
||||
shape = SubResource("RectangleShape2D_8pofm")
|
||||
|
||||
[node name="Hurtbox" parent="Root" index="2"]
|
||||
collision_layer = 4
|
||||
|
||||
[node name="Health" parent="." index="3"]
|
||||
max_health = 30.0
|
||||
|
||||
[node name="LimboHSM" type="LimboHSM" parent="." index="4"]
|
||||
|
||||
[node name="IdleState" type="LimboState" parent="LimboHSM" index="0" node_paths=PackedStringArray("animation_player")]
|
||||
script = ExtResource("3_ekb12")
|
||||
animation_player = NodePath("../../AnimationPlayer")
|
||||
idle_animation = &"idle"
|
||||
|
||||
[node name="MoveState" type="LimboState" parent="LimboHSM" index="1" node_paths=PackedStringArray("animation_player")]
|
||||
script = ExtResource("4_paikn")
|
||||
animation_player = NodePath("../../AnimationPlayer")
|
||||
animation = &"walk"
|
||||
|
||||
[node name="AttackState" type="LimboState" parent="LimboHSM" index="2" node_paths=PackedStringArray("animation_player", "hitbox")]
|
||||
script = ExtResource("5_mpgu6")
|
||||
animation_player = NodePath("../../AnimationPlayer")
|
||||
animations = Array[StringName]([&"attack_1", &"attack_2", &"attack_3"])
|
||||
hitbox = NodePath("../../Root/Hitbox")
|
||||
|
||||
[node name="DodgeState" type="LimboState" parent="LimboHSM" index="3" node_paths=PackedStringArray("animation_player", "hurtbox_collision")]
|
||||
script = ExtResource("6_7o4a6")
|
||||
animation_player = NodePath("../../AnimationPlayer")
|
||||
animation = &"dodge"
|
||||
hurtbox_collision = NodePath("../../Root/Hurtbox/HurtboxCollisionShape2D")
|
||||
60
demo/agents/player/states/attack_state.gd
Normal file
60
demo/agents/player/states/attack_state.gd
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#*
|
||||
#* attack_state.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 LimboState
|
||||
|
||||
## Attack state: Perform 3-part combo attack for as long as player hits attack button.
|
||||
|
||||
@export var animation_player: AnimationPlayer
|
||||
@export var animations: Array[StringName]
|
||||
@export var hitbox: Hitbox
|
||||
|
||||
## Cooldown duration after third attack in the combo is complete.
|
||||
@export var combo_cooldown: float = 0.1
|
||||
|
||||
var anim_index: int = 0
|
||||
var last_attack_msec: int = -10000
|
||||
var _can_enter: bool = true
|
||||
|
||||
|
||||
## This func is used to prevent entering this state using LimboState.set_guard().
|
||||
## Entry is denied for a short duration after the third attack in the combo is complete.
|
||||
func can_enter() -> bool:
|
||||
return _can_enter
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
if (Time.get_ticks_msec() - last_attack_msec) < 200:
|
||||
# Perform next attack animation in the 3-part combo, if an attack was recently performed.
|
||||
anim_index = (anim_index + 1) % 3
|
||||
else:
|
||||
anim_index = 0
|
||||
|
||||
var horizontal_move: float = Input.get_axis(&"move_left", &"move_right")
|
||||
if not is_zero_approx(horizontal_move):
|
||||
agent.face_dir(horizontal_move)
|
||||
|
||||
hitbox.damage = 2 if anim_index == 2 else 1 # deal 2 damage on a third attack in the combo
|
||||
animation_player.play(animations[anim_index])
|
||||
|
||||
await animation_player.animation_finished
|
||||
if is_active():
|
||||
get_root().dispatch(EVENT_FINISHED)
|
||||
|
||||
|
||||
func _exit() -> void:
|
||||
hitbox.damage = 1
|
||||
last_attack_msec = Time.get_ticks_msec()
|
||||
if anim_index == 2 and _can_enter:
|
||||
# Prevent entering this state for a short duration after the third attack
|
||||
# in the combo sequence is complete.
|
||||
_can_enter = false
|
||||
await get_tree().create_timer(combo_cooldown).timeout
|
||||
_can_enter = true
|
||||
48
demo/agents/player/states/dodge_state.gd
Normal file
48
demo/agents/player/states/dodge_state.gd
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#*
|
||||
#* dodge_state.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 LimboState
|
||||
## Dodge state.
|
||||
|
||||
|
||||
@export var animation_player: AnimationPlayer
|
||||
@export var animation: StringName
|
||||
@export var duration: float = 0.4
|
||||
@export var dodge_speed: float = 1000.0
|
||||
@export var hurtbox_collision: CollisionShape2D
|
||||
|
||||
var move_dir: Vector2
|
||||
var elapsed_time: float
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
elapsed_time = 0.0
|
||||
hurtbox_collision.disabled = true
|
||||
|
||||
var horizontal_move: float = Input.get_axis(&"move_left", &"move_right")
|
||||
if is_zero_approx(horizontal_move):
|
||||
move_dir = Vector2.RIGHT * agent.get_facing()
|
||||
else:
|
||||
move_dir = Vector2.RIGHT * signf(horizontal_move)
|
||||
agent.face_dir(move_dir.x)
|
||||
|
||||
animation_player.play(animation, 0.1)
|
||||
|
||||
|
||||
func _exit() -> void:
|
||||
hurtbox_collision.set_deferred(&"disabled", false)
|
||||
|
||||
|
||||
func _update(p_delta: float) -> void:
|
||||
elapsed_time += p_delta
|
||||
var desired_velocity: Vector2 = move_dir * dodge_speed
|
||||
agent.move(desired_velocity)
|
||||
if elapsed_time > duration:
|
||||
get_root().dispatch(EVENT_FINISHED)
|
||||
27
demo/agents/player/states/idle_state.gd
Normal file
27
demo/agents/player/states/idle_state.gd
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#*
|
||||
#* idle_state.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 LimboState
|
||||
## Idle state.
|
||||
|
||||
|
||||
@export var animation_player: AnimationPlayer
|
||||
@export var idle_animation: StringName
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
animation_player.play(idle_animation, 0.1)
|
||||
|
||||
|
||||
func _update(_delta: float) -> void:
|
||||
var horizontal_move: float = Input.get_axis(&"move_left", &"move_right")
|
||||
var vertical_move: float = Input.get_axis(&"move_up", &"move_down")
|
||||
if horizontal_move != 0.0 or vertical_move != 0.0:
|
||||
get_root().dispatch(EVENT_FINISHED)
|
||||
37
demo/agents/player/states/move_state.gd
Normal file
37
demo/agents/player/states/move_state.gd
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#*
|
||||
#* move_state.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 LimboState
|
||||
## Move state.
|
||||
|
||||
|
||||
const VERTICAL_FACTOR := 0.8
|
||||
|
||||
@export var animation_player: AnimationPlayer
|
||||
@export var animation: StringName
|
||||
@export var speed: float = 500.0
|
||||
|
||||
|
||||
func _enter() -> void:
|
||||
animation_player.play(animation, 0.1)
|
||||
|
||||
|
||||
func _update(_delta: float) -> void:
|
||||
var horizontal_move: float = Input.get_axis(&"move_left", &"move_right")
|
||||
var vertical_move: float = Input.get_axis(&"move_up", &"move_down")
|
||||
|
||||
if not is_zero_approx(horizontal_move):
|
||||
agent.face_dir(horizontal_move)
|
||||
|
||||
var desired_velocity := Vector2(horizontal_move, vertical_move * VERTICAL_FACTOR) * speed
|
||||
agent.move(desired_velocity)
|
||||
|
||||
if horizontal_move == 0.0 and vertical_move == 0.0:
|
||||
get_root().dispatch(EVENT_FINISHED)
|
||||
Loading…
Add table
Add a link
Reference in a new issue