godot-shooter / files / actors / Enemy.gd
Enemy.gd
b856550a 2023-10-30 Pavel Safronov | 1 | extends KinematicBody2D |
f398dcb9 2023-11-02 Pavel Safronov | 2 | class_name Enemy |
b856550a 2023-10-30 Pavel Safronov | 3 | |
cf2013fa 2023-11-02 Pavel Safronov | 4 | onready var damage_points = $DamagePoints |
023ec2fb 2023-11-29 Pavel Safronov | 5 | onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D |
16938031 2023-11-17 Pavel Safronov | 6 | const Utils = preload("res://utils/Utils.gd") |
| 7 | const Explosion = preload("res://effects/Explosion.tscn") | |
| 8 | const Smoke = preload("res://effects/Smoke.tscn") | |
2b4497bb 2023-11-27 Pavel Safronov | 9 | const Damage = preload("res://effects/Damage.tscn") |
ee6296b3 2023-11-17 Pavel Safronov | 10 | const Constants = preload("res://utils/Constants.gd") |
0f8974b8 2023-12-01 Pavel Safronov | 11 | const Weapons = preload("res://weapons/Weapons.gd") |
b856550a 2023-10-30 Pavel Safronov | 12 | |
ee6296b3 2023-11-17 Pavel Safronov | 13 | export var move_speed = Constants.SPEED * 1.05 |
4c85b9c3 2023-11-29 Pavel Safronov | 14 | export var turn_rate = 0.03 |
e9f8f8f2 2023-11-01 Pavel Safronov | 15 | export var health = -1 |
3fcb817e 2023-11-10 Pavel Safronov | 16 | export var max_health = 100 |
1d4ba5a6 2023-11-02 Pavel Safronov | 17 | export var is_targeted = false |
52220002 2023-11-06 Pavel Safronov | 18 | export var is_invincible = false |
4c85b9c3 2023-11-29 Pavel Safronov | 19 | export var target: Vector2 |
| 20 | export var follow_target = false | |
11ed9f7a 2023-11-08 Pavel Safronov | 21 | signal enemy_killed(position) |
b856550a 2023-10-30 Pavel Safronov | 22 | |
0f8974b8 2023-12-01 Pavel Safronov | 23 | var weapon: Weapon |
b856550a 2023-10-30 Pavel Safronov | 24 | var velocity = Vector2.ZERO |
| 25 | var dead = false | |
8adb41dc 2023-11-19 Pavel Safronov | 26 | var health_ratio |
| 27 | var health_percentage | |
b856550a 2023-10-30 Pavel Safronov | 28 | |
e9f8f8f2 2023-11-01 Pavel Safronov | 29 | func _ready() -> void: |
0f8974b8 2023-12-01 Pavel Safronov | 30 | weapon = Weapons.create_basic_enemy_gun() |
6ad40cea 2023-12-01 Pavel Safronov | 31 | navigation_agent.max_speed = move_speed |
023ec2fb 2023-11-29 Pavel Safronov | 32 | var _err = navigation_agent.connect("path_changed", self, "path_changed") |
| 33 | _err = navigation_agent.connect("velocity_computed", self, "velocity_computed") | |
| 34 | _err = navigation_agent.connect("target_reached", self, "target_reached") | |
| 35 | ||
539576dd 2023-11-07 Pavel Safronov | 36 | $AnimationPlayer.play("fade_in") |
cf2013fa 2023-11-02 Pavel Safronov | 37 | if health < 0 or health > max_health: |
e9f8f8f2 2023-11-01 Pavel Safronov | 38 | health = max_health |
cf2013fa 2023-11-02 Pavel Safronov | 39 | else: |
| 40 | var hurt_points = max_health - health | |
| 41 | health = max_health | |
| 42 | for i in hurt_points: | |
| 43 | hurt() | |
e9f8f8f2 2023-11-01 Pavel Safronov | 44 | |
023ec2fb 2023-11-29 Pavel Safronov | 45 | func path_changed() -> void: |
638706e1 2023-11-30 Pavel Safronov | 46 | pass |
023ec2fb 2023-11-29 Pavel Safronov | 47 | |
| 48 | func velocity_computed(new_vel: Vector2) -> void: | |
1702bad9 2023-11-30 Pavel Safronov | 49 | velocity = move_and_slide(new_vel) |
6ad40cea 2023-12-01 Pavel Safronov | 50 | global_rotation = velocity.angle() + PI/2.0 |
638706e1 2023-11-30 Pavel Safronov | 51 | pass |
023ec2fb 2023-11-29 Pavel Safronov | 52 | |
| 53 | func target_reached() -> void: | |
6ad40cea 2023-12-01 Pavel Safronov | 54 | var players = get_tree().get_nodes_in_group("player") |
| 55 | var player = players[0] | |
| 56 | player.hurt(25) | |
| 57 | var explosion = Explosion.instance() | |
| 58 | explosion.transform = transform | |
| 59 | get_parent().add_child(explosion) | |
| 60 | kill() | |
638706e1 2023-11-30 Pavel Safronov | 61 | pass |
023ec2fb 2023-11-29 Pavel Safronov | 62 | |
236d1677 2023-11-01 Pavel Safronov | 63 | func _process(_delta: float) -> void: |
8adb41dc 2023-11-19 Pavel Safronov | 64 | var pb: ProgressBar = $Graphics/Alive/Container/ProgressBar |
| 65 | health_ratio = float(health) / float(max_health) | |
| 66 | health_percentage = health_ratio * 100 | |
| 67 | pb.value = health_percentage | |
| 68 | if health_percentage < 20: | |
| 69 | pb.modulate = Color.red | |
| 70 | elif health_percentage < 60: | |
| 71 | pb.modulate = Color.yellow | |
| 72 | else: | |
| 73 | pb.modulate = Color.blue | |
614e7fb1 2023-10-31 Pavel Safronov | 74 | $Graphics/Alive/Container.global_rotation = 0 |
8adb41dc 2023-11-19 Pavel Safronov | 75 | $Graphics/Alive/Sprite/Target.visible = is_targeted |
| 76 | $Graphics/Alive/Sprite/Target.global_rotation = 0 | |
| 77 | $Graphics/Alive/Sprite/Trails.add_position(global_position) | |
0f8974b8 2023-12-01 Pavel Safronov | 78 | |
| 79 | var players = get_tree().get_nodes_in_group("player") | |
| 80 | var player = players[0] | |
| 81 | var dist_to_player = global_position.distance_to(player.global_position) | |
| 82 | ||
| 83 | var should_shoot = dist_to_player < weapon.shooting_range | |
| 84 | if should_shoot: | |
| 85 | var space_state = get_world_2d().direct_space_state | |
| 86 | var intersections = space_state.intersect_ray(global_position, player.global_position, [self]) | |
| 87 | var hits_player = intersections and intersections.collider == player | |
| 88 | if hits_player: | |
| 89 | weapon.try_shoot(self, player.global_position) | |
614e7fb1 2023-10-31 Pavel Safronov | 90 | |
6ad40cea 2023-12-01 Pavel Safronov | 91 | func _physics_process(delta: float) -> void: |
b856550a 2023-10-30 Pavel Safronov | 92 | if dead: |
| 93 | return | |
023ec2fb 2023-11-29 Pavel Safronov | 94 | |
| 95 | # navigate to the next position | |
| 96 | var current_pos = global_position | |
| 97 | var next_pos = navigation_agent.get_next_location() | |
1702bad9 2023-11-30 Pavel Safronov | 98 | var diff: Vector2 = next_pos - current_pos |
| 99 | var dir = diff.normalized() | |
6ad40cea 2023-12-01 Pavel Safronov | 100 | var desired_vel = dir * navigation_agent.max_speed |
| 101 | var steering = (desired_vel - velocity) * delta * 4 | |
| 102 | var new_vel = velocity + steering | |
| 103 | velocity = new_vel | |
| 104 | ||
1702bad9 2023-11-30 Pavel Safronov | 105 | if navigation_agent.avoidance_enabled: |
6ad40cea 2023-12-01 Pavel Safronov | 106 | navigation_agent.set_velocity(velocity) |
1702bad9 2023-11-30 Pavel Safronov | 107 | else: |
6ad40cea 2023-12-01 Pavel Safronov | 108 | velocity_computed(velocity) |
b856550a 2023-10-30 Pavel Safronov | 109 | |
023ec2fb 2023-11-29 Pavel Safronov | 110 | func set_target(pos: Vector2): |
| 111 | # var to_dir = (pos - global_position).normalized() | |
| 112 | # var curr_dir = velocity.normalized() | |
| 113 | # var dir_diff = to_dir - curr_dir | |
| 114 | # var change = dir_diff * turn_rate * move_speed | |
| 115 | # velocity = (velocity + change).normalized() * move_speed | |
1702bad9 2023-11-30 Pavel Safronov | 116 | # var nav_map = navigation_agent.get_navigation_map() |
638706e1 2023-11-30 Pavel Safronov | 117 | # Utils.log("setting target location", pos, "map", nav_map) |
023ec2fb 2023-11-29 Pavel Safronov | 118 | navigation_agent.set_target_location(pos) |
e496c548 2023-11-06 Pavel Safronov | 119 | |
13440f93 2023-11-27 Pavel Safronov | 120 | func _ensure_smoke_exists() -> void: |
| 121 | var max_smoke_count = $DamagePoints.get_child_count() | |
| 122 | var existing_smoke_count = $DamageObjects.get_child_count() | |
| 123 | var expected_smoke_count = ceil(health_ratio * max_smoke_count) | |
| 124 | var smoke_to_add_count = expected_smoke_count - existing_smoke_count | |
| 125 | for i in smoke_to_add_count: | |
| 126 | var smoke = Smoke.instance() | |
| 127 | var smoke_pos = get_damage_point_on_body() | |
| 128 | smoke.position = smoke_pos | |
| 129 | $DamageObjects.add_child(smoke) | |
| 130 | ||
bd0825dd 2023-11-09 Pavel Safronov | 131 | func hurt(damage: int = 1): |
52220002 2023-11-06 Pavel Safronov | 132 | if dead || is_invincible: |
b856550a 2023-10-30 Pavel Safronov | 133 | return |
bd0825dd 2023-11-09 Pavel Safronov | 134 | health -= damage |
2b4497bb 2023-11-27 Pavel Safronov | 135 | add_damage_label(damage) |
8adb41dc 2023-11-19 Pavel Safronov | 136 | # add_child(smoke) |
13440f93 2023-11-27 Pavel Safronov | 137 | _ensure_smoke_exists() |
b856550a 2023-10-30 Pavel Safronov | 138 | if health <= 0: |
| 139 | kill() | |
| 140 | ||
| 141 | func kill(): | |
52220002 2023-11-06 Pavel Safronov | 142 | if dead || is_invincible: |
b856550a 2023-10-30 Pavel Safronov | 143 | return |
| 144 | dead = true | |
| 145 | $Graphics/Alive.hide() | |
969fd5af 2023-11-06 Pavel Safronov | 146 | $CollisionPolygon2D.set_deferred("disabled", true) |
c6faad15 2023-10-31 Pavel Safronov | 147 | var explosion = Explosion.instance() |
| 148 | explosion.connect("explosion_done", self, "_on_death_explosion_finished") | |
| 149 | $Graphics.add_child(explosion) | |
b856550a 2023-10-30 Pavel Safronov | 150 | z_index = -1 |
11ed9f7a 2023-11-08 Pavel Safronov | 151 | emit_signal("enemy_killed", global_position) |
c6faad15 2023-10-31 Pavel Safronov | 152 | |
2b4497bb 2023-11-27 Pavel Safronov | 153 | func add_damage_label(damage_amount: int = 5) -> void: |
| 154 | var damage_label: Damage = Damage.instance() | |
| 155 | damage_label.value = -damage_amount | |
| 156 | damage_label.position = self.position | |
| 157 | get_tree().root.add_child(damage_label) | |
| 158 | ||
fc5de8ee 2023-11-09 Pavel Safronov | 159 | func teleport(dest: Vector2) -> void: |
656778ea 2023-11-28 Pavel Safronov | 160 | $Graphics/Alive/Sprite/Trails.clear() |
fc5de8ee 2023-11-09 Pavel Safronov | 161 | position = dest |
| 162 | ||
c6faad15 2023-10-31 Pavel Safronov | 163 | func _on_death_explosion_finished(): |
cf2013fa 2023-11-02 Pavel Safronov | 164 | $AnimationPlayer.play("fade_out") |
| 165 | ||
| 166 | func get_damage_point_on_body() -> Vector2: | |
| 167 | var child_count = damage_points.get_child_count() | |
| 168 | var random_index = randi() % child_count | |
| 169 | var random_child: Position2D = damage_points.get_child(random_index) | |
| 170 | return random_child.position | |
969fd5af 2023-11-06 Pavel Safronov | 171 | |
| 172 | func remove_thyself(): | |
| 173 | queue_free() | |
115aa5d1 2023-11-07 Pavel Safronov | 174 | |
| 175 | func _on_Area2D_body_entered(body: Node) -> void: | |
| 176 | var players = get_tree().get_nodes_in_group("player") | |
f6120dba 2023-11-08 Pavel Safronov | 177 | var player = players[0] |
115aa5d1 2023-11-07 Pavel Safronov | 178 | var is_player = body == player |
| 179 | if is_player: | |
| 180 | player.hurt(2) | |
| 181 | var explosion = Explosion.instance() | |
| 182 | explosion.transform = transform | |
| 183 | get_parent().add_child(explosion) | |
| 184 | kill() |