|
|
|
|
# Weapon System Documentation
|
|
|
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
|
|
|
|
|
The weapon system is a modular, multiplayer-friendly system that allows players to:
|
|
|
|
|
- Pick up weapons from the world
|
|
|
|
|
- Equip weapons to their right hand (WeaponPoint bone attachment)
|
|
|
|
|
- Drop equipped weapons
|
|
|
|
|
- Attack with weapon-specific stats (damage, range, cooldown)
|
|
|
|
|
|
|
|
|
|
## Architecture
|
|
|
|
|
|
|
|
|
|
### Core Components
|
|
|
|
|
|
|
|
|
|
1. **WeaponData** (`level/scripts/weapon_data.gd`) - Resource
|
|
|
|
|
- Stores weapon stats: name, damage, attack_range, attack_cooldown
|
|
|
|
|
- References a mesh scene for visuals
|
|
|
|
|
- Reusable across multiple weapon instances
|
|
|
|
|
|
|
|
|
|
2. **BaseWeapon** (`level/scripts/base_weapon.gd`) - Node3D
|
|
|
|
|
- Equipped weapon attached to player's hand
|
|
|
|
|
- Handles attack logic and damage application
|
|
|
|
|
- Networked properly for multiplayer
|
|
|
|
|
|
|
|
|
|
3. **WorldWeapon** (`level/scripts/world_weapon.gd`) - RigidBody3D
|
|
|
|
|
- Physics-based pickup object in the world
|
|
|
|
|
- Can be picked up by players
|
|
|
|
|
- Automatically creates collision and pickup area
|
|
|
|
|
|
|
|
|
|
## Creating New Weapons
|
|
|
|
|
|
|
|
|
|
### Step 1: Create a Mesh Scene
|
|
|
|
|
|
|
|
|
|
Create a scene with your weapon's 3D model:
|
|
|
|
|
```
|
|
|
|
|
[Node3D] - WeaponMesh
|
|
|
|
|
└─ [MeshInstance3D] - Your mesh here
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Example: `level/scenes/weapons/sword_mesh.tscn`
|
|
|
|
|
|
|
|
|
|
### Step 2: Create a WeaponData Resource
|
|
|
|
|
|
|
|
|
|
Create a `.tres` file in `level/resources/`:
|
|
|
|
|
|
|
|
|
|
```tres
|
|
|
|
|
[gd_resource type="Resource" script_class="WeaponData" load_steps=3 format=3]
|
|
|
|
|
|
|
|
|
|
[ext_resource type="Script" path="res://level/scripts/weapon_data.gd" id="1"]
|
|
|
|
|
[ext_resource type="PackedScene" path="res://level/scenes/weapons/your_mesh.tscn" id="2"]
|
|
|
|
|
|
|
|
|
|
[resource]
|
|
|
|
|
script = ExtResource("1")
|
|
|
|
|
weapon_name = "Your Weapon Name"
|
|
|
|
|
description = "Weapon description"
|
|
|
|
|
damage = 15.0
|
|
|
|
|
attack_range = 3.5
|
|
|
|
|
attack_cooldown = 0.6
|
|
|
|
|
attack_animation = "Attack1"
|
|
|
|
|
mesh_scene = ExtResource("2")
|
|
|
|
|
pickup_radius = 1.5
|
|
|
|
|
weight = 2.0
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Step 3: Spawn Weapons in the Level
|
|
|
|
|
|
|
|
|
|
There are two ways to add weapons to your level:
|
|
|
|
|
|
|
|
|
|
#### Option A: Manual Placement (Recommended)
|
|
|
|
|
|
|
|
|
|
1. Open your level scene (e.g., `level/scenes/level.tscn`)
|
|
|
|
|
2. Drag a WorldWeapon scene into `WeaponsContainer`:
|
|
|
|
|
- From FileSystem panel: `level/scenes/weapons/world_weapon_sword.tscn`
|
|
|
|
|
- Or: `level/scenes/weapons/world_weapon_shield.tscn`
|
|
|
|
|
- Drop it as a child of `WeaponsContainer`
|
|
|
|
|
3. Position the weapon in 3D space where you want it to spawn
|
|
|
|
|
4. Save the scene
|
|
|
|
|
|
|
|
|
|
**How it works:**
|
|
|
|
|
- The server automatically detects manually placed WorldWeapon nodes on startup
|
|
|
|
|
- Each weapon is assigned a unique ID and tracked for multiplayer
|
|
|
|
|
- Clients automatically receive synced copies via RPC
|
|
|
|
|
- No code changes needed - just drag and drop!
|
|
|
|
|
|
|
|
|
|
#### Option B: Dynamic Spawning
|
|
|
|
|
|
|
|
|
|
Spawn weapons via code in `level.gd`:
|
|
|
|
|
|
|
|
|
|
```gdscript
|
|
|
|
|
# In _spawn_initial_weapons() or wherever you need
|
|
|
|
|
_weapon_spawn_counter += 1
|
|
|
|
|
rpc("spawn_world_weapon",
|
|
|
|
|
"res://level/resources/weapon_sword.tres",
|
|
|
|
|
Vector3(5, 1, 0), # spawn position
|
|
|
|
|
Vector3.ZERO, # initial velocity
|
|
|
|
|
_weapon_spawn_counter
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is useful for:
|
|
|
|
|
- Spawning weapons at runtime
|
|
|
|
|
- Procedural weapon placement
|
|
|
|
|
- Loot drops from enemies
|
|
|
|
|
|
|
|
|
|
## Testing
|
|
|
|
|
|
|
|
|
|
### In Godot Editor
|
|
|
|
|
|
|
|
|
|
1. Open `level/scenes/level.tscn`
|
|
|
|
|
2. Add a manually placed weapon (see Option A above) or modify `_spawn_initial_weapons()` in `level.gd`
|
|
|
|
|
3. Run the game (F5)
|
|
|
|
|
4. Walk near the weapon and press **E** to pick it up
|
|
|
|
|
|
|
|
|
|
### Controls
|
|
|
|
|
|
|
|
|
|
- **E** - Pick up weapon (when near one) or drop equipped weapon
|
|
|
|
|
- **Left Mouse** - Attack with equipped weapon (or unarmed if none)
|
|
|
|
|
|
|
|
|
|
### Multiplayer Testing
|
|
|
|
|
|
|
|
|
|
1. Run the game and click "Host"
|
|
|
|
|
2. Run another instance and click "Join"
|
|
|
|
|
3. Both players can:
|
|
|
|
|
- Pick up weapons
|
|
|
|
|
- Attack each other with weapons
|
|
|
|
|
- Drop weapons (creates a WorldWeapon others can pick up)
|
|
|
|
|
|
|
|
|
|
## How It Works
|
|
|
|
|
|
|
|
|
|
### Pickup Flow
|
|
|
|
|
|
|
|
|
|
1. WorldWeapon creates an Area3D with pickup radius
|
|
|
|
|
2. Player has a WeaponPickupArea that detects nearby WorldWeapons
|
|
|
|
|
3. When player presses "E" near a weapon:
|
|
|
|
|
- Client calls `try_pickup()` via RPC to server
|
|
|
|
|
- Server validates distance and availability
|
|
|
|
|
- Server tells player to `equip_weapon_from_world()`
|
|
|
|
|
- Server removes the WorldWeapon from scene
|
|
|
|
|
- All clients see the weapon disappear and equipped on player
|
|
|
|
|
|
|
|
|
|
### Attack Flow
|
|
|
|
|
|
|
|
|
|
1. Player presses attack button
|
|
|
|
|
2. Player checks if `equipped_weapon` exists
|
|
|
|
|
3. If yes, calls `equipped_weapon.perform_attack()`
|
|
|
|
|
4. Weapon checks cooldown and attack range
|
|
|
|
|
5. Weapon finds targets using physics query
|
|
|
|
|
6. Weapon sends damage request to server
|
|
|
|
|
7. Server validates and applies damage via BaseUnit system
|
|
|
|
|
|
|
|
|
|
### Drop Flow
|
|
|
|
|
|
|
|
|
|
1. Player presses "E" while holding a weapon
|
|
|
|
|
2. Player calls `drop_weapon()` RPC
|
|
|
|
|
3. Server spawns a WorldWeapon at player's position
|
|
|
|
|
4. All clients see weapon unequip and appear in world
|
|
|
|
|
5. Weapon becomes a physics object that can be picked up
|
|
|
|
|
|
|
|
|
|
## Physics Layers
|
|
|
|
|
|
|
|
|
|
- **Layer 1** (player) - Player collisions
|
|
|
|
|
- **Layer 2** (world) - Environment collisions
|
|
|
|
|
- **Layer 3** (weapon) - Weapon pickup objects
|
|
|
|
|
|
|
|
|
|
WorldWeapons:
|
|
|
|
|
- `collision_layer = 4` (layer 3)
|
|
|
|
|
- `collision_mask = 2` (collides with world)
|
|
|
|
|
|
|
|
|
|
Player WeaponPickupArea:
|
|
|
|
|
- `collision_mask = 4` (detects layer 3)
|
|
|
|
|
|
|
|
|
|
## Example Weapons
|
|
|
|
|
|
|
|
|
|
### Iron Sword
|
|
|
|
|
- **Damage**: 15
|
|
|
|
|
- **Range**: 3.5m
|
|
|
|
|
- **Cooldown**: 0.6s
|
|
|
|
|
- **Resource**: `level/resources/weapon_sword.tres`
|
|
|
|
|
|
|
|
|
|
### Wooden Shield
|
|
|
|
|
- **Damage**: 8
|
|
|
|
|
- **Range**: 2.5m
|
|
|
|
|
- **Cooldown**: 0.8s
|
|
|
|
|
- **Resource**: `level/resources/weapon_shield.tres`
|
|
|
|
|
|
|
|
|
|
## Notes
|
|
|
|
|
|
|
|
|
|
- All weapon spawning/pickup is server-authoritative
|
|
|
|
|
- Weapon stats are synced via WeaponData resource
|
|
|
|
|
- Meshes are instantiated locally on each client
|
|
|
|
|
- The system supports any number of weapon types
|
|
|
|
|
- You can extend BaseWeapon for special weapon behaviors (e.g., ranged weapons, magic weapons)
|