// ============================================================================================================= /// <summary> /// It will look for anything that is near. /// </summary> private void LookForNearestEnemy() { var possibleHits = new Collider[20]; var nearestDist = 999f; var size = Physics.OverlapSphereNonAlloc(shootingTower.position, buildingMain.GetPropType.defenseRadiusDistance, possibleHits, layerToSearchFor); for (var i = 0; i < size; i++) { if (buildingMain.IsItAlly) { if (possibleHits[i].CompareTag(GameTags.TeamBlue)) { continue; } } else { if (possibleHits[i].CompareTag(GameTags.TeamRed)) { continue; } } var dist = Vector3.Distance(shootingTower.position, possibleHits[i].transform.position); if (nearestDist > dist) { nearestDist = dist; myTarget = possibleHits[i].GetComponent <LiveObject>(); } } }
// ============================================================================================================= /// <summary> /// It will look for anything allied building that is near, while walking towards the friendly flag to defend. /// </summary> private void LookForNearestFriendlyBuilding() { var possibleHits = new Collider[20]; var nearestDist = 999f; var size = Physics.OverlapSphereNonAlloc(myTransform.position, checkForEnemyRadius, possibleHits, layerToSearchForDef); for (var i = 0; i < size; i++) { if (IsAlly) { if (possibleHits[i].CompareTag(GameTags.TeamRed)) { continue; } } else { if (possibleHits[i].CompareTag(GameTags.TeamBlue)) { continue; } } var dist = Vector3.Distance(myTransform.position, possibleHits[i].transform.position); if (nearestDist > dist) { nearestDist = dist; myNearestTarget = possibleHits[i].GetComponent <LiveObject>(); SetDestination(myNearestTarget.GetPosition); isInCombat = false; } } }
// ============================================================================================================= /// <summary> /// Rotates to target and shoot when possible /// </summary> private void HandleTarget() { if (!buildingMain.IsEnabled) { return; } if (myTarget == null) { currentTimerToSearch -= Time.deltaTime; if (currentTimerToSearch <= 0) { currentTimerToSearch = timerToSearchForTarget; LookForNearestEnemy(); } return; } //Check if target is still alive, I will do this so the target will have time to play death animation if (myTarget.GetMyHealth <= 0) { myTarget = null; return; } //Check if the target is still in the minimum distance var dist = Vector3.Distance(shootingTower.position, myTarget.transform.position); if (dist > buildingMain.GetPropType.defenseRadiusDistance) { myTarget = null; return; } //Make visual if (visualToRotate != null) { // visualToRotate.Rotate(0, Time.deltaTime * 10, 0); var dir = myTarget.transform.position - visualToRotate.position; dir.y = 0; var rot = Quaternion.LookRotation(dir); visualToRotate.rotation = Quaternion.Slerp(visualToRotate.rotation, rot, Time.deltaTime * 10); } //Rotate to target (THIS IS FOR AIM) - so pick an empty game object just as aim object var direction = myTarget.transform.position - shootingTower.position; // direction.y = 0; var rot2 = Quaternion.LookRotation(direction); shootingTower.rotation = Quaternion.Slerp(shootingTower.rotation, rot2, Time.deltaTime * 10); //Shoot currentTimerToShoot -= Time.deltaTime; if (currentTimerToShoot <= 0) { currentTimerToShoot = buildingMain.GetPropType.defenseAttackRate; VfxManager.Instance.CastProjectile(projectileToShoot, shootingTower.position, shootingTower.rotation, buildingMain.IsItAlly, buildingMain.GetPropType.defenseDamage); } }
// ============================================================================================================= /// <summary> /// Attack enemy in case still exists and it is close. /// If it is in the same place for too long, make it move again. /// We don't call SetDestination from NavMesh in all frames, to not waste performance. /// </summary> private void HandleCombat() { if (!IsActivated) { return; } //Attack wait timer is always on even if you don't have a target atkWaitTimer -= Time.deltaTime; if (myNearestTarget != null && isInCombat) { if (myNearestTarget.GetMyHealth <= 0) { myNearestTarget = null; return; } targetDistance = Vector3.Distance(myTransform.position, myNearestTarget.GetPosition); if (targetDistance <= unitData.atkDistance || startedToShoot) { //Rotate to target var direction = myNearestTarget.GetPosition - myTransform.position; direction.y = 0; var rot = Quaternion.LookRotation(direction); myTransform.rotation = Quaternion.Slerp(myTransform.rotation, rot, Time.deltaTime * 10); //Make unit to force stop navMeshAgent.stoppingDistance = 999; //Start attacking if (atkWaitTimer <= 0) { atkWaitTimer = unitData.atkSpeed; myAnimator.SetTrigger(AnimAttack); audioAtk.Play(); if (!isMelee) { startedToShoot = true; } } } else { if (myCurrentVelocity < idleMinimumSpeed) { standingTimer += Time.deltaTime; if (standingTimer > 1) { standingTimer = 0; SetDestination(myNearestTarget.GetPosition); } } } } }
// ============================================================================================================= /// <summary> /// Called when the attack animation is suppose to cast something. /// </summary> public void AttackAnimationCast() { if (myNearestTarget != null) { //Check if target is still alive, I do this so the target will have time to play death animation if (myNearestTarget.GetMyHealth <= 0) { myNearestTarget = null; return; } VfxManager.Instance.CastProjectile(rangedVfxSpawnId, myTransform.position, myTransform.rotation, IsAlly, unitData.damage); } }
// ============================================================================================================= /// <summary> /// Called when the attack animation is suppose to hit something. /// </summary> public void AttackAnimationHit() { if (myNearestTarget != null) { //Check if target is still alive, I do this so the target will have time to play death animation if (myNearestTarget.GetMyHealth <= 0) { myNearestTarget = null; return; } VfxManager.Instance.CallVFx(1, weaponPosition.position, Quaternion.identity); myNearestTarget.TakeDamage(unitData.damage); } }
// ============================================================================================================= /// <summary> /// Change if this unit will attack or defend. Only works for player units. /// </summary> /// <param name="toggle"></param> private void OnAttackMode(bool toggle) { //This should work only for player units. if (!IsAlly) { return; } isAttacking = toggle; //Reset if we were attacking or pursuing something. myNearestTarget = null; SetDestination(isAttacking ? myAttackTarget.position : myDefendTarget.position); }