265 lines
12 KiB
Markdown
265 lines
12 KiB
Markdown
# Универсальная система используемых предметов
|
||
|
||
## Обзор
|
||
|
||
Система построена на принципах наследования и интерфейсов. Любой предмет в руках может реализовывать интерфейс `IUseable` и иметь свою уникальную логику использования.
|
||
|
||
## Архитектура
|
||
|
||
### IUseable
|
||
Интерфейс для всех используемых предметов:
|
||
- `CanUse()` - проверка возможности использования
|
||
- `Use()` - выполнение действия
|
||
- `Cooldown` - время перезарядки между использованиями
|
||
|
||
### BaseWeapon
|
||
Базовый класс для оружия, **наследуется от InventoryItem** и реализует `IUseable`. Содержит:
|
||
- Логику стрельбы и трассировки пуль
|
||
- Управление патронами (магазин + инвентарь)
|
||
- Систему перезарядки
|
||
- Эффекты выстрела и попадания
|
||
- Автоматическую стрельбу
|
||
- **Физику** - автоматическое отключение RigidBody при экипировке
|
||
|
||
### Flashlight
|
||
Пример другого используемого предмета - фонарика. Показывает:
|
||
- Как создавать предметы с собственной логикой
|
||
- Переключение состояний (вкл/выкл)
|
||
- Звуковые эффекты
|
||
|
||
### WeaponFactory
|
||
Универсальная фабрика для создания любых используемых предметов.
|
||
|
||
## Ключевые особенности
|
||
|
||
### 1. Наследование от InventoryItem
|
||
- **BaseWeapon наследуется от InventoryItem** - не нужно вешать 2 компонента на префаб
|
||
- Один компонент = один предмет в инвентаре
|
||
- Автоматическое управление состоянием экипировки
|
||
|
||
### 2. Автоматическая стрельба
|
||
- Оружие стреляет автоматически при удержании кнопки мыши **только если IsAutomatic = true**
|
||
- Для полуавтоматического оружия (IsAutomatic = false) - только одиночные выстрелы
|
||
- **Частота стрельбы берется из WeaponItemDefinition.FireRate**
|
||
|
||
### 3. Система патронов
|
||
- **Оружие начинается с пустым магазином** - патроны нужно зарядить
|
||
- **Сохранение патронов в магазине** - при выбрасывании оружия патроны остаются
|
||
- Патроны хранятся в инвентаре как отдельные предметы
|
||
- **Стрельба зависит ТОЛЬКО от патронов в магазине** - CurrentAmmo
|
||
- **HUD показывает патроны в магазине** - не зависит от инвентаря
|
||
- **Патроны тратятся только из магазина при выстреле** - CurrentAmmo уменьшается
|
||
- **Патроны тратятся из инвентаря только при перезарядке** - загружаются в магазин
|
||
- **Перезарядка только вручную** - кнопка R или автоматически при пустом магазине
|
||
- **Безопасная обработка неполных магазинов** - загружается столько патронов, сколько есть в инвентаре
|
||
|
||
### 4. HUD и UI
|
||
- **Отображение патронов в магазине** (текущие/максимум)
|
||
- **Отображение патронов в инвентаре** (общее количество)
|
||
- **Прогресс перезарядки** в реальном времени
|
||
- Формат: `15/30 (45)` - где 15 в магазине, 30 максимум, 45 всего в инвентаре
|
||
|
||
### 5. Физика
|
||
- **Автоматическое отключение RigidBody при экипировке**
|
||
- **Включение физики при снятии оружия**
|
||
- Предметы не падают когда в руках
|
||
|
||
### 6. Настройка в префабах
|
||
- Не нужно создавать отдельные файлы для каждого оружия
|
||
- Настройка происходит прямо в инстансе префаба
|
||
- Компоненты добавляются автоматически
|
||
|
||
## Практическое использование
|
||
|
||
### 1. Создание оружия в редакторе
|
||
|
||
#### Шаг 1: Создание префаба
|
||
1. Создайте новый GameObject в сцене
|
||
2. Добавьте модель оружия (SkinnedModelRenderer)
|
||
3. Добавьте компонент `BaseWeapon`
|
||
4. Настройте параметры в инспекторе:
|
||
- `GunRenderer` - ссылка на рендерер оружия
|
||
- `MuzzleLight` - свет вспышки
|
||
- `ParticlePrefab` - эффекты попадания
|
||
- `BloodParticle` - эффекты крови
|
||
- `Cooldown` - время между выстрелами
|
||
|
||
#### Шаг 2: Создание WeaponItemDefinition
|
||
1. В Project Settings создайте новый ресурс типа "Weapon Item Definition"
|
||
2. Настройте параметры:
|
||
```
|
||
Name: "Pistol"
|
||
Slot: RightHand
|
||
HoldType: Pistol
|
||
Damage: 25
|
||
FireRate: 8
|
||
Range: 1000
|
||
MagazineSize: 15
|
||
AmmoType: "Pistol"
|
||
ReloadTime: 2.0
|
||
Spread: 0.02
|
||
```
|
||
3. Укажите префаб в поле `Prefab`
|
||
|
||
#### Шаг 3: Добавление в игру
|
||
```csharp
|
||
// В коде игрока или менеджера
|
||
var weaponDef = ResourceLibrary.Get<WeaponItemDefinition>("Items/pistol.weapon");
|
||
var weaponItem = WeaponFactory.CreateWeaponItem(weaponDef);
|
||
player.Inventory.AddItem(weaponItem);
|
||
```
|
||
|
||
### 2. Создание фонарика
|
||
|
||
#### Шаг 1: Создание префаба фонарика
|
||
1. Создайте GameObject с моделью фонарика
|
||
2. Добавьте компонент `Flashlight`
|
||
3. Настройте параметры:
|
||
- `LightSource` - GameObject с источником света
|
||
- `ToggleSound` - звук включения/выключения
|
||
- `Cooldown` - время между переключениями
|
||
|
||
#### Шаг 2: Создание ItemDefinition
|
||
```csharp
|
||
// Создайте BaseItemDefinition или WeaponItemDefinition
|
||
// Name: "Flashlight"
|
||
// Slot: LeftHand
|
||
// Prefab: ссылка на префаб фонарика
|
||
```
|
||
|
||
#### Шаг 3: Использование
|
||
```csharp
|
||
var flashlightDef = ResourceLibrary.Get<BaseItemDefinition>("Items/flashlight.item");
|
||
var flashlightItem = WeaponFactory.CreateItem(flashlightDef);
|
||
player.Inventory.AddItem(flashlightItem);
|
||
```
|
||
|
||
### 3. Создание собственного предмета
|
||
|
||
```csharp
|
||
// Создайте новый класс
|
||
public sealed class Medkit : Component, IUseable
|
||
{
|
||
[Property] public float Cooldown { get; set; } = 5f;
|
||
[Property] public int HealAmount { get; set; } = 50;
|
||
|
||
private TimeSince _lastUseTime;
|
||
|
||
public bool CanUse()
|
||
{
|
||
return IsValid && _lastUseTime >= Cooldown;
|
||
}
|
||
|
||
public void Use()
|
||
{
|
||
if (!CanUse()) return;
|
||
|
||
_lastUseTime = 0;
|
||
|
||
// Логика лечения
|
||
var player = Dedugan.Local;
|
||
if (player != null)
|
||
{
|
||
player.Health = Math.Min(player.Health + HealAmount, 100);
|
||
Log.Info($"Игрок вылечен на {HealAmount} HP");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## WeaponFactory - подробное руководство
|
||
|
||
### Основные методы:
|
||
|
||
#### 1. `CreateUseableItem(BaseItemDefinition, InventoryItem)`
|
||
Создает любой используемый предмет:
|
||
```csharp
|
||
var itemDef = ResourceLibrary.Get<BaseItemDefinition>("path/to/item");
|
||
var item = WeaponFactory.CreateUseableItem(itemDef, inventoryItem);
|
||
```
|
||
|
||
#### 2. `CreateWeapon(WeaponItemDefinition, InventoryItem)`
|
||
Создает оружие (для обратной совместимости):
|
||
```csharp
|
||
var weaponDef = ResourceLibrary.Get<WeaponItemDefinition>("path/to/weapon");
|
||
var weapon = WeaponFactory.CreateWeapon(weaponDef, inventoryItem);
|
||
```
|
||
|
||
#### 3. `CreateItem(BaseItemDefinition)`
|
||
Создает предмет для инвентаря:
|
||
```csharp
|
||
var itemDef = ResourceLibrary.Get<BaseItemDefinition>("path/to/item");
|
||
var inventoryItem = WeaponFactory.CreateItem(itemDef);
|
||
```
|
||
|
||
### Автоматическое определение типа
|
||
|
||
WeaponFactory автоматически определяет тип предмета по имени:
|
||
|
||
- **Оружие**: содержит "pistol", "rifle", "gun" → создается `BaseWeapon`
|
||
- **Фонарик**: содержит "flashlight", "light" → создается `Flashlight`
|
||
- **По умолчанию**: создается `BaseWeapon`
|
||
|
||
### Примеры использования
|
||
|
||
#### Создание пистолета:
|
||
```csharp
|
||
// 1. Создаем предмет для инвентаря
|
||
var pistolDef = ResourceLibrary.Get<WeaponItemDefinition>("Items/pistol.weapon");
|
||
var pistolItem = WeaponFactory.CreateWeaponItem(pistolDef);
|
||
|
||
// 2. Добавляем в инвентарь
|
||
player.Inventory.AddItem(pistolItem);
|
||
|
||
// 3. Экипируем
|
||
player.Inventory.EquipItem(pistolItem);
|
||
```
|
||
|
||
#### Создание фонарика:
|
||
```csharp
|
||
// 1. Создаем предмет
|
||
var flashlightDef = ResourceLibrary.Get<BaseItemDefinition>("Items/flashlight.item");
|
||
var flashlightItem = WeaponFactory.CreateItem(flashlightDef);
|
||
|
||
// 2. Добавляем в инвентарь
|
||
player.Inventory.AddItem(flashlightItem);
|
||
```
|
||
|
||
#### Создание аптечки:
|
||
```csharp
|
||
// 1. Создаем предмет
|
||
var medkitDef = ResourceLibrary.Get<BaseItemDefinition>("Items/medkit.item");
|
||
var medkitItem = WeaponFactory.CreateItem(medkitDef);
|
||
|
||
// 2. Добавляем в инвентарь
|
||
player.Inventory.AddItem(medkitItem);
|
||
```
|
||
|
||
## Настройка в префабах
|
||
|
||
### Для оружия:
|
||
1. Добавьте компонент `BaseWeapon`
|
||
2. Настройте все необходимые ссылки (рендерер, звуки, эффекты)
|
||
3. Установите параметры стрельбы (Cooldown, FireRate и т.д.)
|
||
|
||
### Для других предметов:
|
||
1. Добавьте компонент, реализующий `IUseable`
|
||
2. Настройте специфичные параметры
|
||
3. Реализуйте логику в методах `CanUse()` и `Use()`
|
||
|
||
## Преимущества системы
|
||
|
||
1. **Универсальность** - один интерфейс для всех предметов
|
||
2. **Гибкость** - каждый предмет может иметь свою логику
|
||
3. **Простота** - настройка в префабах, без создания отдельных файлов
|
||
4. **Расширяемость** - легко добавлять новые типы предметов
|
||
5. **Производительность** - кэширование и оптимизация
|
||
6. **Читаемость** - понятная структура и документация
|
||
|
||
## Примеры предметов
|
||
|
||
- **Оружие** - стрельба, перезарядка, патроны
|
||
- **Фонарик** - включение/выключение света
|
||
- **Аптечка** - лечение игрока
|
||
- **Инструменты** - ремонт, строительство
|
||
- **Еда** - восстановление здоровья/голода |