fuzzyworld

godot-shooter / asteroids / files / actors / Enemy.gd

Branch asteroids · default branch · all branches

Enemy.gd

Blame: the commit that last changed each line · file · history

b856550a 2023-10-30 Pavel Safronov1extends KinematicBody2D
f398dcb9 2023-11-02 Pavel Safronov2class_name Enemy
b856550a 2023-10-30 Pavel Safronov3
cf2013fa 2023-11-02 Pavel Safronov4onready var damage_points = $DamagePoints
023ec2fb 2023-11-29 Pavel Safronov5onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D
3dea036b 2024-12-23 Pavel Safronov6onready var viewcone_polygon2d: Polygon2D = $ViewconePolygon2D
16938031 2023-11-17 Pavel Safronov7const Utils = preload("res://utils/Utils.gd")
8const Explosion = preload("res://effects/Explosion.tscn")
9const Smoke = preload("res://effects/Smoke.tscn")
2b4497bb 2023-11-27 Pavel Safronov10const Damage = preload("res://effects/Damage.tscn")
ee6296b3 2023-11-17 Pavel Safronov11const Constants = preload("res://utils/Constants.gd")
0f8974b8 2023-12-01 Pavel Safronov12const Weapons = preload("res://weapons/Weapons.gd")
b856550a 2023-10-30 Pavel Safronov13
50d0dc8b 2023-12-21 Pavel Safronov14export var is_invincible = false
ee6296b3 2023-11-17 Pavel Safronov15export var move_speed = Constants.SPEED * 1.05
4c85b9c3 2023-11-29 Pavel Safronov16export var turn_rate = 0.03
e9f8f8f2 2023-11-01 Pavel Safronov17export var health = -1
3fcb817e 2023-11-10 Pavel Safronov18export var max_health = 100
1d4ba5a6 2023-11-02 Pavel Safronov19export var is_targeted = false
4c85b9c3 2023-11-29 Pavel Safronov20export var target: Vector2
21export var follow_target = false
11ed9f7a 2023-11-08 Pavel Safronov22signal enemy_killed(position)
b856550a 2023-10-30 Pavel Safronov23
3dea036b 2024-12-23 Pavel Safronov24var player: Node2D
0f8974b8 2023-12-01 Pavel Safronov25var weapon: Weapon
b856550a 2023-10-30 Pavel Safronov26var velocity = Vector2.ZERO
27var dead = false
8adb41dc 2023-11-19 Pavel Safronov28var health_ratio
29var health_percentage
3dea036b 2024-12-23 Pavel Safronov30var sees_player: bool
b856550a 2023-10-30 Pavel Safronov31
e9f8f8f2 2023-11-01 Pavel Safronov32func _ready() -> void:
0f8974b8 2023-12-01 Pavel Safronov33 weapon = Weapons.create_basic_enemy_gun()
6ad40cea 2023-12-01 Pavel Safronov34 navigation_agent.max_speed = move_speed
023ec2fb 2023-11-29 Pavel Safronov35 var _err = navigation_agent.connect("path_changed", self, "path_changed")
36 _err = navigation_agent.connect("velocity_computed", self, "velocity_computed")
37 _err = navigation_agent.connect("target_reached", self, "target_reached")
50d0dc8b 2023-12-21 Pavel Safronov38 var players = get_tree().get_nodes_in_group("player")
39 self.player = players[0]
40
539576dd 2023-11-07 Pavel Safronov41 $AnimationPlayer.play("fade_in")
cf2013fa 2023-11-02 Pavel Safronov42 if health < 0 or health > max_health:
e9f8f8f2 2023-11-01 Pavel Safronov43 health = max_health
cf2013fa 2023-11-02 Pavel Safronov44 else:
45 var hurt_points = max_health - health
46 health = max_health
47 for i in hurt_points:
48 hurt()
e9f8f8f2 2023-11-01 Pavel Safronov49
023ec2fb 2023-11-29 Pavel Safronov50func path_changed() -> void:
638706e1 2023-11-30 Pavel Safronov51 pass
023ec2fb 2023-11-29 Pavel Safronov52
53func velocity_computed(new_vel: Vector2) -> void:
1702bad9 2023-11-30 Pavel Safronov54 velocity = move_and_slide(new_vel)
6ad40cea 2023-12-01 Pavel Safronov55 global_rotation = velocity.angle() + PI/2.0
638706e1 2023-11-30 Pavel Safronov56 pass
023ec2fb 2023-11-29 Pavel Safronov57
58func target_reached() -> void:
50d0dc8b 2023-12-21 Pavel Safronov59 Utils.log("enemy", self, "reached player", player, "at", self.position)
6ad40cea 2023-12-01 Pavel Safronov60 player.hurt(25)
61 var explosion = Explosion.instance()
62 explosion.transform = transform
63 get_parent().add_child(explosion)
64 kill()
638706e1 2023-11-30 Pavel Safronov65 pass
023ec2fb 2023-11-29 Pavel Safronov66
236d1677 2023-11-01 Pavel Safronov67func _process(_delta: float) -> void:
3dea036b 2024-12-23 Pavel Safronov68 var is_player_in_visibility_cone = Geometry.is_point_in_polygon(player.global_position, viewcone_polygon2d.polygon)
69 if is_player_in_visibility_cone:
70 var space_state = get_world_2d().direct_space_state
71 var intersections = space_state.intersect_ray(global_position, player.global_position, [self])
72 if intersections.size() == 1:
73 var collider = intersections[0]['collider']
74 sees_player = collider == player
75
76 if sees_player:
77 set_target(player.global_position)
78
8adb41dc 2023-11-19 Pavel Safronov79 var pb: ProgressBar = $Graphics/Alive/Container/ProgressBar
80 health_ratio = float(health) / float(max_health)
81 health_percentage = health_ratio * 100
82 pb.value = health_percentage
83 if health_percentage < 20:
84 pb.modulate = Color.red
85 elif health_percentage < 60:
86 pb.modulate = Color.yellow
87 else:
88 pb.modulate = Color.blue
614e7fb1 2023-10-31 Pavel Safronov89 $Graphics/Alive/Container.global_rotation = 0
8adb41dc 2023-11-19 Pavel Safronov90 $Graphics/Alive/Sprite/Target.visible = is_targeted
91 $Graphics/Alive/Sprite/Target.global_rotation = 0
92 $Graphics/Alive/Sprite/Trails.add_position(global_position)
0f8974b8 2023-12-01 Pavel Safronov93
94 var dist_to_player = global_position.distance_to(player.global_position)
50d0dc8b 2023-12-21 Pavel Safronov95# Utils.log("dist to player", dist_to_player)
96 if dist_to_player < 25:
97 target_reached()
0f8974b8 2023-12-01 Pavel Safronov98
99 var should_shoot = dist_to_player < weapon.shooting_range
100 if should_shoot:
101 var space_state = get_world_2d().direct_space_state
102 var intersections = space_state.intersect_ray(global_position, player.global_position, [self])
103 var hits_player = intersections and intersections.collider == player
104 if hits_player:
105 weapon.try_shoot(self, player.global_position)
614e7fb1 2023-10-31 Pavel Safronov106
6ad40cea 2023-12-01 Pavel Safronov107func _physics_process(delta: float) -> void:
b856550a 2023-10-30 Pavel Safronov108 if dead:
109 return
023ec2fb 2023-11-29 Pavel Safronov110
111 # navigate to the next position
112 var current_pos = global_position
113 var next_pos = navigation_agent.get_next_location()
1702bad9 2023-11-30 Pavel Safronov114 var diff: Vector2 = next_pos - current_pos
115 var dir = diff.normalized()
6ad40cea 2023-12-01 Pavel Safronov116 var desired_vel = dir * navigation_agent.max_speed
117 var steering = (desired_vel - velocity) * delta * 4
118 var new_vel = velocity + steering
119 velocity = new_vel
120
1702bad9 2023-11-30 Pavel Safronov121 if navigation_agent.avoidance_enabled:
6ad40cea 2023-12-01 Pavel Safronov122 navigation_agent.set_velocity(velocity)
1702bad9 2023-11-30 Pavel Safronov123 else:
6ad40cea 2023-12-01 Pavel Safronov124 velocity_computed(velocity)
b856550a 2023-10-30 Pavel Safronov125
023ec2fb 2023-11-29 Pavel Safronov126func set_target(pos: Vector2):
127# var to_dir = (pos - global_position).normalized()
128# var curr_dir = velocity.normalized()
129# var dir_diff = to_dir - curr_dir
130# var change = dir_diff * turn_rate * move_speed
131# velocity = (velocity + change).normalized() * move_speed
1702bad9 2023-11-30 Pavel Safronov132# var nav_map = navigation_agent.get_navigation_map()
638706e1 2023-11-30 Pavel Safronov133# Utils.log("setting target location", pos, "map", nav_map)
023ec2fb 2023-11-29 Pavel Safronov134 navigation_agent.set_target_location(pos)
e496c548 2023-11-06 Pavel Safronov135
13440f93 2023-11-27 Pavel Safronov136func _ensure_smoke_exists() -> void:
137 var max_smoke_count = $DamagePoints.get_child_count()
138 var existing_smoke_count = $DamageObjects.get_child_count()
139 var expected_smoke_count = ceil(health_ratio * max_smoke_count)
140 var smoke_to_add_count = expected_smoke_count - existing_smoke_count
141 for i in smoke_to_add_count:
142 var smoke = Smoke.instance()
143 var smoke_pos = get_damage_point_on_body()
144 smoke.position = smoke_pos
145 $DamageObjects.add_child(smoke)
146
bd0825dd 2023-11-09 Pavel Safronov147func hurt(damage: int = 1):
52220002 2023-11-06 Pavel Safronov148 if dead || is_invincible:
b856550a 2023-10-30 Pavel Safronov149 return
bd0825dd 2023-11-09 Pavel Safronov150 health -= damage
2b4497bb 2023-11-27 Pavel Safronov151 add_damage_label(damage)
8adb41dc 2023-11-19 Pavel Safronov152# add_child(smoke)
13440f93 2023-11-27 Pavel Safronov153 _ensure_smoke_exists()
b856550a 2023-10-30 Pavel Safronov154 if health <= 0:
155 kill()
156
157func kill():
52220002 2023-11-06 Pavel Safronov158 if dead || is_invincible:
b856550a 2023-10-30 Pavel Safronov159 return
160 dead = true
161 $Graphics/Alive.hide()
969fd5af 2023-11-06 Pavel Safronov162 $CollisionPolygon2D.set_deferred("disabled", true)
c6faad15 2023-10-31 Pavel Safronov163 var explosion = Explosion.instance()
164 explosion.connect("explosion_done", self, "_on_death_explosion_finished")
165 $Graphics.add_child(explosion)
b856550a 2023-10-30 Pavel Safronov166 z_index = -1
11ed9f7a 2023-11-08 Pavel Safronov167 emit_signal("enemy_killed", global_position)
c6faad15 2023-10-31 Pavel Safronov168
2b4497bb 2023-11-27 Pavel Safronov169func add_damage_label(damage_amount: int = 5) -> void:
170 var damage_label: Damage = Damage.instance()
171 damage_label.value = -damage_amount
172 damage_label.position = self.position
173 get_tree().root.add_child(damage_label)
174
fc5de8ee 2023-11-09 Pavel Safronov175func teleport(dest: Vector2) -> void:
656778ea 2023-11-28 Pavel Safronov176 $Graphics/Alive/Sprite/Trails.clear()
fc5de8ee 2023-11-09 Pavel Safronov177 position = dest
178
c6faad15 2023-10-31 Pavel Safronov179func _on_death_explosion_finished():
cf2013fa 2023-11-02 Pavel Safronov180 $AnimationPlayer.play("fade_out")
181
182func get_damage_point_on_body() -> Vector2:
183 var child_count = damage_points.get_child_count()
184 var random_index = randi() % child_count
185 var random_child: Position2D = damage_points.get_child(random_index)
186 return random_child.position
969fd5af 2023-11-06 Pavel Safronov187
188func remove_thyself():
189 queue_free()
115aa5d1 2023-11-07 Pavel Safronov190
191func _on_Area2D_body_entered(body: Node) -> void:
192 var is_player = body == player
193 if is_player:
194 player.hurt(2)
195 var explosion = Explosion.instance()
196 explosion.transform = transform
197 get_parent().add_child(explosion)
198 kill()