161 lines
4.7 KiB
C#
161 lines
4.7 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
public class Weapon : MonoBehaviour
|
|
{
|
|
[Header("Weapon Stats")]
|
|
public string weaponName = "Assault Rifle";
|
|
public int damage = 25;
|
|
public float fireRate = 0.12f;
|
|
public float range = 100f;
|
|
public int maxAmmo = 30;
|
|
public int currentAmmo;
|
|
public float reloadTime = 1.5f;
|
|
|
|
[Header("Effects")]
|
|
[SerializeField] private ParticleSystem muzzleFlash;
|
|
[SerializeField] private GameObject impactEffectPrefab;
|
|
[SerializeField] private Transform muzzlePoint;
|
|
|
|
[Header("Ballistics & Projectile Support")]
|
|
[SerializeField] private bool useProjectile = false;
|
|
[SerializeField] private GameObject projectilePrefab;
|
|
[SerializeField] private float projectileSpeed = 50f;
|
|
|
|
[Header("Ammo Reserves")]
|
|
[SerializeField] private bool infiniteReserve = true;
|
|
[SerializeField] private int currentReserveAmmo = 90;
|
|
[SerializeField] private int maxReserveAmmo = 180;
|
|
|
|
[Header("Audio Effects (Optional)")]
|
|
[SerializeField] private AudioSource audioSource;
|
|
[SerializeField] private AudioClip fireSound;
|
|
[SerializeField] private AudioClip reloadSound;
|
|
[SerializeField] private AudioClip emptySound;
|
|
|
|
private float nextFireTime;
|
|
private bool isReloading;
|
|
|
|
public bool IsReloading => isReloading;
|
|
public bool InfiniteReserve => infiniteReserve;
|
|
public int CurrentReserveAmmo => currentReserveAmmo;
|
|
public int MaxReserveAmmo => maxReserveAmmo;
|
|
|
|
private void Awake()
|
|
{
|
|
currentAmmo = maxAmmo;
|
|
if (audioSource == null)
|
|
{
|
|
audioSource = GetComponent<AudioSource>();
|
|
}
|
|
}
|
|
|
|
public bool CanShoot() => Time.time >= nextFireTime && !isReloading && currentAmmo > 0;
|
|
|
|
public void Shoot(Camera playerCamera, LayerMask hitMask)
|
|
{
|
|
nextFireTime = Time.time + fireRate;
|
|
currentAmmo--;
|
|
|
|
if (muzzleFlash) muzzleFlash.Play();
|
|
|
|
PlaySound(fireSound);
|
|
|
|
if (useProjectile && projectilePrefab != null)
|
|
{
|
|
FireProjectile(playerCamera);
|
|
}
|
|
else
|
|
{
|
|
FireHitscan(playerCamera, hitMask);
|
|
}
|
|
}
|
|
|
|
private void FireHitscan(Camera playerCamera, LayerMask hitMask)
|
|
{
|
|
Ray ray = playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
|
|
if (Physics.Raycast(ray, out RaycastHit hit, range, hitMask))
|
|
{
|
|
if (hit.collider.TryGetComponent<EnemyController>(out var enemy))
|
|
{
|
|
enemy.TakeDamage(damage);
|
|
}
|
|
|
|
if (impactEffectPrefab)
|
|
{
|
|
GameObject impact = Instantiate(impactEffectPrefab, hit.point, Quaternion.LookRotation(hit.normal));
|
|
Destroy(impact, 2.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FireProjectile(Camera playerCamera)
|
|
{
|
|
Vector3 spawnPosition = muzzlePoint != null ? muzzlePoint.position : playerCamera.transform.position + playerCamera.transform.forward * 0.5f;
|
|
|
|
// Calculate aim point by casting from crosshair
|
|
Ray ray = playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
|
|
Vector3 targetPoint;
|
|
if (Physics.Raycast(ray, out RaycastHit hit, range))
|
|
{
|
|
targetPoint = hit.point;
|
|
}
|
|
else
|
|
{
|
|
targetPoint = ray.GetPoint(range);
|
|
}
|
|
|
|
Vector3 direction = (targetPoint - spawnPosition).normalized;
|
|
Quaternion rotation = Quaternion.LookRotation(direction);
|
|
|
|
GameObject projectileObj = Instantiate(projectilePrefab, spawnPosition, rotation);
|
|
if (projectileObj.TryGetComponent<Projectile>(out var projectile))
|
|
{
|
|
projectile.Initialize(damage, projectileSpeed, "Player");
|
|
}
|
|
}
|
|
|
|
public IEnumerator ReloadRoutine()
|
|
{
|
|
if (isReloading || currentAmmo == maxAmmo) yield break;
|
|
if (!infiniteReserve && currentReserveAmmo <= 0)
|
|
{
|
|
PlaySound(emptySound);
|
|
yield break;
|
|
}
|
|
|
|
isReloading = true;
|
|
PlaySound(reloadSound);
|
|
|
|
yield return new WaitForSeconds(reloadTime);
|
|
|
|
int neededAmmo = maxAmmo - currentAmmo;
|
|
if (infiniteReserve)
|
|
{
|
|
currentAmmo = maxAmmo;
|
|
}
|
|
else
|
|
{
|
|
int ammoToAdd = Mathf.Min(neededAmmo, currentReserveAmmo);
|
|
currentAmmo += ammoToAdd;
|
|
currentReserveAmmo -= ammoToAdd;
|
|
}
|
|
|
|
isReloading = false;
|
|
}
|
|
|
|
public void AddReserveAmmo(int amount)
|
|
{
|
|
currentReserveAmmo = Mathf.Clamp(currentReserveAmmo + amount, 0, maxReserveAmmo);
|
|
}
|
|
|
|
private void PlaySound(AudioClip clip)
|
|
{
|
|
if (clip != null && audioSource != null)
|
|
{
|
|
audioSource.PlayOneShot(clip);
|
|
}
|
|
}
|
|
}
|
|
|