Files
LowPolyFPS/Assets/Scripts/Weapon.cs
2026-10-12 21:28:47 +01:00

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);
}
}
}