-
-
Notifications
You must be signed in to change notification settings - Fork 48
/
agent_base.gd
161 lines (123 loc) · 4.53 KB
/
agent_base.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#*
#* agent_base.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* 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 CharacterBody2D
## Base agent script that is shared by all agents.
signal death
# Resource file to use in summon_minion() method.
const MINION_RESOURCE := "res://demo/agents/03_agent_imp.tscn"
# Projectile resource.
const NinjaStar := preload("res://demo/agents/ninja_star/ninja_star.tscn")
const Fireball := preload("res://demo/agents/fireball/fireball.tscn")
var summon_count: int = 0
var _frames_since_facing_update: int = 0
var _is_dead: bool = false
var _moved_this_frame: bool = false
@onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var health: Health = $Health
@onready var root: Node2D = $Root
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
@onready var summoning_effect: GPUParticles2D = $FX/Summoned
func _ready() -> void:
health.damaged.connect(_damaged)
health.death.connect(die)
func _physics_process(_delta: float) -> void:
_post_physics_process.call_deferred()
func _post_physics_process() -> void:
if not _moved_this_frame:
velocity = lerp(velocity, Vector2.ZERO, 0.5)
_moved_this_frame = false
func move(p_velocity: Vector2) -> void:
velocity = lerp(velocity, p_velocity, 0.2)
move_and_slide()
_moved_this_frame = true
## Update agent's facing in the velocity direction.
func update_facing() -> void:
_frames_since_facing_update += 1
if _frames_since_facing_update > 3:
face_dir(velocity.x)
## Face specified direction.
func face_dir(dir: float) -> void:
if dir > 0.0 and root.scale.x < 0.0:
root.scale.x = 1.0;
_frames_since_facing_update = 0
if dir < 0.0 and root.scale.x > 0.0:
root.scale.x = -1.0;
_frames_since_facing_update = 0
## Returns 1.0 when agent is facing right.
## Returns -1.0 when agent is facing left.
func get_facing() -> float:
return signf(root.scale.x)
func throw_ninja_star() -> void:
var ninja_star := NinjaStar.instantiate()
ninja_star.dir = get_facing()
get_parent().add_child(ninja_star)
ninja_star.global_position = global_position + Vector2.RIGHT * 100.0 * get_facing()
func spit_fire() -> void:
var fireball := Fireball.instantiate()
fireball.dir = get_facing()
get_parent().add_child(fireball)
fireball.global_position = global_position + Vector2.RIGHT * 100.0 * get_facing()
func summon_minion(p_position: Vector2) -> void:
var minion: CharacterBody2D = load(MINION_RESOURCE).instantiate()
get_parent().add_child(minion)
minion.position = p_position
minion.play_summoning_effect()
summon_count += 1
minion.death.connect(func(): summon_count -= 1)
## Method is used when this agent is summoned from the dungeons of the castle AaaAaaAAAAAaaAAaaaaaa
func play_summoning_effect() -> void:
summoning_effect.emitting = true
## Is specified position inside the arena (not inside an obstacle)?
func is_good_position(p_position: Vector2) -> bool:
var space_state := get_world_2d().direct_space_state
var params := PhysicsPointQueryParameters2D.new()
params.position = p_position
params.collision_mask = 1 # Obstacle layer has value 1
var collision := space_state.intersect_point(params)
return collision.is_empty()
## When agent is damaged...
func _damaged(_amount: float, knockback: Vector2) -> void:
apply_knockback(knockback)
animation_player.play(&"hurt")
var btplayer := get_node_or_null(^"BTPlayer") as BTPlayer
if btplayer:
btplayer.set_active(false)
var hsm := get_node_or_null(^"LimboHSM")
if hsm:
hsm.set_active(false)
await animation_player.animation_finished
if btplayer and not _is_dead:
btplayer.restart()
if hsm and not _is_dead:
hsm.set_active(true)
## Push agent in the knockback direction for the specified number of physics frames.
func apply_knockback(knockback: Vector2, frames: int = 10) -> void:
if knockback.is_zero_approx():
return
for i in range(frames):
move(knockback)
await get_tree().physics_frame
func die() -> void:
if _is_dead:
return
death.emit()
_is_dead = true
root.process_mode = Node.PROCESS_MODE_DISABLED
animation_player.play(&"death")
collision_shape_2d.set_deferred(&"disabled", true)
for child in get_children():
if child is BTPlayer or child is LimboHSM:
child.set_active(false)
if get_tree():
await get_tree().create_timer(10.0).timeout
queue_free()
func get_health() -> Health:
return health