Port of JavaScript/Three.js interior physics proxy system to Godot 4.5 with GDScript.
This system allows players to move inside vehicles and vehicle containers with stable physics while the exterior rotates and moves. It uses separate physics spaces:
- World Physics: Main space physics (vehicles, containers moving/rotating in space)
- Proxy Interior Physics: Stable interior physics with gravity (player movement inside)
- Dock Proxy Physics: Separate space for vehicles docked inside containers
-
PhysicsProxy (
physics_proxy.gd)- Manages three separate physics spaces
- Handles gravity toggling for artificial gravity/magnetism
-
Vehicle (
vehicle.gd)- Exterior RigidBody3D in world/dock space
- Interior visual geometry (kinematic, visual only)
- Static colliders in proxy interior space for player physics
- Dock proxy body for when docked inside container
-
VehicleContainer (
vehicle_container.gd)- Large structure with docking bay
- Exterior physics body in world
- Proxy interior colliders for player
- Dock proxy colliders for vehicle physics when docked
-
CharacterController (
character_controller.gd)- Dual physics bodies (world + proxy)
- Switches between physics spaces seamlessly
- Handles movement in both spaces
-
FPSCamera (
fps_camera.gd)- First-person camera with mouse look
- Properly composes rotations (vehicle rotation + mouse look)
- Transforms proxy positions to world space
-
GameManager (
game_manager.gd)- Main controller
- Handles input, transitions, and state management
The player never collides with the actual vehicle/container interior. Instead:
- Vehicle/container interiors are visual only (kinematic)
- Static colliders exist in a separate "proxy" physics space
- Player physics body exists in this proxy space
- Player position is transformed from proxy space to world space for rendering
This means:
- Player experiences stable gravity and physics
- Vehicle/container can rotate freely without affecting player physics
- No jittering or instability from rotating collision shapes
Vehicles inside containers use a nested proxy:
- Container exterior in world physics
- Vehicle exterior can be in:
- World physics (when flying free)
- Dock proxy physics (when docked inside container)
- Player is always in proxy interior physics
- Positions are transformed through multiple spaces as needed
- WASD: Character movement
- Space: Jump
- Mouse: Look around
- Arrow Keys: Vehicle pitch/yaw
- Q/E: Vehicle roll
- M: Vehicle thrust forward
- N: Vehicle thrust backward
- U/J: Container thrust (when docked or inside)
- H/K: Container yaw (when docked or inside)
- B: Toggle magnetism/artificial gravity (when docked)
- ESC: Toggle mouse capture
- Create a new 3D scene in Godot 4.5
- Add a Node3D as root
- Attach
game_manager.gdto root - Run the scene
The system will automatically create:
- Physics proxy manager
- Vehicle at origin
- VehicleContainer at (100, 0, 0)
- Character inside vehicle
- FPS camera
- Starfield and lighting
- Default Godot physics space
- No gravity (space)
- Contains vehicle and container exterior bodies
- Created via PhysicsServer3D
- Has gravity (-9.81 Y) by default
- Can be toggled for magnetism
- Contains static floor/wall colliders
- Contains character physics body
- Created via PhysicsServer3D
- No gravity (space-like)
- Contains dock bay colliders
- Contains vehicle body when docked
- Character walks through transition zone at container entrance
- Switches from
vehicle_interiortocontainer_interior - Stays in proxy physics space
- Camera transforms update to use container rotation
- Vehicle enters container transition zone
- Vehicle physics transfers from world to dock proxy
- Vehicle can now collide with dock bay walls/floor
- Player can toggle magnetism (artificial gravity)
- Walking out of transition zones reverses the process
- Physics bodies seamlessly switch spaces
- State is preserved during transitions
This implementation uses PhysicsServer3D directly for:
- Creating custom physics spaces
- Manual rigid body creation in custom spaces
- Low-level control over gravity per space
This is necessary because Godot's high-level physics nodes (RigidBody3D, etc.) are tied to the default world space.
Camera rotation in interiors uses proper composition:
# Vehicle/Container basis * Local mouse look basis
global_transform.basis = vehicle_basis * mouse_look_basisThis ensures:
- Mouse look works in local coordinates
- Yaw rotates around the vehicle's "up" direction
- No gimbal lock or unexpected behavior
Character visual position is updated in _process:
# Transform from proxy space to world space
world_pos = vehicle_pos + vehicle_basis * proxy_pos- Physics Engine: RAPIER → Godot Physics (PhysicsServer3D)
- Scene Graph: THREE.js → Godot Node tree
- Rendering: WebGL → Godot renderer
- State Management: Svelte runes → GDScript class variables
- Input: DOM events → Godot Input system
- Add smooth state transfer during docking
- Implement proper collision layers/masks
- Add EVA (spacewalk) mechanics
- Multiple vehicles and containers
- Networking/multiplayer support
- Save/load system for physics state
- Performance optimizations for large scales
- Original JavaScript implementation:
Game.svelte - Godot Physics Server docs: https://docs.godotengine.org/en/stable/classes/class_physicsserver3d.html