ufo.gd 6.4 KB

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