using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class AlliesMovement : MonoBehaviour { public GameObject m_ArrowPrefab = null; public NavMeshAgent playerAgent; public GameObject targetPosition; public GameObject ExitPosition;// Just so AlliesManager doesn't need to track it private Animator selfAnimator = null; private ArcPrediction m_Predictor = null; private float triggerRadius = 1f; private bool previousAnimationStateWasAiming = false; public float arrowForceMin = 0.3f; public float arrowForceMax = 0.9f; private Vector3 target; private string ennemyChestName = "Spine_01"; private string selfHeadName = "Head"; public AudioSource m_bowShootingSound; // Update is called once per frame void FixedUpdate() { NavMeshSetup(); } void Awake() { selfAnimator = GetComponent(); } void Start() { m_Predictor = GetComponentInChildren(); m_Predictor.HideArc(); } private void OnDestroy() { playerAgent.enabled = false; } private void NavMeshSetup() { if (!playerAgent.enabled) { playerAgent.enabled = true; } NavmeshAgentMovement(); } void NavmeshAgentMovement() { if (NearTargetPosition()) { TryShootEnemy(); } else { selfAnimator.runtimeAnimatorController = Resources.Load("Animations/SlowRun/SlowRunController") as RuntimeAnimatorController; playerAgent.SetDestination(targetPosition.transform.position); } } void TryShootEnemy() { Enemy[] enemies = GameObject.FindObjectsOfType(); if (enemies.Length > 0) { Vector3 selfHead = GetChildWithName(transform, selfHeadName).position; Enemy closestVisibleEnemy = null; float enemyClosestDistence = 1000000000f; foreach (Enemy enemy in enemies) { //Aim for the chest for higher odds of touching Vector3 enemyChest = GetChildWithName(enemy.transform, ennemyChestName).position; if (Vector3.Distance(enemyChest, selfHead) < enemyClosestDistence) { if (Physics.Linecast(selfHead, enemyChest, out RaycastHit hit)) { if (hit.collider.transform.IsChildOf(enemy.transform))// Found a closer enemy that is visible that can be shot { closestVisibleEnemy = enemy; enemyClosestDistence = Vector3.Distance(enemyChest, selfHead); } } else// Did not colide anything, including the enemy, so it should be fine to shoot? { closestVisibleEnemy = enemy; enemyClosestDistence = Vector3.Distance(enemyChest, selfHead); } } } if (closestVisibleEnemy != null) { //Aim for the chest for higher odds of touching Vector3 enemyChest = GetChildWithName(closestVisibleEnemy.transform, ennemyChestName).position; transform.LookAt(enemyChest); bool nextAnimationStateWasAiming = selfAnimator.GetCurrentAnimatorStateInfo(0).IsName("Aiming"); if(nextAnimationStateWasAiming != previousAnimationStateWasAiming){ target = enemyChest; } previousAnimationStateWasAiming = nextAnimationStateWasAiming; if (selfAnimator.runtimeAnimatorController.name != "BowDrawController") { selfAnimator.runtimeAnimatorController = Resources.Load("Animations/BowDraw/BowDrawController") as RuntimeAnimatorController; } } else { if (selfAnimator.runtimeAnimatorController.name != "Idle") { selfAnimator.runtimeAnimatorController = Resources.Load("Animations/Idle/Idle") as RuntimeAnimatorController; } } }else { if (selfAnimator.runtimeAnimatorController.name != "Idle") { selfAnimator.runtimeAnimatorController = Resources.Load("Animations/Idle/Idle") as RuntimeAnimatorController; } } } private Transform GetChildWithName(Transform parent, string name) { if(parent.childCount > 0) { foreach (Transform child in parent) { if (child.name == name) return child; if (child.childCount > 0) { Transform subChild = GetChildWithName(child, name); if (subChild != null) { return subChild; } } } } return null; } bool NearTargetPosition() { if (targetPosition != null) { return Vector3.Distance(targetPosition.transform.position, this.transform.position) < triggerRadius; } return true; // If no target is set, assume it's in position } // Called by an animation event private void FireArrow() { // Arrow setup Transform bowTransform = GetChildWithName(transform, "ModifiedAssetBowWithBlender"); GameObject arrowObject = Instantiate(m_ArrowPrefab, bowTransform.position, new Quaternion(0, 1f, -0.1f, 0.2f)); Arrow arrow = arrowObject.GetComponent(); Vector3 shootingDirection = new Vector3(target.x,bowTransform.position.y, target.z); arrowObject.transform.LookAt(shootingDirection); arrowObject.GetComponent().detectCollisions = false; // Figuring out the required force float arrowForce = arrowForceMin; float flightTime = 1.4142135f*Mathf.Sqrt((target.y - bowTransform.position.y)/Physics.gravity.y); float distanceX = target.x - bowTransform.position.x; float distanceZ = target.z - bowTransform.position.z; float targetSpeed = Mathf.Sqrt(distanceX*distanceX+distanceZ*distanceZ)/flightTime; float neededPower = targetSpeed / arrow.m_MaxLaunchSpeedMeterPerSecond; if(neededPower > arrowForceMin && neededPower < arrowForceMax){ arrowForce = neededPower; } else if (neededPower > arrowForceMax){ // Likely gonna miss, but lmao nice try arrowForce = arrowForceMax; } // Fire the arrow m_Predictor.RenderArc(arrowForce * arrow.m_MaxLaunchSpeedMeterPerSecond, 20, arrowObject.transform.forward); arrow.Fire(arrowForce, arrowObject.transform.forward, m_bowShootingSound); } }