using GameDevHQ.FileBase.Gatling_Gun; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using UnityEngine; using UnityEngine.AI; public class HitscanTurret : Emplacement, IDamageable { [SerializeField] float _attackRange = 1f; [SerializeField] float _damagePerSecond = 10f; [SerializeField] float _turnSpeed = 1f; [SerializeField] float _targetingArc = 5f; [SerializeField, ReadOnly(true)] Collider _triggerCollider; [SerializeField] GameObject _turretObject; [SerializeField] GameObject _closestEnemy; [SerializeField] float _idleTurnSpeed = 0.2f; [SerializeField] Gatling_Gun _gun; Dictionary _enemyDict; List _availableEnemies; private void Start() { _enemyDict = new Dictionary(); SphereCollider collider = gameObject.AddComponent(); collider.radius = _attackRange; collider.isTrigger = true; _triggerCollider = collider; } private void OnDrawGizmos() { Gizmos.DrawWireSphere(transform.position, _attackRange); } // Update is called once per frame void Update() { if (!_active) { return; } FindEnemy(); AimAtAndShootAtCurrentEnemy(); } private void OnTriggerEnter(Collider other) { if (other.CompareTag("EnemyTarget")) { Debug.Log("Adding enemy", other.gameObject); _enemyDict.Add(other.gameObject.GetInstanceID(), other.gameObject); if (_closestEnemy != null) { _closestEnemy = other.gameObject; } } } private void OnTriggerExit(Collider other) { int instanceID = other.gameObject.GetInstanceID(); if (other.CompareTag("EnemyTarget") && _enemyDict.ContainsKey(instanceID)) { Debug.Log("Removing enemy", other.gameObject); _enemyDict.Remove(instanceID); if (_closestEnemy && _closestEnemy.GetInstanceID() == instanceID) { _closestEnemy = null; // We'll find them in the Aim // EventManager.Instance.StopFiring(_closestEnemy); } } } private int? GetClosestEnemyID() { GameObject enemy = _closestEnemy; while (!enemy.transform.root) { enemy = enemy.transform.root.gameObject; if (enemy.CompareTag("Enemy")) { return enemy.GetInstanceID(); } } return null; } private void AimAtAndShootAtCurrentEnemy() { if (_closestEnemy == null) { _gun.Firing = false; return; } // Shouldn't need to do distance check since our trigger volume handles it Vector3 targetVector = _closestEnemy.transform.position - _turretObject.transform.position; // Rotate toward the hit _turretObject.transform.forward = Vector3.RotateTowards(_turretObject.transform.forward, targetVector, _turnSpeed * Time.deltaTime, 0f); // If in target arc, fire if (Vector3.Angle(_turretObject.transform.forward, targetVector) < _targetingArc && !_gun.Firing) { // Play the animation for firing _gun.Firing = true; int? enemyID = GetClosestEnemyID(); if (enemyID != null) { EventManager.Instance.DispatchAttackStart((int)enemyID, _damagePerSecond); } } else { _gun.Firing = false; } } private void FindEnemy() { if (_closestEnemy != null) { return; } if (_enemyDict.Count < 1) { // General spin _turretObject.transform.Rotate(Vector3.up, _idleTurnSpeed * Time.deltaTime); _gun.Firing = false; return; } _closestEnemy = _enemyDict[0]; float _closestDistance = Vector3.Distance(transform.position, _closestEnemy.transform.position); for (int i = 1; i < _enemyDict.Count; i++) { float distance = Vector3.Distance(transform.position, _enemyDict[i].transform.position); if (distance < _closestDistance) { _closestDistance = distance; _closestEnemy = _enemyDict[i]; } } } }