152 lines
4.3 KiB
C#
152 lines
4.3 KiB
C#
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<HarvesterChaseController>(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
|
|
}
|
|
}
|