ufo.gd 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. extends CharacterBody2D
  2. class_name UFO
  3. @export var movement_speed: float = 800.0
  4. @export var radius: float = 150.0
  5. var max_velocity: float = movement_speed
  6. @onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D
  7. @onready var plants: Node = $"../../Plants"
  8. var target: Plant = null
  9. var target2: Plant = null
  10. var announce_self: bool = false
  11. var dead = false
  12. @export_range(1.0, 1000.0) var dps: float = 10.0
  13. @export var max_hp = 100.0
  14. var hp: float
  15. var dead_timer: Timer = Timer.new()
  16. @export var wheat_out: int = 3
  17. var Wheat = preload("res://scene/entity/wheat.tscn")
  18. @export var should_rotate: bool = true
  19. @onready var ray = $Plx/Ray
  20. @onready var ray2 = find_child("Ray2")
  21. var attack_range = 1000.0
  22. var second_player = find_child("AudioStreamPlayer2D2")
  23. @onready var power_level: float = $"../../Waves".power_level
  24. func _ready():
  25. call_deferred("actor_setup")
  26. navigation_agent.connect("velocity_computed", move)
  27. max_hp *= power_level
  28. dps *= power_level * sqrt(power_level)
  29. $RerollTimer.connect("timeout", roll_movement_target)
  30. $DamageTimer.connect("timeout", damage_target)
  31. navigation_agent.set_path_desired_distance(10.0)
  32. navigation_agent.set_target_desired_distance(attack_range)
  33. navigation_agent.set_path_max_distance(40.0)
  34. navigation_agent.set_avoidance_enabled(true)
  35. navigation_agent.set_radius(radius)
  36. navigation_agent.set_neighbor_distance(movement_speed * 2)
  37. navigation_agent.set_max_speed(movement_speed)
  38. $AudioStreamPlayer2D.set_bus("Music" + str(randi_range(0, 3)))
  39. $AudioStreamPlayer2D.play($"../../HomeSound".get_playback_position())
  40. if second_player != null:
  41. second_player.set_bus("Music" + str(randi_range(0, 3)))
  42. second_player.play($"../../HomeSound".get_playback_position())
  43. hp = max_hp
  44. $Plx/HP.set_max(max_hp)
  45. $Plx/HP.set_value(max_hp)
  46. func _process(delta):
  47. if dead:
  48. _process_dead(delta)
  49. if navigation_agent.is_target_reached() and target != null:
  50. enable_ray(ray, target)
  51. if ray2 != null:
  52. if target2 == null or target2.dead:
  53. target2 = roll_aux_target()
  54. if target2 != null:
  55. enable_ray(ray2, target2)
  56. else:
  57. hide_ray(ray2)
  58. if $DamageTimer.is_stopped():
  59. $DamageTimer.start()
  60. if target.dead:
  61. if target2 != null:
  62. target = target2
  63. target2 = null
  64. else:
  65. target = roll_movement_target()
  66. hide_ray(ray)
  67. else:
  68. hide_ray(ray)
  69. hide_ray(ray2)
  70. $DamageTimer.stop()
  71. func _process_dead(delta: float):
  72. var time_left = dead_timer.get_time_left() * 3.0
  73. var scale = ease(time_left, 5)
  74. set_scale(Vector2(scale, scale))
  75. $AudioStreamPlayer2D.set_volume_db($AudioStreamPlayer2D.get_volume_db() - delta * 30.0)
  76. if second_player != null:
  77. second_player.set_volume_db(second_player.get_volume_db() - delta * 30.0)
  78. if time_left == 0.0:
  79. get_parent().remove_child(self)
  80. queue_free()
  81. func _physics_process(delta):
  82. if navigation_agent.is_target_reached():
  83. var new_speed = velocity.length() - delta * movement_speed * 2.0
  84. velocity = velocity.normalized() * new_speed
  85. move_and_slide()
  86. else:
  87. var current_agent_position: Vector2 = global_transform.origin
  88. var next_path_position: Vector2 = navigation_agent.get_next_location()
  89. var new_velocity: Vector2 = next_path_position - current_agent_position
  90. new_velocity = new_velocity.normalized()
  91. new_velocity = new_velocity * movement_speed
  92. navigation_agent.set_velocity(new_velocity)
  93. func actor_setup():
  94. await get_tree().physics_frame
  95. target = roll_movement_target()
  96. func roll_movement_target():
  97. var all_plants = plants.get_children()
  98. var count = all_plants.size()
  99. announce_self = true
  100. var res: UFO = null
  101. if count == 0:
  102. $RerollTimer.start()
  103. else:
  104. var i = 0
  105. while (res == null or res.dead) and i < 10:
  106. res = all_plants[randi_range(0, count - 1)]
  107. i += 1
  108. if i == 10:
  109. res = null
  110. $RerollTimer.start()
  111. else:
  112. navigation_agent.set_target_location(res.get_global_position())
  113. return res
  114. func roll_aux_target():
  115. var all_plants = plants.get_children()
  116. for plant in all_plants:
  117. if plant != target and plant.get_global_position().distance_to(get_global_position()) <= attack_range:
  118. return plant
  119. return null
  120. func damage_target():
  121. if target != null:
  122. target.deal_damage(dps / 20.0, self if announce_self else null)
  123. if target2 != null:
  124. target2.deal_damage(dps / 20.0, self if announce_self else null)
  125. func move(velocity_: Vector2):
  126. velocity = velocity_
  127. move_and_slide()
  128. if should_rotate:
  129. var top = find_child("Top")
  130. top.set_rotation(lerp_angle(top.get_rotation(), velocity.angle(), 10.0 * get_physics_process_delta_time()))
  131. func _on_area_2d_body_entered(body):
  132. if body.get_class() == "Bullet":
  133. deal_damage(body.damage)
  134. body.get_parent().remove_child(body)
  135. body.queue_free()
  136. func deal_damage(damage):
  137. hp -= damage
  138. $Plx/HP.set_value(hp)
  139. if hp <= 0 and not dead:
  140. dead = true
  141. $Coin.play()
  142. set_collision_layer_value(1, false)
  143. set_collision_mask_value(1, false)
  144. $Plx/HP.hide()
  145. dead_timer.set_wait_time(0.333)
  146. dead_timer.set_one_shot(true)
  147. add_child(dead_timer)
  148. dead_timer.start()
  149. $DamageTimer.stop()
  150. hide_ray(ray)
  151. hide_ray(ray2)
  152. call_deferred("spawn_wheat")
  153. func spawn_wheat():
  154. for i in range(0, wheat_out):
  155. var wheat = Wheat.instantiate()
  156. wheat.rotate(randf_range(-PI, PI))
  157. wheat.set_position(get_global_position())
  158. $"../../Wheat".add_child(wheat)
  159. func enable_ray(ray, target: Node2D):
  160. if ray != null:
  161. var diff = target.get_global_position() - get_global_position()
  162. var poly = ray.get_polygon()
  163. poly[1] = diff + Vector2(-80.0, target.height / 1.5 + target.y_offset)
  164. poly[2] = diff + Vector2(80.0, target.height / 1.5 + target.y_offset)
  165. ray.set_polygon(poly)
  166. ray.show()
  167. func hide_ray(r):
  168. if r != null:
  169. r.hide()