# Универсальная система используемых предметов ## Обзор Система построена на принципах наследования и интерфейсов. Любой предмет в руках может реализовывать интерфейс `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("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("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("path/to/item"); var item = WeaponFactory.CreateUseableItem(itemDef, inventoryItem); ``` #### 2. `CreateWeapon(WeaponItemDefinition, InventoryItem)` Создает оружие (для обратной совместимости): ```csharp var weaponDef = ResourceLibrary.Get("path/to/weapon"); var weapon = WeaponFactory.CreateWeapon(weaponDef, inventoryItem); ``` #### 3. `CreateItem(BaseItemDefinition)` Создает предмет для инвентаря: ```csharp var itemDef = ResourceLibrary.Get("path/to/item"); var inventoryItem = WeaponFactory.CreateItem(itemDef); ``` ### Автоматическое определение типа WeaponFactory автоматически определяет тип предмета по имени: - **Оружие**: содержит "pistol", "rifle", "gun" → создается `BaseWeapon` - **Фонарик**: содержит "flashlight", "light" → создается `Flashlight` - **По умолчанию**: создается `BaseWeapon` ### Примеры использования #### Создание пистолета: ```csharp // 1. Создаем предмет для инвентаря var pistolDef = ResourceLibrary.Get("Items/pistol.weapon"); var pistolItem = WeaponFactory.CreateWeaponItem(pistolDef); // 2. Добавляем в инвентарь player.Inventory.AddItem(pistolItem); // 3. Экипируем player.Inventory.EquipItem(pistolItem); ``` #### Создание фонарика: ```csharp // 1. Создаем предмет var flashlightDef = ResourceLibrary.Get("Items/flashlight.item"); var flashlightItem = WeaponFactory.CreateItem(flashlightDef); // 2. Добавляем в инвентарь player.Inventory.AddItem(flashlightItem); ``` #### Создание аптечки: ```csharp // 1. Создаем предмет var medkitDef = ResourceLibrary.Get("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. **Читаемость** - понятная структура и документация ## Примеры предметов - **Оружие** - стрельба, перезарядка, патроны - **Фонарик** - включение/выключение света - **Аптечка** - лечение игрока - **Инструменты** - ремонт, строительство - **Еда** - восстановление здоровья/голода