Files

61 lines
2.2 KiB
GDScript
Raw Permalink Normal View History

2026-09-12 11:01:37 +02:00
class_name BotSteering
extends RefCounted
var last_position := Vector3.INF
var stalled := 0.0
var repaths := 0
var life := -1
func needs_repath(p: Fighter, delta: float) -> bool:
if life != p.life:
life = p.life
last_position = p.global_position
stalled = 0
repaths = 0
if p.bot_path.is_empty():
stalled = 0
return false
if p.global_position.distance_to(last_position) > 0.3:
last_position = p.global_position
stalled = 0
repaths = 0
else:
stalled += delta
if stalled < 1.25: return false
stalled = 0
repaths += 1
return true
static func reached(position: Vector3, waypoint: Vector3) -> bool:
# Navigation surfaces sit one voxel above the physical floor. Compare height
# separately so stair landings do not leave an unreachable waypoint forever.
return Vector2(position.x - waypoint.x, position.z - waypoint.z).length() < 0.5 and absf(position.y - waypoint.y) < 0.65
static func clear_direction(p: Fighter, direction: Vector3) -> bool:
var pose := p.global_transform
pose.origin.y += 0.26
return not p.test_move(pose, direction * 0.35)
static func avoid(p: Fighter, desired: Vector3, roster: Array) -> Vector3:
var direction := Vector3(desired.x, 0, desired.z).normalized()
var side := Vector3(-direction.z, 0, direction.x)
var separation := Vector3.ZERO
for other: Fighter in roster:
if other == p or other.hp <= 0 or absf(other.position.y - p.position.y) > 1.2: continue
var offset := p.position - other.position
offset.y = 0
var distance := offset.length()
if distance > 1.8: continue
var away := offset.normalized() if distance > 0.01 else side * (1 if p.peer_id > other.peer_id else -1)
separation += away * maxf(0, 1.3 - distance)
# Both approaching actors keep right; unlike random strafe they do not
# mirror one another into the same gap each frame.
if direction.dot(-away) > 0.2: separation += side * (1.8 - distance)
var candidate := (direction + separation * 1.4).normalized()
if clear_direction(p, candidate): return candidate
if clear_direction(p, direction): return direction
for angle in [0.7, -0.7, 1.3, -1.3]:
var alternative := direction.rotated(Vector3.UP, angle)
if clear_direction(p, alternative): return alternative * 0.65
return Vector3.ZERO