spaceship/GasBombController.gd

124 lines
4.4 KiB
GDScript3
Raw Normal View History

2026-08-15 04:45:15 +02:00
class_name GasBombController
extends "res://AimedFleetAbilityController.gd"
2026-08-15 04:45:15 +02:00
const BOMB_COLOR := Color(0.96, 0.22, 0.72)
const TARGET_COLOR := Color(0.78, 0.32, 1.0)
const MAX_RANGE := 950.0
const AOE_RADIUS := 180.0
const DRAG_RADIUS := 260.0
const PROJECTILE_SPEED := 720.0
const DAMAGE := 3
const COOLDOWN := 5.0
const GAS_PER_SHOT: int = 5
2026-08-15 04:45:15 +02:00
2026-08-15 10:12:33 +02:00
var projectiles: Array = []
var explosions: Array = []
var last_hit_count: int = 0
2026-08-15 04:45:15 +02:00
2026-08-15 10:12:33 +02:00
var projectile_active: bool:
get: return not projectiles.is_empty()
var explosion_time: float:
get:
var longest: float = 0.0
2026-08-15 10:12:33 +02:00
for explosion in explosions:
longest = maxf(longest, float(explosion.time))
return longest
2026-08-15 04:45:15 +02:00
func _button_path() -> NodePath: return "../UI/GasBombButton"
func _status_path() -> NodePath: return "../UI/GasBombStatus"
func _component_id() -> String: return "gas_bomber"
func _ammo_resource() -> String: return GameState.RESOURCE_GAS
func _ammo_cost() -> int: return GAS_PER_SHOT
func _aim_padding() -> float: return AOE_RADIUS
func _has_effect_visuals() -> bool: return not projectiles.is_empty() or not explosions.is_empty()
2026-08-15 04:45:15 +02:00
func _calculate_aim_target(drag: Vector2, origin: Vector2) -> Vector2:
if drag.length() < 0.001:
return origin
var distance: float = minf(drag.length() / DRAG_RADIUS, 1.0) * MAX_RANGE
return origin + drag.normalized() * distance
func _consume_shot(component: Node) -> bool:
return component.consume_shot(COOLDOWN)
func _perform_shot(ship: Node2D, _component: Node) -> void:
projectiles.append({
"position": ship.global_position,
"target": aim_target,
"trail": PackedVector2Array([ship.global_position]),
})
func _next_ready_bomber() -> Node2D:
return _next_ready_ship()
2026-08-15 04:45:15 +02:00
func _advance_effects(delta: float) -> void:
2026-08-15 10:12:33 +02:00
for i in range(projectiles.size() - 1, -1, -1):
var projectile: Dictionary = projectiles[i]
var distance: float = (projectile.position as Vector2).distance_to(projectile.target)
2026-08-15 04:45:15 +02:00
if distance <= PROJECTILE_SPEED * delta:
2026-08-15 10:12:33 +02:00
projectile.position = projectile.target
_explode(projectile.target)
projectiles.remove_at(i)
2026-08-15 04:45:15 +02:00
else:
projectile.position = (projectile.position as Vector2).move_toward(
projectile.target, PROJECTILE_SPEED * delta)
2026-08-15 10:12:33 +02:00
var trail: PackedVector2Array = projectile.trail
trail.append(projectile.position)
while trail.size() > 12:
trail.remove_at(0)
projectile.trail = trail
for i in range(explosions.size() - 1, -1, -1):
var explosion: Dictionary = explosions[i]
explosion.time = maxf(float(explosion.time) - delta, 0.0)
if float(explosion.time) <= 0.0:
explosions.remove_at(i)
2026-08-15 04:45:15 +02:00
func _explode(at: Vector2) -> void:
2026-08-15 10:12:33 +02:00
explosions.append({"position": at, "time": 0.8})
2026-08-15 04:45:15 +02:00
last_hit_count = 0
for enemy in get_tree().get_nodes_in_group("enemies"):
if is_instance_valid(enemy) and enemy is Node2D \
and enemy.global_position.distance_to(at) <= AOE_RADIUS:
enemy.take_damage(DAMAGE)
last_hit_count += 1
func _draw() -> void:
if aiming:
NeonDraw.draw_glowing_line(self, _aim_origin(), aim_target, TARGET_COLOR, 0.7, 0.8)
2026-08-15 04:45:15 +02:00
_draw_ring(aim_target, AOE_RADIUS, TARGET_COLOR, 0.8)
_draw_ring(aim_target, 18.0, BOMB_COLOR, 1.0)
2026-08-15 10:12:33 +02:00
for projectile in projectiles:
var trail: PackedVector2Array = projectile.trail
if trail.size() >= 2:
for i in range(1, trail.size()):
var alpha: float = float(i) / trail.size()
draw_line(trail[i - 1], trail[i], Color(BOMB_COLOR, alpha * 0.65),
4.0 + alpha * 4.0, true)
2026-08-15 10:12:33 +02:00
draw_circle(projectile.position, 12.0, Color(BOMB_COLOR, 0.35))
NeonDraw.draw_glowing_circle(self, projectile.position, 7.0, BOMB_COLOR, 1.0)
for explosion in explosions:
var progress: float = 1.0 - float(explosion.time) / 0.8
var radius: float = lerpf(24.0, AOE_RADIUS, minf(progress * 1.5, 1.0))
2026-08-15 10:12:33 +02:00
draw_circle(explosion.position, radius, Color(BOMB_COLOR, (1.0 - progress) * 0.16))
_draw_ring(explosion.position, radius, BOMB_COLOR, 1.0 - progress)
2026-08-15 04:45:15 +02:00
for i in range(7):
var angle: float = TAU * float(i) / 7.0 + progress
var cloud_at: Vector2 = explosion.position \
+ Vector2(cos(angle), sin(angle)) * radius * 0.55
draw_circle(cloud_at, 18.0 + 14.0 * progress,
Color(BOMB_COLOR, (1.0 - progress) * 0.22))
2026-08-15 04:45:15 +02:00
func _draw_ring(center: Vector2, radius: float, color: Color, alpha: float) -> void:
draw_arc(center, radius, 0.0, TAU, 64, Color(color, 0.16 * alpha), 16.0, true)
draw_arc(center, radius, 0.0, TAU, 64, Color(color, 0.5 * alpha), 6.0, true)
draw_arc(center, radius, 0.0, TAU, 64, Color(1.0, 0.86, 0.96, 0.9 * alpha), 2.0, true)