Randoloot/scripts/game/shield_intersections.gd
2026-10-25 22:38:13 +01:00

31 lines
1.5 KiB
GDScript

extends RefCounted
static func intercept(world_hit: Dictionary, start: Vector2, end: Vector2, mask: int, excluded: Array[RID], tree: SceneTree) -> Dictionary:
var nearest := world_hit
var distance := start.distance_squared_to(world_hit.position) if not world_hit.is_empty() else INF
var segment := end-start
var length_squared := segment.length_squared()
if length_squared < 0.000001: return nearest
for target in tree.get_nodes_in_group("shielded_combatants"):
if not is_instance_valid(target) or target.is_queued_for_deletion(): continue
if (int(target.collision_layer)&mask)==0 or target.get_rid() in excluded: continue
if float(target.shields)<=0.0 or float(target.hull)<=0.0: continue
if target.has_method("is_mini_boosting") and (bool(target.is_docked) or bool(target._is_destroyed)): continue
var shield := target.get_node_or_null("ShieldVisual") as Node2D
if shield == null: continue
var radius := float(shield.shield_radius)*shield.global_transform.x.length()
var offset := start-shield.global_position
var b := offset.dot(segment)
var c := offset.length_squared()-radius*radius
var discriminant := b*b-length_squared*c
if discriminant < 0.0: continue
var t := (-b-sqrt(discriminant))/length_squared
if c < 0.0: t = 0.0
if t < 0.0 or t > 1.0: continue
var point := start+segment*t
var candidate := start.distance_squared_to(point)
if candidate < distance:
distance = candidate
nearest = {"position":point,"collider":target,"normal":(point-shield.global_position).normalized(),"shield":true}
return nearest