feat(*): Add rounded arena boundaries and reward shaping to curb corner-camping

This commit is contained in:
Josh Creek
2026-07-20 08:20:33 +01:00
parent 6cb5902eb6
commit 3457d4ca84
5 changed files with 376 additions and 13 deletions
+32 -5
View File
@@ -33,6 +33,16 @@ const FIELD_HALF_X := ArenaBoundary.INNER_HALF_X - SPAWN_INSET
const FIELD_HALF_Z := ArenaBoundary.GOAL_LINE_Z - SPAWN_INSET
const FIELD_MIN_Y := 1.5
const FIELD_MAX_Y := ArenaBoundary.INNER_HEIGHT - SPAWN_INSET
# The corner curves reach at most their chord plane |x| + |z| = INNER_HALF_X
# + INNER_HALF_Z - CORNER_RADIUS; spawns keep the same SPAWN_INSET clearance
# from that plane as from the walls (perpendicular distance, hence the
# sqrt(2) when expressed in |x| + |z| terms). The true curve bulges outward
# from the chord, so this is conservative.
const CORNER_LIMIT := ArenaBoundary.INNER_HALF_X + ArenaBoundary.INNER_HALF_Z \
- ArenaBoundary.CORNER_RADIUS - SPAWN_INSET * sqrt(2.0)
# Below this height a tilted ship could reach down into the wall-base
# fillets, so low spawns stay an extra BASE_RADIUS off the walls.
const FILLET_CLEAR_Y := ArenaBoundary.BASE_RADIUS + FIELD_MIN_Y
const MAX_RANDOM_BALL_SPEED := 12.0
const MAX_RANDOM_SHIP_SPEED := 8.0
@@ -224,11 +234,28 @@ func _place_ships_random() -> void:
func _random_position() -> Vector3:
return Vector3(
randf_range(-FIELD_HALF_X, FIELD_HALF_X),
randf_range(FIELD_MIN_Y, FIELD_MAX_Y),
randf_range(-FIELD_HALF_Z, FIELD_HALF_Z)
)
# Resample anything too close to a corner curve or wall-base fillet (see
# CORNER_LIMIT / FILLET_CLEAR_Y); the violating region is a few percent
# of the volume, so 20 attempts effectively never fall through.
var position := Vector3.ZERO
for _attempt in 20:
position = Vector3(
randf_range(-FIELD_HALF_X, FIELD_HALF_X),
randf_range(FIELD_MIN_Y, FIELD_MAX_Y),
randf_range(-FIELD_HALF_Z, FIELD_HALF_Z)
)
if _spawn_position_clear(position):
break
return position
func _spawn_position_clear(position: Vector3) -> bool:
if absf(position.x) + absf(position.z) > CORNER_LIMIT:
return false
if position.y >= FILLET_CLEAR_Y:
return true
return absf(position.x) <= FIELD_HALF_X - ArenaBoundary.BASE_RADIUS \
and absf(position.z) <= FIELD_HALF_Z - ArenaBoundary.BASE_RADIUS
func _random_direction() -> Vector3: