mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
feat(training): support N-vs-M matches with persistent per-ship spawn IDs
Extends ShipObservations beyond the old self+1-opponent layout to padded teammate/opponent arrays (MAX_TEAMMATES=4, MAX_OPPONENTS=5, SIZE=83), zero-filling slots past the real roster size the same way the old single- opponent slot was zero-filled when absent. Slot stability across ticks requires a persistent identity: Ship gains spawn_index (set once by GameMode.spawn_ship, never reassigned — there's no despawn path anywhere in this codebase, so a roster is fixed for the whole episode/match). ai_ship_controller.gd's opponent discovery is rewritten from "first non-self ship" to classify every other ship by team and sort by spawn_index; training_mode.gd/ship_ai_controller.gd carry the equivalent sorted lists through the training path so both agree on slot assignment for the same roster. training_mode.gd and match_mode.gd both gain a team_size export (default 1, so every existing curriculum script and match keeps today's 1v1 behaviour unchanged). This is plumbing only: no 2v2+ curriculum or reward design, and no match-mode UI to pick team size, has been done yet. The two checkpoints in Game/bots/promoted/ are fitted to the old 35-float layout and are not migrated — expected to go stale until the next training run.
This commit is contained in:
@@ -106,7 +106,8 @@ const MAX_BALL_DISTANCE := sqrt(
|
||||
var ship: Ship
|
||||
var rl_controller: RLShipController
|
||||
var ball: RigidBody3D
|
||||
var opponent: Ship
|
||||
var teammates: Array[Ship] = []
|
||||
var opponents: Array[Ship] = []
|
||||
var attack_goal_position: Vector3
|
||||
|
||||
# Set directly by TrainingMode (_on_goal_scored / the timeout branch in
|
||||
@@ -146,12 +147,16 @@ var _air_touches := 0
|
||||
|
||||
|
||||
# Wire up references after the ship is spawned. `attack_goal` is the goal
|
||||
# this ship scores into (goal.team == opponent's team).
|
||||
func setup(p_ship: Ship, p_rl_controller: RLShipController, p_ball: RigidBody3D, p_opponent: Ship, p_attack_goal_position: Vector3) -> void:
|
||||
# this ship scores into (goal.team == the opposing team's team).
|
||||
func setup(
|
||||
p_ship: Ship, p_rl_controller: RLShipController, p_ball: RigidBody3D,
|
||||
p_teammates: Array[Ship], p_opponents: Array[Ship], p_attack_goal_position: Vector3
|
||||
) -> void:
|
||||
ship = p_ship
|
||||
rl_controller = p_rl_controller
|
||||
ball = p_ball
|
||||
opponent = p_opponent
|
||||
teammates = p_teammates
|
||||
opponents = p_opponents
|
||||
attack_goal_position = p_attack_goal_position
|
||||
init(ship)
|
||||
|
||||
@@ -161,7 +166,7 @@ func setup(p_ship: Ship, p_rl_controller: RLShipController, p_ball: RigidBody3D,
|
||||
|
||||
|
||||
func get_obs() -> Dictionary:
|
||||
return {"obs": ShipObservations.build(ship, opponent, ball, attack_goal_position)}
|
||||
return {"obs": ShipObservations.build(ship, teammates, opponents, ball, attack_goal_position)}
|
||||
|
||||
|
||||
func get_reward() -> float:
|
||||
|
||||
Reference in New Issue
Block a user