using System;
using System.Collections;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
public class GunController : MonoBehaviour
{
public Camera playerCamera;
public bool isShooting, readyToShoot;
bool allowReset = true;
public float shootingDelay = 2f;
public int bulletsPerBurst = 3;
public int burstBulletsLeft;
public float spreadIntensity;
public GameObject bulletPrefab;
public Transform bulletSpawn;
public float bulletVelocity = 30;
public float bulletPrefabLifeTime = 3f;
public float reloadTime;
public int magazineSize, bulletsLeft;
public bool isReloading;
public enum ShootingMode
{
Single,
Burst,
Auto
}
public ShootingMode currentShootingMode;
private void Awake()
{
readyToShoot = true;
burstBulletsLeft = bulletsPerBurst;
bulletsLeft = magazineSize;
}
[Header("Gun Settings")]
public float fireRate = 0.1f;
public int clipSize = 30;
public int reservedAmmoCapacity = 270;
//Variables that change throughout code
bool _canShoot;
int _currentAmmoInClip;
int _ammoInReserve;
//Muzzle Flash
public Image muzzleFlashImage;
public Sprite[] flashes;
//Aiming
public Vector3 normalLocalPosition;
public Vector3 aimingLocalPosition;
public float aimSmoothing = 10;
[Header("Mouse Settings")]
Vector2 _currentRotation;
//Weapon Recoil
public bool randomizeRecoil;
public Vector2 randomRecoilConstraints;
public Vector2[] recoilPattern;
private void Start()
{
_currentAmmoInClip = clipSize;
_ammoInReserve = reservedAmmoCapacity;
_canShoot = true;
}
private void Update()
{
if (currentShootingMode == ShootingMode.Auto)
{
isShooting = Input.GetKey(KeyCode.Mouse0);
}
else if (currentShootingMode == ShootingMode.Single ||
currentShootingMode == ShootingMode.Burst)
{
isShooting = Input.GetKeyDown(KeyCode.Mouse0);
}
if (Input.GetKeyDown(KeyCode.R) && bulletsLeft < magazineSize && isReloading == false)
{
Reload();
}
if (readyToShoot && isShooting == false && isReloading == false && bulletsLeft <= 0)
{
Reload();
}
if (readyToShoot && isShooting && bulletsLeft > 0)
{
burstBulletsLeft = bulletsPerBurst;
FireWeapon();
}
if (readyToShoot && isShooting)
{
burstBulletsLeft = bulletsPerBurst;
FireWeapon();
}
DetermineAim();
if (Input.GetMouseButton(0) && _canShoot && _currentAmmoInClip > 0)
{
_canShoot = false;
_currentAmmoInClip--;
StartCoroutine(ShootGun());
}
else if (Input.GetKeyDown(KeyCode.R) && _currentAmmoInClip < clipSize && _ammoInReserve > 0)
{
int amountNeeded = clipSize - _currentAmmoInClip;
if (amountNeeded >= _ammoInReserve)
{
_currentAmmoInClip += amountNeeded;
_ammoInReserve -= amountNeeded;
}
else
{
_currentAmmoInClip = clipSize;
_ammoInReserve -= amountNeeded;
}
}
}
void DetermineAim()
{
Vector3 target = normalLocalPosition;
if (Input.GetMouseButton(1)) target = aimingLocalPosition;
Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing);
transform.localPosition = desiredPosition;
}
void DetermineRecoil()
{
transform.localPosition -= Vector3.forward * 0.1f;
if (randomizeRecoil)
{
float xRecoil = UnityEngine.Random.Range(-randomRecoilConstraints.x, randomRecoilConstraints.x);
float yRecoil = UnityEngine.Random.Range(-randomRecoilConstraints.y, randomRecoilConstraints.y);
Vector2 recoil = new Vector2(xRecoil, yRecoil);
_currentRotation += recoil;
}
else
{
if (recoilPattern == null || recoilPattern.Length == 0)
{
Debug.LogError("Recoil Pattern is null or empty!");
return;
}
int currentStep = clipSize + 1 - _currentAmmoInClip;
currentStep = Mathf.Clamp(currentStep, 0, recoilPattern.Length - 1);
_currentRotation += recoilPattern[currentStep];
}
}
IEnumerator ShootGun()
{
DetermineRecoil();
StartCoroutine(MuzzleFlash());
yield return new WaitForSeconds(fireRate);
_canShoot = true;
}
IEnumerator MuzzleFlash()
{
muzzleFlashImage.sprite = flashes[UnityEngine.Random.Range(0, flashes.Length)];
muzzleFlashImage.color = Color.white;
yield return new WaitForSeconds(0.05f);
muzzleFlashImage.sprite = null;
muzzleFlashImage.color = new Color(0, 0, 0, 0);
}
private void FireWeapon()
{
bulletsLeft--;
readyToShoot = false;
Vector3 shootingDirection = CalculateDirectionAndSpread().normalized;
GameObject bullet = Instantiate(bulletPrefab, bulletSpawn.position, Quaternion.identity);
bullet.transform.forward = shootingDirection;
bullet.GetComponent<Rigidbody>().AddForce(shootingDirection * bulletVelocity, ForceMode.Impulse);
StartCoroutine(DestroyBulletAfterTime(bullet, bulletPrefabLifeTime));
if (allowReset)
{
Invoke("ResetShot", shootingDelay);
allowReset = false;
}
if (currentShootingMode == ShootingMode.Burst && burstBulletsLeft > 1)
{
burstBulletsLeft--;
Invoke("FireWeapon", shootingDelay);
}
}
private void Reload()
{
isReloading = true;
Invoke("ReloadCompleted", reloadTime);
}
private void ReloadCompleted()
{
bulletsLeft = magazineSize;
isReloading = false;
}
private void ResetShot()
{
readyToShoot = true;
allowReset = true;
}
public Vector3 CalculateDirectionAndSpread()
{
Ray ray = playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
Vector3 targetPoint;
if (Physics.Raycast(ray, out hit))
{
targetPoint = hit.point;
}
else
{
targetPoint = ray.GetPoint(100);
}
Vector3 direction = targetPoint - bulletSpawn.position;
float x = UnityEngine.Random.Range(-spreadIntensity, spreadIntensity);
float y = UnityEngine.Random.Range(-spreadIntensity, spreadIntensity);
return direction + new Vector3(x, y, 0);
}
private IEnumerator DestroyBulletAfterTime(GameObject bullet, float delay)
{
yield return new WaitForSeconds(delay);
Destroy(bullet);
}
}