Files
PGiZ3/Assets/Code/Gameplay/Weapons/WeaponBase.cs
T
2026-02-24 09:18:49 +03:00

185 lines
5.5 KiB
C#

using System;
using System.Collections;
using Code.Gameplay.Camera;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Code.Gameplay.Weapons
{
public abstract class WeaponBase : MonoBehaviour
{
[SerializeField] protected WeaponType weaponType;
[SerializeField] protected string weaponName;
[SerializeField] protected FireMode fireMode;
[SerializeField] protected float damage = 20f;
[SerializeField] protected float fireRate = 0.5f;
[SerializeField] protected float bulletSpeed = 50f;
[SerializeField] protected int magazineSize = 10;
[SerializeField] protected int currentAmmo;
[SerializeField] protected int reserveAmmo = 30;
[SerializeField] protected float reloadTime = 1.5f;
[SerializeField] protected float spreadAngle = 1f;
public Transform _firePoint;
[SerializeField] protected GameObject bulletPrefab;
[SerializeField] protected ParticleSystem muzzleFlash;
[SerializeField] protected AudioClip shootSound;
[SerializeField] protected AudioClip reloadSound;
[SerializeField] protected AudioClip emptySound;
protected AudioSource audioSource;
protected bool isShooting;
protected bool isReloading;
protected float lastShotTime;
protected float lastShotTryTime;
public WeaponType Type => weaponType;
public int CurrentAmmo => currentAmmo;
public int ReserveAmmo => reserveAmmo;
public int MagazineSize => magazineSize;
public bool IsReloading => isReloading;
public float FireRate => fireRate;
public string WeaponName => weaponName;
protected virtual void Awake()
{
audioSource = GetComponent<AudioSource>();
if (audioSource == null)
audioSource = gameObject.AddComponent<AudioSource>();
currentAmmo = magazineSize;
}
protected virtual void Start()
{
if (!_firePoint)
_firePoint = FindFirstObjectByType<CameraController>().transform;
}
public virtual void Shoot()
{
if (isReloading) return;
if (Time.time - lastShotTime < fireRate)
return;
if (currentAmmo <= 0)
{
PlayEmptySound();
return;
}
switch (fireMode)
{
case FireMode.SemiAutomatic:
if (!isShooting) return;
break;
case FireMode.Automatic:
break;
case FireMode.BoltAction:
if (!isShooting) return;
StartCoroutine(BoltActionDelay());
break;
default:
throw new ArgumentOutOfRangeException();
}
PerformShot();
}
protected virtual void PerformShot()
{
currentAmmo--;
lastShotTime = Time.time;
SpawnBullet();
if (muzzleFlash != null)
muzzleFlash.Play();
if (shootSound != null)
audioSource.PlayOneShot(shootSound);
OnShoot();
}
protected virtual void SpawnBullet()
{
if (bulletPrefab == null) return;
var spread = Random.insideUnitSphere * (spreadAngle / 100f);
var direction = (_firePoint.forward + spread).normalized;
var bullet = Instantiate(bulletPrefab, _firePoint.position, Quaternion.LookRotation(direction));
var bulletComponent = bullet.GetComponent<Bullet>();
if (bulletComponent != null)
{
bulletComponent.Initialize(bulletSpeed, damage, direction);
}
}
protected virtual void OnShoot()
{
}
public virtual void StartShooting()
{
isShooting = true;
Shoot();
}
public virtual void StopShooting()
{
isShooting = false;
}
public virtual void Reload()
{
if (isReloading) return;
if (reserveAmmo <= 0) return;
if (currentAmmo == magazineSize) return;
StartCoroutine(ReloadCoroutine());
}
protected virtual IEnumerator ReloadCoroutine()
{
isReloading = true;
if (reloadSound != null)
audioSource.PlayOneShot(reloadSound);
yield return new WaitForSeconds(reloadTime);
var ammoNeeded = magazineSize - currentAmmo;
var ammoToTake = Mathf.Min(ammoNeeded, reserveAmmo);
currentAmmo += ammoToTake;
reserveAmmo -= ammoToTake;
isReloading = false;
}
protected virtual void PlayEmptySound()
{
if (Time.time - lastShotTryTime < fireRate)
return;
lastShotTryTime = Time.time;
if (emptySound != null)
audioSource.PlayOneShot(emptySound);
}
public virtual void AddAmmo(int amount)
{
reserveAmmo += amount;
}
protected virtual IEnumerator BoltActionDelay()
{
yield return new WaitForSeconds(reloadTime);
}
}
}