35 lines
1.6 KiB
GDScript
35 lines
1.6 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.hull)<=0.0: continue
|
|
if target.has_method("is_mini_boosting") and (bool(target.is_docked) or bool(target._is_destroyed)): continue
|
|
var shield: Node2D
|
|
if target.has_method("get_active_shield_visual"):
|
|
shield = target.get_active_shield_visual()
|
|
elif float(target.shields) > 0.0:
|
|
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
|