$npx -y skills add thedivergentai/GD-Agentic-Skills --skill godot-genre-shooterExpert blueprint for FPS/TPS shooter games (Call of Duty, Counter-Strike, Apex Legends, Fortnite) covering weapon systems, recoil patterns, hitscan vs projectile, aim assist, multiplayer prediction, and gunplay feel. Use when building competitive shooters, battle royales, or tact
| 1 | ## Godot 4.7 Baseline |
| 2 | |
| 3 | - Expert patterns in this skill target **Godot 4.7+** (stable, 2026-06-18). |
| 4 | - Consult the [Godot 4.7 migration guide](https://docs.godotengine.org/en/4.7/tutorials/migrating/upgrading_to_godot_4.7.html) when upgrading projects from 4.6. |
| 5 | - **NEVER** assume 4.6 defaults (stretch mode, audio area_mask, RichTextLabel percent flags) without checking 4.7 migration notes. |
| 6 | |
| 7 | # Genre: Shooter (FPS/TPS) |
| 8 | |
| 9 | Gunplay feel, responsive combat, and competitive balance define shooters. |
| 10 | |
| 11 | ## Available Scripts |
| 12 | |
| 13 | ### [advanced_weapon_controller.gd](scripts/advanced_weapon_controller.gd) |
| 14 | Expert pattern for recoil, bloom, and dual hitscan/projectile systems with object pooling notes. |
| 15 | |
| 16 | ## Core Loop |
| 17 | |
| 18 | `Engage → Aim → Fire → Kill Confirm → Acquire Next` |
| 19 | |
| 20 | ## NEVER Do (Expert Anti-Patterns) |
| 21 | |
| 22 | ### Gunplay & Hit Registration |
| 23 | - NEVER use `_process()` for hit detection; strictly use **`_physics_process()`** to maintain frame-rate independent accuracy (aiming/firing are physics events). |
| 24 | - NEVER apply recoil solely to the weapon model transform; strictly apply it to **Camera Rotation (kick)** and **Weapon Bloom (spread)**. |
| 25 | - NEVER use `Area3D` overlap for high-speed hit detection; strictly use **`PhysicsDirectSpaceState3D.intersect_ray()`** for 100x better performance. |
| 26 | - NEVER trust the client for hit registration in multiplayer; strictly use **Server-Authoritative** validation using lag compensation (rewinding). |
| 27 | - NEVER synchronize every bullet over the network; strictly use **Client-Side Prediction** for visual tracers and only send the initial "Fire" event. |
| 28 | - NEVER forget to exclude the player's own RID from hitscan raycasts; strictly use **`add_exception()`** to prevent shots colliding with the weapon barrel. |
| 29 | - NEVER use exact floating-point equality (==) for bullet damage or health; strictly use **`is_equal_approx()`** to mitigate precision loss. |
| 30 | |
| 31 | ### Performance & Architecture |
| 32 | - NEVER hardcode weapon statistics (Damage, Recoil) inside logic; strictly use **Resource-based WeaponData** for rapid balancing. |
| 33 | - NEVER use a single `AudioStreamPlayer` for gunfire; strictly use **Layered Audio** (Mechanical + Shot + Reverb Tail) for punchy feedback. |
| 34 | - NEVER instantiate and `free()` hundreds of projectile nodes; strictly use **Object Pooling** or the `PhysicsServer3D` API for stability. |
| 35 | - NEVER use `Sprite3D` for bullet impacts on surfaces; strictly use the **Decal** node for conforming, perspective-correct projection. |
| 36 | - NEVER use absolute pixel positioning for crosshairs; strictly rely on **Anchors & RectCenter** to ensure accuracy across resolutions. |
| 37 | - NEVER scale `CollisionShape3D` non-uniformly; strictly scale the **Internal Shape Resource** to maintain valid physics calculations. |
| 38 | - NEVER use TCP for multiplayer shooter synchronization; strictly use **ENet (UDP)** with unreliable transfer modes to avoid latency spikes. |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## 🛠 Expert Components (scripts/) |
| 43 | |
| 44 | ### Original Expert Patterns |
| 45 | - [advanced_weapon_controller.gd](scripts/advanced_weapon_controller.gd) - Professional-grade weapon system with deterministic recoil, bloom, and dual firing modes. |
| 46 | |
| 47 | ### Modular Components |
| 48 | - [shooter_patterns.gd](scripts/shooter_patterns.gd) - Reusable patterns: Server-bypassing hitscan, random spread, and ShapeCast3D explosions. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## Weapon System Architecture |
| 53 | |
| 54 | ```gdscript |
| 55 | class_name Weapon |
| 56 | extends Node3D |
| 57 | |
| 58 | @export_group("Stats") |
| 59 | @export var damage: int = 20 |
| 60 | @export var fire_rate: float = 0.1 # Seconds between shots |
| 61 | @export var magazine_size: int = 30 |
| 62 | @export var reload_time: float = 2.0 |
| 63 | @export var range: float = 100.0 |
| 64 | |
| 65 | @export_group("Recoil") |
| 66 | @export var base_recoil: Vector2 = Vector2(0.5, 2.0) # X, Y degrees |
| 67 | @export var recoil_recovery_speed: float = 5.0 |
| 68 | @export var max_spread: float = 5.0 |
| 69 | |
| 70 | @export_group("Type") |
| 71 | @export var is_hitscan: bool = true |
| 72 | @export var projectile_scene: PackedScene |
| 73 | |
| 74 | var current_ammo: int |
| 75 | var can_fire: bool = true |
| 76 | var current_recoil: Vector2 = Vector2.ZERO |
| 77 | var current_spread: float = 0.0 |
| 78 | |
| 79 | signal fired |
| 80 | signal reloaded |
| 81 | signal ammo_changed(current: int, max: int) |
| 82 | ``` |
| 83 | |
| 84 | --- |
| 85 | |
| 86 | ## Hitscan vs Projectile |
| 87 | |
| 88 | ### Hitscan (Instant Hit) |
| 89 | |
| 90 | ```gdscript |
| 91 | func fire_hitscan() -> void: |
| 92 | if not can_fire or current_ammo <= 0: |
| 93 | return |
| 94 | |
| 95 | current_ammo -= 1 |
| 96 | ammo_changed.emit(current_ammo, magazine_size) |
| 97 | |
| 98 | var camera := get_viewport().get_camera_3d() |
| 99 | var ray_origin := camera.global_position |
| 100 | var ray_direction := -camera.global_basis.z |
| 101 | |
| 102 | # Apply spread |
| 103 | ray_direction = apply_spread(ray_direction) |
| 104 | |
| 105 | var |