Advertisement
Nicklaj

TowerAI

Nov 18th, 2024
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.89 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using UnityEngine;
  5.  
  6. public class TowerAI : MonoBehaviour
  7. {
  8.     public bool IsAggressive = true;
  9.     public float IdleRotationSpeed = 20f;
  10.     public float AttackRotationSpeed = 50f;
  11.     public float ViewDistance = 10f;
  12.     public float ViewAngle = 45f;
  13.     public int RaysNumber = 12;
  14.     public GameObject Target;
  15.     public GameObject BulletType;
  16.     public float ProjectileSpeed = 10f;
  17.     public GameObject BGMSource;
  18.     public float AggressionResetTime = 3f;
  19.     public float TargetLoadTime = .6f;
  20.     public float ReloadTime = 2f;
  21.     public float TargettingTime = 5f;
  22.  
  23.     private Vector3 _rayOrigin;
  24.     private bool _targetVisible = false;
  25.     private float _targetLoadingTimer = 0f;
  26.     private float _targettingTimer = 0f;
  27.     private float _reloadTimer = 0f;
  28.     private float _aggressionResetTimer = 0f;
  29.     private bool _isLoadingTarget = false;
  30.     private bool _isReloading = false;
  31.     private bool _isTargetting = false;
  32.     private bool _isLookingForTarget = false;
  33.     private bool _canShoot = false;
  34.     private LineRenderer _targetRay;
  35.     private AudioClip _laserClip;
  36.     private AudioClip _firingClip;
  37.     private AudioSource _sfxSource;
  38.     private IEnumerator _bgmFadeCoroutine;
  39.  
  40.     // Start is called before the first frame update
  41.     void Start()
  42.     {
  43.         _laserClip = Resources.Load<AudioClip>("Sounds/LaserCharge");
  44.         _firingClip = Resources.Load<AudioClip>("Sounds/GuardianFiring");
  45.         _sfxSource = GetComponentInChildren<AudioSource>();
  46.         _targetRay = transform.Find("GunPivot").Find("RayOrigin").GetComponentInChildren<LineRenderer>();
  47.     }
  48.  
  49.     void SetRayOrigin()
  50.     {
  51.         try
  52.         {
  53.             _rayOrigin = this.gameObject.transform.Find("GunPivot").Find("RayOrigin").gameObject.transform.position;
  54.         }
  55.         catch (System.Exception e)
  56.         {
  57.             _rayOrigin = this.gameObject.transform.position;
  58.         }
  59.     }
  60.  
  61.     // Update is called once per frame
  62.     void Update()
  63.     {
  64.         // Ho cercato di simulare il comportamento dei guardiani di Breath of the Wild. Questo è il massimo che riesca a fare senza spenderci più di mezza giornata.
  65.         // IDLE BEHAVIOUR: Rotate the tower around its Y axis
  66.         if (!_targetVisible && !_isLookingForTarget)
  67.         {
  68.             transform.RotateAround(transform.position, Vector3.up, IdleRotationSpeed * Time.deltaTime);
  69.             SetRayOrigin();
  70.         }
  71.  
  72.         // Check if target is visible to the tower by shooting many rays in an area
  73.         RaycastHit hit;
  74.         Ray[] rays = new Ray[RaysNumber];
  75.         float angleStep = ViewAngle / (RaysNumber - 1);
  76.  
  77.         bool found = false;
  78.         for (int i = 0; i < RaysNumber; i++)
  79.         {
  80.             rays[i] = new Ray(_rayOrigin, Quaternion.Euler(0, -ViewAngle / 2 + angleStep * i, 0) * transform.forward);
  81.             Debug.DrawRay(rays[i].origin, rays[i].direction * ViewDistance, Color.red);
  82.             LayerMask mask = LayerMask.GetMask(LayerMask.LayerToName(2));
  83.             if (Physics.Raycast(rays[i], out hit, ViewDistance, ~mask))
  84.             {
  85.                 if (IsAggressive && hit.collider.gameObject == Target)
  86.                 {
  87.                     found = true;
  88.                     //Debug.Log("Target is visible");
  89.                 }
  90.             }
  91.         }
  92.  
  93.         // If at least one ray hits the target, the target is visible
  94.         if (found)
  95.         {
  96.             if (!_targetVisible) // Runs when the target is first found
  97.             {
  98.                 if (_bgmFadeCoroutine != null) StopCoroutine(_bgmFadeCoroutine);
  99.                 if (!BGMSource.GetComponent<AudioSource>().isPlaying)
  100.                 {
  101.                     BGMSource.GetComponent<AudioSource>().Play(0);
  102.                     BGMSource.GetComponent<AudioSource>().mute = false;
  103.                     BGMSource.GetComponent<AudioSource>().volume = 1;
  104.                 }
  105.                 _targetLoadingTimer = TargetLoadTime;
  106.                 _isLoadingTarget = true;
  107.             }
  108.             else _aggressionResetTimer = 0;
  109.             // Target has been found
  110.             _targetVisible = true;
  111.         }
  112.         else
  113.         {
  114.             // Target has not been found
  115.             if (_targetVisible)
  116.             {
  117.                 // Target was visible but isn't anymore. Start a timer to reset aggro.
  118.                 _aggressionResetTimer = AggressionResetTime;
  119.                 _isLookingForTarget = true;
  120.             }
  121.             _targetVisible = false;
  122.         }
  123.  
  124.         // Wait for some time before starting the targetting process
  125.         if (_targetLoadingTimer > 0)
  126.         {
  127.             _targetLoadingTimer -= Time.deltaTime;
  128.             if (_targetLoadingTimer <= 0)
  129.             {
  130.                 _isLoadingTarget = false;
  131.  
  132.                 if (_targetVisible)
  133.                 {
  134.                     _sfxSource.clip = _laserClip;
  135.                     _sfxSource.Play();
  136.  
  137.                     _isTargetting = true;
  138.                     _targettingTimer = TargettingTime;
  139.                 }
  140.             }
  141.         }
  142.  
  143.         // Targetting process
  144.         if (_targettingTimer > 0)
  145.         {
  146.             _targettingTimer -= Time.deltaTime;
  147.             if (_targettingTimer < TargettingTime / 2)
  148.             {
  149.                 _sfxSource.pitch = 2;
  150.             }
  151.             if (_targettingTimer <= 0)
  152.             {
  153.                 _isTargetting = false;
  154.                 _sfxSource.pitch = 1;
  155.                 _sfxSource.Stop();
  156.                 if (_targetVisible)
  157.                 {
  158.                     _canShoot = true;
  159.                 }
  160.             }
  161.         }
  162.  
  163.         // AGGRESSIVE BEHAVIOUR: Point the tower towards the target and shoot
  164.         if (IsAggressive && Target != null)
  165.         {
  166.             if (_targetVisible)
  167.             {
  168.                 // Smoothly rotate towards the target when found
  169.                 Vector3 direction = (Target.transform.position - transform.position).normalized;
  170.                 Quaternion lookRotation = Quaternion.LookRotation(direction);
  171.                 Quaternion rot = Quaternion.Slerp(transform.rotation, lookRotation, AttackRotationSpeed / 20 * Time.deltaTime);
  172.                 rot.x = 0;
  173.                 rot.z = 0;
  174.                 transform.rotation = rot;
  175.                 SetRayOrigin();
  176.  
  177.                 // Show targetting ray during the targetting process
  178.                 if (_isTargetting) _targetRay.SetPosition(1, transform.InverseTransformPoint(Target.transform.position));
  179.  
  180.                 if (_canShoot && BulletType != null)
  181.                 {
  182.                     _sfxSource.clip = _firingClip;
  183.                     _sfxSource.Play();
  184.                     _canShoot = false;
  185.  
  186.                     // Instantiate a new bullet and shoot it towards the player
  187.                     GameObject bullet = GameObject.Instantiate(BulletType);
  188.                     bullet.transform.forward = transform.forward;
  189.                     bullet.transform.position = _rayOrigin;
  190.                     bullet.GetComponent<Rigidbody>().velocity = direction * ProjectileSpeed;
  191.  
  192.                     _reloadTimer = ReloadTime;
  193.                     _isReloading = true;
  194.                 }
  195.             }
  196.             if(!_isTargetting) _targetRay.SetPosition(1, _targetRay.GetPosition(0));
  197.         }
  198.  
  199.         // Reload process
  200.         if (_reloadTimer > 0)
  201.         {
  202.             _reloadTimer -= Time.deltaTime;
  203.             if (_reloadTimer <= 0)
  204.             {
  205.                 _isReloading = false;
  206.  
  207.                 if (_targetVisible)
  208.                 {
  209.                     _sfxSource.clip = _laserClip;
  210.                     _sfxSource.Play();
  211.  
  212.                     _isTargetting = true;
  213.                     _targettingTimer = TargettingTime;
  214.                 }
  215.             }
  216.         }
  217.  
  218.         // Reset aggression after some time
  219.         if (_aggressionResetTimer > 0)
  220.         {
  221.             _aggressionResetTimer -= Time.deltaTime;
  222.             if (_aggressionResetTimer <= 0)
  223.             {
  224.                 _bgmFadeCoroutine = FadeAudioSource.StartFade(BGMSource.GetComponent<AudioSource>(), 1f, 0f);
  225.                 StartCoroutine(_bgmFadeCoroutine); // Fade out combat music
  226.                 _isLookingForTarget = false;
  227.             }
  228.         }
  229.     }
  230. }
  231.  
  232. // SRC: https://johnleonardfrench.com/how-to-fade-audio-in-unity-i-tested-every-method-this-ones-the-best/#first_method
  233. public static class FadeAudioSource
  234. {
  235.     public static IEnumerator StartFade(AudioSource audioSource, float duration, float targetVolume)
  236.     {
  237.         float currentTime = 0;
  238.         float start = audioSource.volume;
  239.         while (currentTime < duration)
  240.         {
  241.             currentTime += Time.deltaTime;
  242.             audioSource.volume = Mathf.Lerp(start, targetVolume, currentTime / duration);
  243.             yield return null;
  244.         }
  245.         audioSource.Stop();
  246.         yield break;
  247.     }
  248. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement