using System.Collections.Generic; using ActionGameFramework.Health; using ActionGameFramework.Helpers; using ActionGameFramework.Projectiles; using Core.Utilities; using TowerDefense.Affectors; using TowerDefense.Level; using UnityEngine; using UnityEngine.Events; namespace TowerDefense.Towers.TowerLaunchers { /// /// Rapid fire launcher, launchers a homing projectile /// public class SuperTowerLauncher : HomingLauncher { /// /// How long the tower will stay active /// public float towerLifeSpan = 10; /// /// Angle, in degrees, to rotate, on the x axis, the fire vector by /// public float fireVectorXRotationAdjustment = 45.0f; /// /// Fires when the max amount of projectiles has been reached /// public UnityEvent death; /// /// Timer to invoke a unity event when it elapses /// protected Timer m_LifeTimer; /// /// Finds a random enemy in a list and fires from a random point /// /// /// The list of enemies to sample from /// /// /// The object used to attack /// /// public override void Launch(List enemies, GameObject attack, Transform[] firingPoints,int maxAttack = 1) { var poolable = Poolable.TryGetPoolable(attack); if (poolable == null) { return; } Targetable enemy = enemies[Random.Range(0, enemies.Count)]; Transform firingPoint = GetRandomTransform(firingPoints); Launch(enemy, poolable.gameObject, firingPoint); } public override void Launch(Targetable enemy, GameObject attack, Transform firingPoint,int idx = 0) { var homingMissile = attack.GetComponent(); if (homingMissile == null) { Debug.LogError("No HomingLinearProjectile attached to attack object"); return; } Vector3 startingPoint = firingPoint.position; Vector3 targetPoint = Ballistics.CalculateLinearLeadingTargetPoint( startingPoint, enemy.position, enemy.velocity, homingMissile.startSpeed, homingMissile.acceleration); homingMissile.SetHomingTarget(enemy); var attackAffector = GetComponent(); Vector3 direction = attackAffector.towerTargetter.turret.forward; Vector3 binormal = Vector3.Cross(direction, Vector3.up); Quaternion rotation = Quaternion.AngleAxis(fireVectorXRotationAdjustment, binormal); Vector3 adjustedFireVector = rotation * direction; homingMissile.FireInDirection(startingPoint, adjustedFireVector); PlayParticles(fireParticleSystem, startingPoint, targetPoint); } /// /// Subscribes to Level Manager onStateChanged /// If waves have already begun, then begin death timer /// protected virtual void OnEnable() { if (!LevelManager.instanceExists) { return; } LevelState currentState = LevelManager.instance.levelState; if (currentState == LevelState.SpawningEnemies || currentState == LevelState.AllEnemiesSpawned) { m_LifeTimer = new Timer(towerLifeSpan, OnLifeTimerElapsed); } else { LevelManager.instance.levelStateChanged += OnLevelStateChanged; } } /// /// Unsubscribe from Level Manager onStateChanged /// protected virtual void OnDisable() { if (LevelManager.instanceExists) { LevelManager.instance.levelStateChanged -= OnLevelStateChanged; } } /// /// Tick the timer /// protected void Update() { if (m_LifeTimer == null) { return; } m_LifeTimer.Tick(Time.deltaTime); } /// /// Invoke the UnityEvent once the timer elapses /// protected void OnLifeTimerElapsed() { death.Invoke(); } /// /// Checks the current state, if within a valid state, start the death timer /// /// /// The previous state the the LevelManager was in /// /// /// The current state the LevelManager was in /// void OnLevelStateChanged(LevelState previousState, LevelState currentState) { if (currentState == LevelState.SpawningEnemies || currentState == LevelState.AllEnemiesSpawned) { m_LifeTimer = new Timer(towerLifeSpan, OnLifeTimerElapsed); } } } }