From c75e142c8ae722a13af8de9b90b2c92ce25cd806 Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:32:54 +0100 Subject: [PATCH] perf(physics): name and assign collision layers Adds a [layer_names] section to project.godot (Ships/Ball/Arena/ GoalSensor) and sets collision_layer/collision_mask on the 4 physics body roots (Ship, Ball, Goal Area3D, ArenaBoundary StaticBody3D), which previously all sat on the default layer 1 / mask 1 so every body broadphase-tested against every other. Ships collide with ships/ball/arena but no longer test against the goal sensor; the goal's mask (Ball only) is the physics-level fix for what goal.gd's is_in_group("ball") check was doing defensively in code (left in place, now a no-op guard). ArenaBoundary's runtime- generated CollisionShape3D children inherit layer/mask from the StaticBody3D root automatically. Verified live via godot-mcp under Jolt Physics: ship-vs-ship and ship-vs-ball collisions still transfer momentum, the ball still bounces off arena walls, a ball entering a goal still fires goal_scored (score updates / HUD reset), and a ship teleported into a goal recess produces zero overlapping bodies on the goal Area3D (was reachable before, physics-level fix confirmed, not just the code guard). Headless smoke test (free_play.tscn) is clean. --- Game/objects/arena_boundary.tscn | 2 ++ Game/objects/ball.tscn | 2 ++ Game/objects/goal.tscn | 2 ++ Game/objects/ship.tscn | 2 ++ Game/project.godot | 7 +++++++ TODO.md | 1 - 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Game/objects/arena_boundary.tscn b/Game/objects/arena_boundary.tscn index ff6f37ed..c558f475 100644 --- a/Game/objects/arena_boundary.tscn +++ b/Game/objects/arena_boundary.tscn @@ -12,6 +12,8 @@ size = Vector3(1, 13, 38) size = Vector3(26, 13, 1) [node name="ArenaBoundary" type="StaticBody3D"] +collision_layer = 4 +collision_mask = 3 script = ExtResource("1_bndry") [node name="FloorShape" type="CollisionShape3D" parent="."] diff --git a/Game/objects/ball.tscn b/Game/objects/ball.tscn index 5f968f8e..670f27fc 100644 --- a/Game/objects/ball.tscn +++ b/Game/objects/ball.tscn @@ -10,6 +10,8 @@ bounce = 0.5 friction = 0.4 [node name="Ball" type="RigidBody3D" groups=["ball"]] +collision_layer = 2 +collision_mask = 13 mass = 3 physics_material_override = SubResource("PhysicsMaterial_ball") continuous_cd = true diff --git a/Game/objects/goal.tscn b/Game/objects/goal.tscn index bc05606d..e6a187f8 100644 --- a/Game/objects/goal.tscn +++ b/Game/objects/goal.tscn @@ -6,6 +6,8 @@ size = Vector3(3.5, 1.5, 0.1) [node name="Goal" type="Area3D"] +collision_layer = 8 +collision_mask = 2 script = ExtResource("1_v8ikr") [node name="CollisionShape3D" type="CollisionShape3D" parent="."] diff --git a/Game/objects/ship.tscn b/Game/objects/ship.tscn index cd9f4156..2b91b937 100644 --- a/Game/objects/ship.tscn +++ b/Game/objects/ship.tscn @@ -12,6 +12,8 @@ bounce = 0.15 size = Vector3(1, 1, 4) [node name="Ship" type="RigidBody3D"] +collision_layer = 1 +collision_mask = 7 mass = 5.0 physics_material_override = SubResource("PhysicsMaterial_ship") inertia = Vector3(1, 1, 1) diff --git a/Game/project.godot b/Game/project.godot index 0345abd5..587b1eb2 100644 --- a/Game/project.godot +++ b/Game/project.godot @@ -119,6 +119,13 @@ roll_right={ ] } +[layer_names] + +3d_physics/layer_1/name="Ships" +3d_physics/layer_2/name="Ball" +3d_physics/layer_3/name="Arena" +3d_physics/layer_4/name="GoalSensor" + [physics] 3d/physics_engine="Jolt Physics" diff --git a/TODO.md b/TODO.md index 429a809d..f1fd7027 100644 --- a/TODO.md +++ b/TODO.md @@ -25,7 +25,6 @@ Bugs found in an adversarial review. None are gameplay- or physics-affecting, so ## Performance -- [ ] Name collision layers in `project.godot` and assign them — nothing configures `collision_layer`/`collision_mask` today, so every body tests against every other. - [ ] Measure `nebula_dust.gdshader`'s per-fragment depth-texture sample across 500 large soft billboards before adding more particle work. - [ ] Bake `ArenaBoundary`'s ~160 runtime-generated `CollisionShape3D` nodes into the scene. Costs a load hitch on every arena entry and repeats in every parallel headless training env. **Blocked on the trained-bot decision below** — `arena_boundary.gd:235` notes this geometry is what the shipped policies were fitted against, so the bake must be verified byte-identical.