Skip to content

Implement SprayPattern node for weapon recoil and spray behaviors#182

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-157afc4d-ddb8-4e55-9cbe-1ee1f50d54f7
Draft

Implement SprayPattern node for weapon recoil and spray behaviors#182
Copilot wants to merge 3 commits intomainfrom
copilot/fix-157afc4d-ddb8-4e55-9cbe-1ee1f50d54f7

Conversation

Copy link
Contributor

Copilot AI commented Sep 29, 2025

This PR implements the SprayPattern node, a reusable and customizable Godot 4.5 node that defines and manages recoil and spray behaviors for firearms. The node integrates seamlessly with the existing weapon system while maintaining modularity and backward compatibility.

Features

The SprayPattern node provides comprehensive spray pattern functionality:

  • Curve2D-based patterns: Define spray curves where x-axis represents shot sequence and y-axis represents recoil offset
  • Stateful tracking: Maintains current shot index and accumulated recoil offset
  • Configurable randomness: Separate pitch and yaw randomness for realistic spray variation
  • Automatic recovery: View gradually recenters when not shooting with configurable speed
  • Time-based reset: Pattern automatically resets after configurable cooldown period
  • Loop support: Patterns can loop indefinitely or stop at the end

Properties

All properties from the original feature request are implemented:

@export var base_curve: Curve2D           # Spray pattern definition
@export var recovery_speed: float = 5.0   # View recentering speed
@export var apply_speed: float = 10.0     # Recoil application speed
@export var randomness_pitch: float = 0.1 # Vertical randomness
@export var randomness_yaw: float = 0.1   # Horizontal randomness
@export var reset_after_ms: int = 500     # Reset cooldown in milliseconds
@export var loop_pattern: bool = false    # Pattern looping behavior

Integration

The node automatically integrates with the existing weapon system:

# Simply add SprayPattern as a child of FirstPersonItem
# It will automatically connect to Magazine discharge events
weapon_item.spray_offset_updated.connect(_apply_recoil_to_camera)

func _apply_recoil_to_camera(offset: Vector2, shot_index: int):
    camera.rotation.x += offset.x * sensitivity
    camera.rotation.y += offset.y * sensitivity

Usage Examples

Different weapon types can be easily configured:

# SMG: Fast, looping pattern with high randomness
spray_pattern.recovery_speed = 8.0
spray_pattern.randomness_pitch = 0.15
spray_pattern.loop_pattern = true

# Assault Rifle: Longer predictable pattern
spray_pattern.recovery_speed = 4.0
spray_pattern.randomness_pitch = 0.05
spray_pattern.loop_pattern = false

# Shotgun: Strong initial kick with high randomness
spray_pattern.apply_speed = 20.0
spray_pattern.randomness_pitch = 0.3
spray_pattern.randomness_yaw = 0.2

Implementation Details

The implementation follows Nodot conventions and maintains minimal impact on existing code:

  • Only 17 lines added to FirstPersonItem.gd for automatic detection and integration
  • No changes to existing Magazine or weapon functionality
  • Backward compatible - existing weapons continue to work unchanged
  • Comprehensive test suite with both unit and integration tests
  • Complete documentation with API reference and usage examples

Files Added

  • addons/nodot/weapons/SprayPattern.gd - Core implementation
  • addons/nodot/weapons/SprayPattern.md - Documentation and examples
  • addons/nodot/icons/spray_pattern.svg - Custom node icon
  • tests/unit/weapons/SprayPattern.test.gd - Unit tests
  • tests/unit/weapons/SprayPatternIntegration.test.gd - Integration tests

The SprayPattern node enables developers to create realistic and varied weapon behaviors that can range from Counter-Strike-like deterministic patterns to arcade-style random recoil, all while ensuring perfect synchronization between visual recoil and bullet trajectory.

Original prompt

This section details on the original issue you should resolve

<issue_title>Spray patterns</issue_title>
<issue_description>

Feature Suggestion: SprayPattern Node for Godot 4.5

Category: FPS / Weapon System Enhancement
Related Nodes: Weapon, Magazine, WeaponManager


Overview

The SprayPattern node is a reusable, customizable Godot 4.5 node that defines and manages recoil and spray behaviors for firearms. It integrates seamlessly with existing Weapon and Magazine nodes, allowing developers to assign deterministic or randomized shooting patterns to weapons. The goal is to provide an easy-to-use and highly flexible system that can mimic recoil curves from realistic shooters, arcade-style upward sprays, or game-specific designs.


Core Functionality

  • Customizable Spray Control:

    • Stores spray curves as Curve2D resources, where the x-axis represents shots fired (heat/sequence), and the y-axis represents positional recoil offset (pitch/yaw).
    • Patterns can be weapon-specific (e.g., P90, AK47) or procedurally generated.
  • Stateful Recoil Tracking:

    • The node tracks "current shot index" or "heat level" to know where in the spray pattern the weapon currently lies.
    • Supports reset behavior when the player stops shooting or after a cooldown period.
  • Randomness:

    • Allows per-weapon adjustable randomness on both pitch and yaw offsets to simulate varied spray control.
    • Supports blending between deterministic patterns and randomized deviation.
  • Synchronization with Weapon Fire:

    • Exposes the calculated offset via signals or getters, so both the:
      1. Player View/Camera
      2. Bullet Direction/Raycast
        can be synchronized to the same recoil effect.

Example Properties

[SprayPattern]
 ├─ base_curve: Curve2D          # The defined spray pattern
 ├─ recovery_speed: float        # Speed at which view recenters
 ├─ apply_speed: float           # Speed of recoil application
 ├─ randomness_pitch: float      # Additive randomness (vertical)
 ├─ randomness_yaw: float        # Additive randomness (horizontal)
 ├─ reset_after_ms: int          # Cooldown before recoil resets
 └─ loop_pattern: bool           # Whether the pattern repeats

Example Signals

  • spray_offset_updated(Vector2 offset, int shot_index)
    Fired every time recoil is applied, sending the offset and shot index.
  • pattern_reset()
    Fired when the spray pattern resets after cooldown.

Example Usage

  1. Node Setup:

    • Attach a SprayPattern node to a Weapon node.
    • Assign a custom Curve2D resource representing the weapon’s recoil pattern.
  2. In WeaponManager:

    • Call spray_pattern.get_next_offset() on every shot.
    • Apply the offset both to:
      • The camera (pitch/yaw adjustments).
      • The bullet raycast direction.
  3. Weapon Variation:

    • SMG: shorter looping patterns with light randomness.
    • Rifle: long deterministic spray curves with high recoil recovery requirement.
    • Shotgun: strong initial upward randomness, little pattern curve.

Benefits

  • Modularity: Keeps recoil and spray system isolated from the weapon logic.
  • Reusability: One node can handle multiple weapons via different curves.
  • Flexibility: Developers can easily import Counter-Strike-like spray charts or create arcade-style upward recoil.
  • Synchrony: Ensures recoil visually matches bullet trajectory.

✅ This SprayPattern node integrates naturally into the existing FPS weapon system and complements the Magazine node by adding depth to shooting mechanics while still allowing flexible, designer-driven control.
</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #165

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits September 29, 2025 13:33
Co-authored-by: krazyjakee <623463+krazyjakee@users.noreply.github.com>
…on tests

Co-authored-by: krazyjakee <623463+krazyjakee@users.noreply.github.com>
Copilot AI changed the title [WIP] Spray patterns Implement SprayPattern node for weapon recoil and spray behaviors Sep 29, 2025
Copilot AI requested a review from krazyjakee September 29, 2025 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spray patterns

2 participants