Save workspace artifacts: character-controller, gdextension scaffold, network scripts, map-pipeline, server config
Includes code from task workspaces that was never pushed: - client/characters/ — fps_character_controller.gd (400 lines), fps_camera.gd, input_handler.gd - gdextension/simulation/ — C++ GDExtension scaffold: entity, movement, hit detection, simulation server, state serializer, bitstream (14 files) - scripts/network/ — ENet-based network_manager.gd, server/client_main.gd, player.gd - scripts/map_packaging/ — PCK pipeline: pack_map.gd, map_downloader.gd, map_registry_server.py, README - scripts/config/ — server_config.gd (480 lines) - scenes/ — client_main, server_main, player, test_range - project.godot, export_presets.cfg
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# FPS Character Controller — Tactical Shooter
|
||||
|
||||
First-person character controller for the tactical shooter GDExtension simulation core.
|
||||
|
||||
## Architecture
|
||||
|
||||
The character controller is a **GDScript bridge** between Godot's input/physics system and the C++ `SimulationServer` (built in task `t_aca0f251`).
|
||||
|
||||
```
|
||||
Godot Input
|
||||
│
|
||||
├─► FPSCharacterController._physics_process()
|
||||
│ ├─ capture input (WASD, mouse, jump, sprint, crouch, shoot)
|
||||
│ ├─ build EntityInput Dictionary
|
||||
│ ├─ SimulationServer.apply_input(entity_id, input_dict)
|
||||
│ ├─ SimulationServer.fire_weapon(entity_id) [if shoot]
|
||||
│ ├─ read entity position from server → apply to CharacterBody3D
|
||||
│ └─ apply mouse look (yaw on body, pitch on camera)
|
||||
│
|
||||
├─► FpsCamera._process()
|
||||
│ ├─ view bobbing (head bob from movement)
|
||||
│ ├─ weapon sway
|
||||
│ └─ sprint FOV kick
|
||||
│
|
||||
└─► SimulationServer (C++ GDExtension)
|
||||
├─ process_tick() @ 128Hz
|
||||
├─ MovementComponent.update()
|
||||
├─ HitDetection.process_shot()
|
||||
└─→ returns serialized snapshot
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `character/fps_character_controller.gd` | Main controller (CharacterBody3D). Input capture, simulation bridge, walk toggle, crouch, jump. |
|
||||
| `character/fps_camera.gd` | First-person camera (Camera3D). Mouse look pitch, view bobbing, weapon sway, FOV kick. |
|
||||
| `input/input_handler.gd` | Documentation of expected input map bindings. |
|
||||
|
||||
## Scene Setup
|
||||
|
||||
1. **Create a CharacterBody3D scene:**
|
||||
```
|
||||
FPSCharacterController (CharacterBody3D) — script: fps_character_controller.gd
|
||||
├── FpsCamera (Camera3D) — script: fps_camera.gd
|
||||
├── CollisionShape3D (CapsuleShape3D) — radius: 0.4, height: 1.8
|
||||
└── Weapon (Node3D, optional) — child of camera, rest transform tracked
|
||||
```
|
||||
|
||||
2. **Configure exports** on the root node:
|
||||
- `mouse_sensitivity`: 0.1–0.2 for typical tactical feel
|
||||
- `walk_toggle`: `true` = tap Shift to toggle sprint (CS-style)
|
||||
- `crouch_toggle`: `false` = hold Ctrl to crouch (tactical-style)
|
||||
- `eye_height_stand` / `eye_height_crouch`: match your capsule height
|
||||
|
||||
3. **Set up Input Map** in Project Settings:
|
||||
- `move_forward` → W
|
||||
- `move_backward` → S
|
||||
- `move_left` → A
|
||||
- `move_right` → D
|
||||
- `jump` → Space
|
||||
- `sprint` → Shift
|
||||
- `crouch` → Ctrl
|
||||
- `shoot` → Mouse LMB
|
||||
- `aim` → Mouse RMB
|
||||
- `ui_cancel` → Esc (built-in, releases mouse capture)
|
||||
|
||||
4. **Integration with SimulationServer:**
|
||||
|
||||
```gdscript
|
||||
# In your game manager (autoload or scene root):
|
||||
var server = SimulationServer.new()
|
||||
server.set_tick_rate(128)
|
||||
server.start()
|
||||
var player_id = server.spawn_entity(Vector3(0, 0, 0))
|
||||
|
||||
# When player scene is ready:
|
||||
$Player/FPSCharacterController.set_entity_id(player_id)
|
||||
|
||||
# In _process(delta):
|
||||
while server.can_tick(delta):
|
||||
var snapshot = server.tick()
|
||||
# send snapshot to network layer
|
||||
```
|
||||
|
||||
## Walk Toggle Behavior
|
||||
|
||||
- **`walk_toggle = true`** (default): Press Shift to toggle between walk and sprint. Press again to toggle off. Same feel as Counter-Strike's walk/run toggle.
|
||||
- **`walk_toggle = false`**: Hold Shift for temporary sprint. Release to decelerate to walk speed.
|
||||
|
||||
## Crouch Behavior
|
||||
|
||||
- **`crouch_toggle = false`** (default): Hold Ctrl to crouch. Release to stand up.
|
||||
- **`crouch_toggle = true`**: Press Ctrl once to crouch, press again to stand.
|
||||
|
||||
Crouch transitions are smooth lerps over `crouch_transition_time` seconds. The collision capsule height and camera eye height both lerp simultaneously.
|
||||
|
||||
## Standalone Mode
|
||||
|
||||
When no `SimulationServer` singleton is available, the controller falls back to built-in `CharacterBody3D` movement (`_move_local()`). This is useful for:
|
||||
- Testing the character controller in isolation
|
||||
- Prototyping without the GDExtension compiled
|
||||
- Single-player scenarios without the full simulation stack
|
||||
|
||||
Configure `local_walk_speed`, `local_sprint_speed`, `local_crouch_speed`, etc. for standalone tuning.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Godot 4.2+** (for `Input.get_vector`, `move_toward`, `StringName` literals)
|
||||
- **SimulationServer GDExtension** (from task `t_aca0f251`) for server-authoritative mode
|
||||
- Input map actions listed above
|
||||
|
||||
## See Also
|
||||
|
||||
- Scaffold: `t_aca0f251` — `src/movement_component.h` (C++ Quake/CS movement physics)
|
||||
- Greybox map: `t_p1_greybox` — test environment for this controller
|
||||
- Hitscan weapon: `t_p1_hitscan` — weapon firing + lag compensation
|
||||
- Client prediction: `t_p1_pred` — client-side prediction + server reconciliation
|
||||
- Round system: `t_p1_round` — win/loss/sudden death on top of character controller
|
||||
Reference in New Issue
Block a user