Files
CosmicClash/Game/objects/ship.tscn
T
Josh Creek ea756bd5ba fix(physics): make upright a real state, and actually start ships on the floor
Six rounds of reward shaping (~700M steps) failed to produce upright ground
driving. A critical review of the simulation rather than the reward found
why:

1. The hull was a 1x1x4 box with inertia (1,1,1) and no restoring torque
   anywhere, so belly-down and rolled-90 were geometrically identical
   resting states. "Upright" was not a physically distinguished state at
   all - the reward was paying for a property the simulation did not have.
2. ~65% of episodes spawned ships via _random_position, which samples Y
   uniformly over the full 18m volume (mean ~8.7m). The measured
   airborne_fraction ~0.44 was largely that spawn distribution, and every
   ground-handling term fades out above 3m, so the shaping being tuned
   barely ever applied.
3. air_drill_chance 0.20 spawned deliberately unreachable-without-climbing
   states in the stage meant to teach ground driving, and its own
   air_touch_fraction (0.0002) shows the drills were never solved.

Fixes land in the physics and the task distribution, not the reward:
- ship.tscn: hull 1x1x4 -> 1.6x0.6x4 so it has one stable resting face;
  inertia (1,1,1) -> (7,1,7), physically correct for the hull, making
  tumbling reluctant while keeping yaw snappy.
- ship.gd: new altitude-faded righting torque (spring-damper toward
  belly-down, faded out by 3m so aerials keep full attitude freedom).
  This is the grav-plating analogue of Rocket League's auto-righting and
  helps human pilots land cleanly too.
- training_mode.gd: new ground_start_chance branch spawning ships level and
  resting on the floor with a floor-level ball - the state the handling
  stage's rewards are actually written for.
- generation5.py: ground-start-chance 0.50, air-drill-chance 0.20 -> 0.0.

Reward terms are left exactly as they were; they should finally pull in a
direction the ship can go.
2026-08-16 08:17:16 +01:00

32 lines
1.1 KiB
Plaintext

[gd_scene load_steps=13 format=3 uid="uid://p07epxnh8wwp"]
[ext_resource type="Script" uid="uid://dyq1n7q1bqjps" path="res://scripts/ship.gd" id="1_efag7"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_nose.res" id="3_nose"]
[ext_resource type="ArrayMesh" path="res://assets/models/ship_tailfin.res" id="5_talfin"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_ship"]
friction = 0.1
bounce = 0.15
[sub_resource type="BoxShape3D" id="BoxShape3D_dsjou"]
size = Vector3(1.6, 0.6, 4)
[node name="Ship" type="RigidBody3D"]
collision_layer = 1
collision_mask = 7
mass = 5.0
physics_material_override = SubResource("PhysicsMaterial_ship")
inertia = Vector3(7, 1, 7)
script = ExtResource("1_efag7")
[node name="Nose" type="MeshInstance3D" parent="."]
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0)
mesh = ExtResource("3_nose")
[node name="TailFin" type="MeshInstance3D" parent="."]
transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.24, 0.72)
mesh = ExtResource("5_talfin")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_dsjou")