using System; using System.Collections.Generic; using ActionGameFramework.Audio; using ActionGameFramework.Health; using Core.Health; using TowerDefense.Agents; using TowerDefense.Targetting; using TowerDefense.Towers; using TowerDefense.Towers.Projectiles; using UnityEngine; using KTGMGemClient; namespace TowerDefense.Affectors { /// /// The common effect for handling firing projectiles to attack /// /// Requires an ILauncher but it is not automatically added /// Add an ILauncher implementation to this GameObject before you add this script /// [RequireComponent(typeof(ILauncher))] public class AttackAffector : Affector, ITowerRadiusProvider { /// /// The projectile used to attack /// public GameObject projectile; // protected GameObject projectile1; protected GameObject projectile2; /// /// The list of points to launch the projectiles from /// public Transform[] projectilePoints; /// /// The reference to the center point where the tower will search from /// public Transform epicenter; /// /// Configuration for when the tower does splash damage /// public bool isMultiAttack; /// /// 如果是多目标攻击,最多攻击目标 /// public int maxAttackNum = 1; /// /// The fire rate in fires-per-second /// public float fireRate; /// /// 是否木属性数据 /// public bool bWoodAffector = false; /// /// The audio source to play when firing /// public RandomAudioSource randomAudioSource; /// /// Gets the targetter /// public Targetter towerTargetter; /// /// Color of effect radius visualization /// public Color radiusEffectColor; /// /// Search condition /// public Filter searchCondition; /// /// Fire condition /// public Filter fireCondition; /// /// The reference to the attached launcher /// protected ILauncher m_Launcher; /// /// The time before firing is possible /// protected float m_FireTimer; /// /// Reference to the current tracked enemy /// protected Targetable m_TrackingEnemy; /// /// 处理装弹时间. /// protected float fillBulletTime = 0.0f; /// /// 充能时间 /// protected float energyCalTime = 0; protected float fInEnergy = 0; protected float fBackupTimer = 0.0f; /// /// Gets the search rate from the targetter /// public float searchRate { get { return towerTargetter.searchRate; } set { towerTargetter.searchRate = value; } } /// /// Gets the targetable /// public Targetable trackingEnemy { get { return m_TrackingEnemy; } } /// /// Gets or sets the attack radius /// public float effectRadius { get { return towerTargetter.effectRadius; } } public Color effectColor { get { return radiusEffectColor; } } public Targetter targetter { get { return towerTargetter; } } /// /// Initializes the attack affector /// public override void Initialize(IAlignmentProvider affectorAlignment) { Initialize(affectorAlignment, -1); } /// /// 返回可能存在的Targetter. /// /// public override TowerDefense.Targetting.Targetter GetTargetter() { return targetter; } /// /// Initialises the attack affector with a layer mask /// public override void Initialize(IAlignmentProvider affectorAlignment, LayerMask mask) { base.Initialize(affectorAlignment, mask); SetUpTimers(); towerTargetter.ResetTargetter(); towerTargetter.alignment = affectorAlignment; towerTargetter.acquiredTarget += OnAcquiredTarget; towerTargetter.lostTarget += OnLostTarget; } void OnDestroy() { towerTargetter.acquiredTarget -= OnAcquiredTarget; towerTargetter.lostTarget -= OnLostTarget; } void OnLostTarget() { m_TrackingEnemy = null; } void OnAcquiredTarget(Targetable acquiredTarget) { m_TrackingEnemy = acquiredTarget; } public Damager damagerProjectile { get { return projectile == null ? null : projectile.GetComponent(); } } public Damager damagerProjectile1 { get { return projectile == null ? null : projectile.GetComponent(); } } public Damager damagerProjectile2 { get { return projectile == null ? null : projectile.GetComponent(); } } /// /// Returns the total projectile damage /// public float GetProjectileDamage() { var splash = projectile.GetComponent(); float splashDamage = splash != null ? splash.damage : 0; return damagerProjectile.finalDamage + splashDamage; } /// /// Initialise the RepeatingTimer /// protected virtual void SetUpTimers() { m_FireTimer = 1 / fireRate; m_Launcher = GetComponent(); } protected void updateTowerSkillData() { // // 预留出来装填子弹的时间. if (fillBulletTime > 0) { fillBulletTime -= Time.deltaTime; if (fillBulletTime <= 0.3f) { if (towerPtr && towerPtr.bulletCtl) towerPtr.bulletCtl.resetToMaxBullet(); } if (fillBulletTime <= 0) { fillBulletTime = 0; } } // // 充能时间的处理 if( towerPtr && towerPtr.energyCtl) { if( this.fInEnergy <= 0) { this.energyCalTime += Time.deltaTime; float process = energyCalTime % 11.0f; int proint = (int)Math.Floor(process); proint += towerPtr.uiProOffset; towerPtr.energyCtl.SetEnergyProgress(proint); if (proint == 10) { fInEnergy = 5.0f; // 设置多倍攻击速度 fBackupTimer = m_FireTimer; m_FireTimer = m_FireTimer / 3.0f; towerPtr.uiProOffset = 0; } } else { fInEnergy -= Time.deltaTime; if( fInEnergy <= 0) { EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd); fInEnergy = 0.0f; this.energyCalTime = 0.0f; towerPtr.energyCtl.SetEnergyProgress(0); // 恢复正常攻击速度 m_FireTimer = fBackupTimer; } } } } /// /// Update the timers /// protected virtual void Update() { // 处理当前Affector所在Tower对应的技能 updateTowerSkillData(); m_FireTimer -= Time.deltaTime; if( trackingEnemy == null ) m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector); if (trackingEnemy != null && m_FireTimer <= 0.0f) { OnFireTimer(); m_FireTimer = 1 / fireRate; // 多倍攻速: if (fInEnergy > 0.0f) m_FireTimer = m_FireTimer / 3.0f; } } /// /// Fired at every poll of the fire rate timer /// protected virtual void OnFireTimer() { if (fireCondition != null) { if (!fireCondition()) { return; } } FireProjectile(); } /// /// Common logic when attacking /// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标 /// protected virtual void FireProjectile() { // 不再处理多子弹攻击,确保只有一个弹道 isMultiAttack = false; m_TrackingEnemy = targetter.GetTarget( waveLineID, bWoodAffector ); if ( (m_TrackingEnemy == null) || (fillBulletTime>0) ) { if (this.towerPtr) towerPtr.setTowerState(false); return; }else { if (this.towerPtr) towerPtr.setTowerState(true); } // // 处理子弹充能相关的内容 if( towerPtr && (towerPtr.bulletCtl != null)) { int bnum = towerPtr.bulletCtl.decBullet(); // if (bnum == 0) { damagerProjectile.damageMulti = 2.0f; fillBulletTime = 2.0f; } } if (isMultiAttack) { List enemies = towerTargetter.GetAllTargets(); if( (enemies != null)&&(Targetter.bSearchTarget) ) m_Launcher.Launch(enemies, projectile, projectilePoints,this.maxAttackNum); } else { if(Targetter.bSearchTarget ) m_Launcher.Launch(m_TrackingEnemy, damagerProjectile.gameObject, projectilePoints); } if (randomAudioSource != null) { if( Targetter.bSearchTarget ) randomAudioSource.PlayRandomClip(); } } /// /// A delegate to compare distances of components /// /// /// protected virtual int ByDistance(Targetable first, Targetable second) { float firstSqrMagnitude = Vector3.SqrMagnitude(first.position - epicenter.position); float secondSqrMagnitude = Vector3.SqrMagnitude(second.position - epicenter.position); return firstSqrMagnitude.CompareTo(secondSqrMagnitude); } #if UNITY_EDITOR /// /// Draws the search area /// void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(epicenter.position, towerTargetter.effectRadius); } #endif } /// /// A delegate for boolean calculation logic /// public delegate bool Filter(); }