Files
tactical-shooter/client/characters/README.md
T
shawn e9dc05983c 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
2026-07-01 18:30:44 -04:00

120 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.10.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