initial commit
This commit is contained in:
160
Assets/Scripts/Weapon.cs
Normal file
160
Assets/Scripts/Weapon.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user