177 lines
5.2 KiB
C#
177 lines
5.2 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;
|
|
|
|
private 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;
|
|
|
|
public WeaponType Type => weaponType;
|
|
public int CurrentAmmo => currentAmmo;
|
|
public int ReserveAmmo => reserveAmmo;
|
|
public int MagazineSize => magazineSize;
|
|
public bool IsReloading => isReloading;
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
audioSource = GetComponent<AudioSource>();
|
|
if (audioSource == null)
|
|
audioSource = gameObject.AddComponent<AudioSource>();
|
|
|
|
currentAmmo = magazineSize;
|
|
}
|
|
|
|
protected virtual void Start()
|
|
{
|
|
_firePoint = FindFirstObjectByType<CameraController>().transform;
|
|
}
|
|
|
|
public virtual void Shoot()
|
|
{
|
|
if (isReloading) return;
|
|
if (currentAmmo <= 0)
|
|
{
|
|
PlayEmptySound();
|
|
return;
|
|
}
|
|
|
|
if (Time.time - lastShotTime < fireRate)
|
|
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 (emptySound != null)
|
|
audioSource.PlayOneShot(emptySound);
|
|
}
|
|
|
|
public virtual void AddAmmo(int amount)
|
|
{
|
|
reserveAmmo += amount;
|
|
}
|
|
|
|
protected virtual IEnumerator BoltActionDelay()
|
|
{
|
|
yield return new WaitForSeconds(reloadTime);
|
|
}
|
|
}
|
|
} |