using Godot; public partial class PhysicsSpike : Node3D { private RigidBody3D _ball; private RigidBody3D _chaser; private Node3D _chaseTarget; private float _elapsed; private bool _ballTouched; public override void _Ready() { StaticBody3D floor = new() { Position = new Vector3(0, -0.5f, 0) }; floor.AddChild(new CollisionShape3D { Shape = new BoxShape3D { Size = new Vector3(20, 1, 20) } }); AddChild(floor); _ball = new RigidBody3D { Position = new Vector3(0, 2, 0), ContactMonitor = true, MaxContactsReported = 4 }; _ball.AddChild(new CollisionShape3D { Shape = new SphereShape3D { Radius = 0.25f } }); _ball.BodyEntered += _ => _ballTouched = true; AddChild(_ball); StaticBody3D wall = new() { Position = new Vector3(5, 2, 0) }; wall.AddChild(new CollisionShape3D { Shape = new BoxShape3D { Size = new Vector3(0.5f, 4, 4) } }); AddChild(wall); _chaser = new RigidBody3D { Position = new Vector3(0, 1, 0), GravityScale = 0f }; _chaser.AddChild(new CollisionShape3D { Shape = new SphereShape3D { Radius = 0.25f } }); AddChild(_chaser); _chaseTarget = new Node3D(); AddChild(_chaseTarget); GD.Print("SPIKE: physics spike scene ready"); } public override void _PhysicsProcess(double delta) { _elapsed += (float)delta; _chaseTarget.GlobalPosition = new Vector3(Mathf.Min(8f, _elapsed * 2f), 1, 0); Vector3 to = _chaseTarget.GlobalPosition - _chaser.GlobalPosition; Vector3 desired = to / (float)delta; if (desired.Length() > 3f) desired = desired.Normalized() * 3f; _chaser.LinearVelocity = desired; if (_elapsed < 2.5f) return; bool dropOk = _ballTouched && _ball.GlobalPosition.Y > 0.2f && _ball.GlobalPosition.Y < 0.35f; bool chaseOk = _chaser.GlobalPosition.X > 4.4f && _chaser.GlobalPosition.X < 5.05f; GD.Print($"SPIKE: drop test — ball y={_ball.GlobalPosition.Y:F3} (expected ~0.25), contact={_ballTouched} → {(dropOk ? "PASS" : "FAIL")}"); GD.Print($"SPIKE: chase test — chaser x={_chaser.GlobalPosition.X:F3} (wall face 4.75, body radius 0.25), vel={_chaser.LinearVelocity.Length():F2} → {(chaseOk ? "PASS" : "FAIL")}"); GD.Print($"SPIKE: overall {(dropOk && chaseOk ? "PASS — Box3D functional from C#" : "CHECK — behavior differs, inspect above")}"); GetTree().Quit(); } }