mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
feat(*): Add a distance-to-ball penalty so idling scores negative, boost ball-seeking rewards, and halve the wall-contact penalty
This commit is contained in:
@@ -15,15 +15,23 @@ extends AIController3D
|
||||
# Reward shaping weights. Dense terms accrue per physics tick (60 sim-ticks
|
||||
# per sim-second); event terms fire once. Exported so tuning needs no code
|
||||
# edits. Goal rewards are added by TrainingMode, which owns goal events.
|
||||
@export var ball_touch_reward := 0.25
|
||||
@export var velocity_to_ball_weight := 0.002
|
||||
@export var ball_touch_reward := 1.0
|
||||
@export var velocity_to_ball_weight := 0.02
|
||||
@export var ball_velocity_to_goal_weight := 0.004
|
||||
# Per-tick penalty scaled by distance to the ball (full value at the arena's
|
||||
# far diagonal, 0 on top of the ball). Run04 lesson: with idling worth a flat
|
||||
# 0, camping in a corner strictly dominated risking the wall/tilt penalties
|
||||
# to chase the ball — this makes "do nothing far from the ball" the worst
|
||||
# option instead of the safest. A penalty, not a proximity bonus, so orbiting
|
||||
# the ball farms nothing.
|
||||
@export var ball_distance_penalty := 0.002
|
||||
# Per-tick penalty while pressed against a side wall, end wall, or the
|
||||
# ceiling — NOT the floor (run03 lesson: taxing floor contact punishes the
|
||||
# ship's natural low flight and drowns every other signal). At 60 ticks per
|
||||
# sim-second this is -0.3/s: parked on a wall for a full 30 s episode loses
|
||||
# ~9 — comparable to conceding — while a brief graze costs almost nothing.
|
||||
@export var wall_contact_penalty := 0.005
|
||||
# sim-second this is -0.15/s. Halved for run05: the ball lives near walls,
|
||||
# and the old -0.3/s made the productive region of the pitch aversive
|
||||
# relative to the (then far weaker) ball-seeking shaping.
|
||||
@export var wall_contact_penalty := 0.0025
|
||||
# Per-tick penalty for not being upright, scaled by tilt: 0 when flat, full
|
||||
# value (-0.12/s) when inverted. A penalty rather than an upright bonus so a
|
||||
# flat, idle ship farms nothing.
|
||||
@@ -33,6 +41,14 @@ extends AIController3D
|
||||
# penalty); below it they read as wall (sideways) or ceiling (downward).
|
||||
const FLOOR_NORMAL_MIN_Y := 0.7
|
||||
|
||||
# Longest possible ship-to-ball separation: the enclosure's interior diagonal.
|
||||
# Normalizes ball_distance_penalty so its export is the worst-case per-tick cost.
|
||||
const MAX_BALL_DISTANCE := sqrt(
|
||||
(2.0 * ArenaBoundary.INNER_HALF_X) ** 2
|
||||
+ (2.0 * ArenaBoundary.INNER_HALF_Z) ** 2
|
||||
+ ArenaBoundary.INNER_HEIGHT ** 2
|
||||
)
|
||||
|
||||
var ship: Ship
|
||||
var rl_controller: RLShipController
|
||||
var ball: RigidBody3D
|
||||
@@ -92,6 +108,11 @@ func _physics_process(delta):
|
||||
var closing_speed := ship.linear_velocity.dot(to_ball.normalized())
|
||||
reward += velocity_to_ball_weight * closing_speed / ship.max_speed
|
||||
|
||||
# Dense penalty: distance to the ball, so idling far away bleeds reward
|
||||
# instead of scoring a safe zero (see ball_distance_penalty).
|
||||
if ball_distance_penalty > 0.0:
|
||||
reward -= ball_distance_penalty * to_ball.length() / MAX_BALL_DISTANCE
|
||||
|
||||
# Dense shaping: ball velocity toward the goal we attack
|
||||
var ball_to_goal := attack_goal_position - ball.global_position
|
||||
if ball_to_goal.length_squared() > 0.0001:
|
||||
|
||||
Reference in New Issue
Block a user