void Update() { // if stop == true, halt behaviour. if (stop) { return; } // If there isn't a current target then stop firing. if (targetIndex < 0 || targetIndex > targets.Length || targets[targetIndex] == null) { // If there are no targets, try find one (or more) again. if (targets.Length == 0) { targets = GameObject.FindGameObjectsWithTag(TargetTag); } // Hide muzzle flash. _CurrentWeapon.GetMuzzleFlashGO().SetActive(false); // Randomly pick a new target from the possible targets. (done 50 times in the case the target is null) for (int i = 0; i < 50; i++) { if (targets.Length == 0) { break; } targetIndex = Random.Range(0, targets.Length); // If a target is found, check to see if the AI (self) can see the target. if (targets[targetIndex] != null) { RaycastHit hit; if (Physics.Raycast(this.transform.position, targets[targetIndex].transform.position - this.transform.position, out hit, _SightRange)) { if (hit.transform.tag == TargetTag) { break; } } } } // If no target is found, stop behaviour. if (targets.Length > 0 && targets[targetIndex] == null) { stop = true; } // The target is not spotted by default. SpottedPlayer = false; return; } // "Look" (aim gun) towards the player. this.transform.LookAt(targets[targetIndex].transform.position, transform.up); // If waitFor is true (in the case of reaction time), hault behaviour. if (waitFor) { return; } // Create 3 different rays (so that the AI has can spot targets in obscure postions such as crouched) RaycastHit hitBottom; // Lowest ray hit (stores hit data) RaycastHit hitMid; // Medium ray hit (stores hit data) RaycastHit hitTop; // Top ray hit (stores hit data) #region Debugging // hitTop Debug.DrawRay(this.transform.position, (this.transform.forward + (this.transform.up * 0.075f)) * _SightRange, Color.green); // hitMid Debug.DrawRay(this.transform.position, (this.transform.forward + (this.transform.up * 0.05f)) * _SightRange, Color.green); // hitBottom Debug.DrawRay(this.transform.position, this.transform.forward * _SightRange, Color.green); #endregion // Has the ray hit an object? bool hitMidBool = Physics.Raycast(this.transform.position, (this.transform.forward + (this.transform.up * 0.05f)), out hitMid, _SightRange); bool hitTopBool = Physics.Raycast(this.transform.position, (this.transform.forward + (this.transform.up * 0.075f)), out hitTop, _SightRange); bool hitBottomBool = Physics.Raycast(this.transform.position, this.transform.forward, out hitBottom, _SightRange); // If none of the rays have hit an object, return and hide the muzzle flash (stopped firing). if (!hitBottomBool && !hitMidBool && !hitTopBool) { _CurrentWeapon.GetMuzzleFlashGO().SetActive(false); return; } // Else if ANY of the three rays have hit the player/a target. else if (hitTop.transform != null && (hitTop.transform.tag == TargetTag || (hitTop.transform.GetComponent <Destructable> () && SpottedPlayer)) || hitBottom.transform != null && (hitBottom.transform.tag == TargetTag || (hitBottom.transform.GetComponent <Destructable> () && SpottedPlayer)) || hitMid.transform != null && (hitMid.transform.tag == TargetTag || (hitMid.transform.GetComponent <Destructable> () && SpottedPlayer))) { // If the player hasn't already been spotted. if (SpottedPlayer == false) { // React (wait for a moment of time). StartCoroutine("Reaction"); SpottedPlayer = true; return; } } // Else if another object (not a player/target) return and hide the muzzle flash (stopped firing). else { //TODO NEXT BUILD // ATEMPT TO SEE TARGET BY CROUCHING OR LEANING _CurrentWeapon.GetMuzzleFlashGO().SetActive(false); return; } // If the Muzzle Flash is not playing then activate it. if (!_CurrentWeapon.GetMuzzleFlashPS().isPlaying) { _CurrentWeapon.GetMuzzleFlashPS().Play(); _CurrentWeapon.GetMuzzleFlashPS().enableEmission = true; _CurrentWeapon.GetMuzzleFlashGO().SetActive(true); } // If the weapon's clip is empty. if (_CurrentWeapon.GetClip() <= 0) { // If there is Ammo left then reload. if (_CurrentWeapon.AIGetAmmo() > 0) { // Play Reload sound. if (_AudioSource) { _AudioSource.clip = ReloadSound; if (_AudioSource.isPlaying == false) { if (_AudioSource.enabled == true) { _AudioSource.Play(); } } } //Reload weapon. _CurrentWeapon.Reload(); } // Activate/show Muzzle flash. _CurrentWeapon.GetMuzzleFlashGO().SetActive(false); return; } // If no animation is playing (weapon is idle/not being used) if (this.GetComponent <Animation> ().isPlaying == false) { // Recoil effect implemented using random vector to be used as an offset. Vector3 randomVector = new Vector3(Random.Range(-_RandomVectorRange, _RandomVectorRange), Random.Range(-_RandomVectorRange, _RandomVectorRange), Random.Range(-_RandomVectorRange, _RandomVectorRange)); Debug.DrawRay(this.transform.position + this.transform.up * 0.5f, (this.transform.forward + randomVector) * _SightRange, Color.blue); // If the ray (bullet) has hit an object. RaycastHit hit; if (Physics.Raycast(this.transform.position, this.transform.forward + randomVector, out hit, _SightRange)) { // Play recoil animation this.GetComponent <Animation> ().Play("recoil"); // Play shoot/fire sound. if (_AudioSource) { _AudioSource.clip = AssaultRifleFireSound; if (_AudioSource.enabled == true) { _AudioSource.Play(); } } // Activate/Show muzzle flash. _CurrentWeapon.GetMuzzleFlashGO().SetActive(true); // Reduce clip size by 1 bullet. _CurrentWeapon.ManipulateClip(-1); // Apply force to the hit object (if it has a Rigidbody component). if (hit.transform.GetComponent <Rigidbody> ()) { hit.transform.GetComponent <Rigidbody> ().AddForce(this.transform.forward * 10000f * Time.deltaTime); } // Reduce object's health by 1 (if it has a Destructable component). if (hit.transform.GetComponent <Destructable> ()) { hit.transform.GetComponent <Destructable> ().ManipulateHealth(_CurrentWeapon.GetDamage()); } } } }