using RaceFields.Harvesters.AI; using UnityEngine; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif public sealed class MachineGunWeapon : MonoBehaviour { [Header("References")] [SerializeField] private Transform aimPivot; [SerializeField] private Transform muzzle; [SerializeField] private BulletProjectile projectilePrefab; [SerializeField] private ParticleSystem muzzleFlash; [Header("Targeting")] [SerializeField] private float targetSearchRadius = 80f; [SerializeField] private float targetHeightOffset = 1.1f; [SerializeField] private float aimTurnSpeed = 18f; [Header("Shooting")] [SerializeField] private float fireRate = 12f; [SerializeField] private float damagePerShot = 8f; [SerializeField] private float projectileSpeed = 70f; [SerializeField] private float projectileLifeTime = 2.5f; [SerializeField] private float spreadAngle = 1.2f; private Transform ownerRoot; private Transform currentTarget; private float nextShotTime; private void Awake() { if (aimPivot == null) aimPivot = transform; if (muzzle == null) muzzle = transform; } private void OnEnable() { nextShotTime = 0f; } private void Update() { AcquireTarget(); AimAtTarget(); if (IsFireHeld()) TryShoot(); } public void SetOwner(Transform owner) { ownerRoot = owner != null ? owner.root : null; } private void AcquireTarget() { if (IsValidTarget(currentTarget)) return; currentTarget = null; HarvesterChaseController[] enemies = Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); float bestDistanceSqr = targetSearchRadius * targetSearchRadius; Vector3 origin = transform.position; for (int i = 0; i < enemies.Length; i++) { if (enemies[i] == null) continue; Transform candidate = enemies[i].transform; float distanceSqr = (candidate.position - origin).sqrMagnitude; if (distanceSqr >= bestDistanceSqr) continue; currentTarget = candidate; bestDistanceSqr = distanceSqr; } } private bool IsValidTarget(Transform target) { if (target == null || !target.gameObject.activeInHierarchy) return false; return (target.position - transform.position).sqrMagnitude <= targetSearchRadius * targetSearchRadius; } private void AimAtTarget() { if (currentTarget == null || aimPivot == null) return; Vector3 targetPoint = currentTarget.position + Vector3.up * targetHeightOffset; Vector3 direction = targetPoint - aimPivot.position; if (direction.sqrMagnitude < 0.001f) return; Quaternion targetRotation = Quaternion.LookRotation(direction.normalized, Vector3.up); aimPivot.rotation = Quaternion.Slerp(aimPivot.rotation, targetRotation, aimTurnSpeed * Time.deltaTime); } private void TryShoot() { if (Time.time < nextShotTime || projectilePrefab == null) return; nextShotTime = Time.time + 1f / Mathf.Max(0.01f, fireRate); ShootProjectile(); } private void ShootProjectile() { Vector3 direction = ApplySpread(muzzle.forward); BulletProjectile projectile = Instantiate(projectilePrefab, muzzle.position, Quaternion.LookRotation(direction, Vector3.up)); projectile.Launch(direction * projectileSpeed, damagePerShot, projectileLifeTime, ownerRoot); if (muzzleFlash != null) muzzleFlash.Play(); } private Vector3 ApplySpread(Vector3 direction) { if (spreadAngle <= 0f) return direction.normalized; Quaternion spread = Quaternion.Euler( Random.Range(-spreadAngle, spreadAngle), Random.Range(-spreadAngle, spreadAngle), 0f); return (spread * direction).normalized; } private static bool IsFireHeld() { #if ENABLE_INPUT_SYSTEM if (Mouse.current != null) return Mouse.current.leftButton.isPressed; #endif #if ENABLE_LEGACY_INPUT_MANAGER return Input.GetMouseButton(0); #else return false; #endif } }