This commit is contained in:
Oscar
2025-06-28 19:17:59 +03:00
parent 23a35fe3cd
commit 3cb6514f78
9 changed files with 216 additions and 251 deletions

View File

@@ -22,7 +22,6 @@ public class BaseWeapon : InventoryItem, IUseable
[Property] public GameObject EjectTransform { get; set; }
// Состояние оружия
[Sync] public int CurrentAmmo { get; set; }
[Sync] public bool IsReloading { get; set; }
[Sync] public TimeSince TimeSinceLastShot { get; set; }
[Sync] public TimeSince TimeSinceReloadStart { get; set; }
@@ -35,6 +34,7 @@ public class BaseWeapon : InventoryItem, IUseable
// Кэш для производительности
private WeaponItemDefinition _weaponDefinition;
private bool _isInitialized;
private InventoryItem _inventoryItem;
// IUseable реализация - Cooldown вычисляется на основе FireRate
public float Cooldown
@@ -46,6 +46,32 @@ public class BaseWeapon : InventoryItem, IUseable
}
}
/// <summary>
/// Установить ссылку на InventoryItem
/// </summary>
public void SetInventoryItem( InventoryItem item )
{
_inventoryItem = item;
// Инициализируем оружие после установки InventoryItem
InitializeWeapon();
}
/// <summary>
/// Получить количество патронов в магазине из InventoryItem
/// </summary>
public int CurrentAmmo
{
get => _inventoryItem?.MagazineAmmo ?? 0;
set
{
if ( _inventoryItem != null )
{
_inventoryItem.MagazineAmmo = value;
}
}
}
protected override void OnStart()
{
base.OnStart();
@@ -54,8 +80,7 @@ public class BaseWeapon : InventoryItem, IUseable
_sound = GameObject.GetComponent<SoundPointComponent>( true );
_pickupItem = GameObject.Components.Get<PickupItem>();
// Инициализируем оружие
InitializeWeapon();
// Инициализация оружия будет вызвана после установки InventoryItem
}
protected override void OnUpdate()
@@ -88,8 +113,7 @@ public class BaseWeapon : InventoryItem, IUseable
return;
}
// Оружие начинается с пустым магазином - патроны нужно зарядить
CurrentAmmo = 0;
// Инициализация завершена
_isInitialized = true;
}
@@ -308,6 +332,24 @@ public class BaseWeapon : InventoryItem, IUseable
IsReloading = true;
TimeSinceReloadStart = 0;
var weaponDef = GetWeaponDefinition();
float reloadSpeed = weaponDef?.ReloadTime > 0 ? 1f / weaponDef.ReloadTime : 1f;
// Анимация перезарядки оружия
if ( GunRenderer != null )
{
GunRenderer.Set( "b_reload", true );
GunRenderer.Set( "speed_reload", reloadSpeed );
}
// Анимация перезарядки персонажа
var player = Dedugan.Local;
if ( player?.Renderer != null )
{
player.Renderer.Set( "b_reload", true );
player.Renderer.Set( "speed_reload", reloadSpeed );
}
// Эффекты перезарядки
PlayReloadEffects();
}
@@ -319,6 +361,21 @@ public class BaseWeapon : InventoryItem, IUseable
{
IsReloading = false;
// Сбрасываем анимацию перезарядки оружия
if ( GunRenderer != null )
{
GunRenderer.Set( "b_reload", false );
GunRenderer.Set( "speed_reload", 1f );
}
// Сбрасываем анимацию перезарядки персонажа
var player = Dedugan.Local;
if ( player?.Renderer != null )
{
player.Renderer.Set( "b_reload", false );
player.Renderer.Set( "speed_reload", 1f );
}
var weaponDef = GetWeaponDefinition();
if ( weaponDef == null ) return;

View File

@@ -45,12 +45,16 @@
### 3. Система патронов
- **Оружие начинается с пустым магазином** - патроны нужно зарядить
- **Сохранение патронов в магазине** - при выбрасывании оружия патроны остаются
- **Патроны сохраняются при снятии/экипировке** - патроны в магазине не теряются при переключении оружия
- Патроны хранятся в инвентаре как отдельные предметы
- **Стрельба зависит ТОЛЬКО от патронов в магазине** - CurrentAmmo
- **HUD показывает патроны в магазине** - не зависит от инвентаря
- **Патроны тратятся только из магазина при выстреле** - CurrentAmmo уменьшается
- **Патроны тратятся из инвентаря только при перезарядке** - загружаются в магазин
- **Перезарядка только вручную** - кнопка R или автоматически при пустом магазине
- **Анимация перезарядки оружия** - `b_reload` параметр анимации оружия
- **Анимация перезарядки персонажа** - `b_reload` параметр анимации персонажа
- **Скорость анимации перезарядки** - `speed_reload` параметр для контроля скорости анимации (рассчитывается как 1/ReloadTime)
- **Безопасная обработка неполных магазинов** - загружается столько патронов, сколько есть в инвентаре
### 4. HUD и UI
@@ -136,130 +140,4 @@ 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. **Читаемость** - понятная структура и документация
## Примеры предметов
- **Оружие** - стрельба, перезарядка, патроны
- **Фонарик** - включение/выключение света
- **Аптечка** - лечение игрока
- **Инструменты** - ремонт, строительство
- **Еда** - восстановление здоровья/голода
```