using System; using System.Collections.Generic; using ActionGameFramework.Audio; using ActionGameFramework.Health; using Core.Health; 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; /// /// 木塔最后一击是特殊攻击,需要替换projectile /// public GameObject woodProjectile_SP; // 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 /// [SerializeField] private float projectileFireRate = 1; public float FireRate { get { return 1 / GetFireDuration(); } } /// /// 是否木属性数据 /// 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; protected float freezeBreathTimer; /// /// Reference to the current tracked enemy /// protected Targetable m_TrackingEnemy; public TowerLevel towerLevel; /// /// 处理装弹时间. /// protected float fillBulletTime = 0.0f; /// /// 火精灵充能时间 /// protected float energyCalTime = 0; protected float fInEnergy = 0; protected float fBackupTimer = 0.0f; /// /// 水精灵的充能时间 /// protected float freezeBreathCallTime = 0; protected float inFreezeBreath = 0; protected float freezeBreathBackTimer = 0; private int towerAttributeId; /// /// 火精灵技能固定攻击倍速 /// /// protected float fireSpeed { get; set; } = 5f; /// /// 火精灵攻击最终攻击倍速,里面计算了buff增加的倍速 /// /// public float finalFireSpeed { get { FireRateAdd fireRateAdd = (FireRateAdd)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.FireRateAdd); float rateAdd = fireRateAdd.GetFireSpeedAdd(towerAttributeId); return rateAdd > 1 ? rateAdd : fireSpeed; } } /// /// 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; GetAudioEnum(); myTower = transform.parent.GetComponent(); } private AudioEnum audioEnum;//当前音乐的种类 void GetAudioEnum() { if (transform.parent.name.StartsWith("GrowUpTower")) { //火元素 audioEnum = AudioEnum.FireTAttack; } else if (transform.parent.name.StartsWith("BlinkTower")) { //木元素 audioEnum = AudioEnum.WoodTAttack; } else if (transform.parent.name.StartsWith("CopyCatTower")) { //水元素 audioEnum = AudioEnum.WaterTAttack; } } void OnDestroy() { towerTargetter.acquiredTarget -= OnAcquiredTarget; // towerTargetter.lostTarget -= OnLostTarget; } 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_Launcher = GetComponent(); } TowerLevel myTower; bool fireState = false; protected void updateTowerSkillData() { HandleBullet(); HandleEnergy(); HandleFreezeBreath(); } // 处理木精灵装填子弹 private void HandleBullet() { // 预留出来装填子弹的时间. if (fillBulletTime > 0) { fillBulletTime -= Time.deltaTime; if (fillBulletTime <= 0.3f) { if (towerPtr && towerPtr.bulletCtl) towerPtr.bulletCtl.ResetToMaxBullet(); } if (fillBulletTime <= 0) { fillBulletTime = 0; } } } // 处理火精灵充能 private void HandleEnergy() { // 充能时间的处理 if (towerPtr && towerPtr.energyCtl) { if (fInEnergy <= 0) { energyCalTime += Time.deltaTime; float process = energyCalTime % 11.0f; int proint = (int)Math.Floor(process); proint += towerPtr.uiProOffset; towerPtr.energyCtl.SetEnergyProcessFloat(process); if (proint == 10) { fireState = true; fInEnergy = finalFireSpeed; myTower.SetFireMatSpeed(true);//设置了火宝石快速攻击 // 设置多倍攻击速度 fBackupTimer = m_FireTimer; m_FireTimer = m_FireTimer / finalFireSpeed; towerPtr.uiProOffset = 0; towerPtr.PlayEnergyEffect(true); } } else { fInEnergy -= Time.deltaTime; if (fInEnergy <= 0) { myTower.SetFireMatSpeed(false);//恢复了火宝石攻击速度 fireState = false; EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd); fInEnergy = 0.0f; energyCalTime = 0.0f; towerPtr.energyCtl.SetEnergyProgress(0); // 恢复正常攻击速度 m_FireTimer = fBackupTimer; towerPtr.PlayEnergyEffect(false); } } } } // 处理水精灵的充能 private void HandleFreezeBreath() { if (towerPtr && towerPtr.FreezeBreathCtrl) { Damager damager = projectile.gameObject.GetComponent(); float finalDamage = damager.damage; List list = EndlessBuffManager.instance.GetBuffListByEffectType(EndlessBuffEffectType.AttackAdd, towerPtr.attributeId); float ratio = 0; float add = 0; if (list.Count > 0) { for (int i = 0; i < list.Count; ++i) { ratio += list[i].Config.buff_effect[1]; add += list[i].Config.buff_effect[2]; } } finalDamage += (ratio / 100f) * finalDamage + add; if (inFreezeBreath <= 0) { freezeBreathCallTime += Time.deltaTime; float process = freezeBreathCallTime % (FreezeBreath.ChargeTime + 1); int processInt = (int)Mathf.Floor(process); processInt += towerPtr.FreezeBreathProgressOffset; towerPtr.FreezeBreathCtrl.SetProgress(process); if (processInt == (int)Mathf.Floor(FreezeBreath.ChargeTime)) { inFreezeBreath = FreezeBreath.EffectTime; towerPtr.FreezeBreathProgressOffset = 0; towerPtr.PlayFreezeBreathEffect(true); towerPtr.FreezeBreathCtrl.ReleaseCount = 1; towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, finalDamage, damager.alignmentProvider); } } else { inFreezeBreath -= Time.deltaTime; if (inFreezeBreath <= FreezeBreath.EffectTime / 2 && towerPtr.FreezeBreathCtrl.ReleaseCount != 2) { towerPtr.FreezeBreathCtrl.ReleaseCount = 2; towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, finalDamage, damager.alignmentProvider); return; } if (inFreezeBreath <= 0) { inFreezeBreath = 0; freezeBreathCallTime = 0; towerPtr.FreezeBreathCtrl.SetProgress(0); towerPtr.PlayFreezeBreathEffect(false); towerPtr.FreezeBreathCtrl.ReleaseCount = 3; towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, finalDamage, damager.alignmentProvider); } } } } /// /// This function is called when the object becomes enabled and active. /// void OnEnable() { if (towerPtr && towerPtr.energyCtl) { if (fireState) { myTower.SetFireMatSpeed(true);//设置了火宝石快速攻击 towerPtr.PlayEnergyEffect(true); } } } /// /// This function is called when the behaviour becomes disabled or inactive. /// void OnDisable() { if (towerPtr && towerPtr.energyCtl) { towerPtr.PlayEnergyEffect(false, false); } if (towerPtr && towerPtr.FreezeBreathCtrl) towerPtr.PlayFreezeBreathEffect(false, false); } /// /// 获取子弹发射时间间隔 /// public float GetFireDuration() { DecreaseTowerAttackCD endlessBuff = (DecreaseTowerAttackCD)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.DecreaseTowerAttackCD); return endlessBuff.GetDecreaseCD(towerPtr.attributeId, 1 / projectileFireRate); } /// /// Update the timers /// protected virtual void Update() { if (m_Launcher == null) return; // 处理当前Affector所在Tower对应的技能 updateTowerSkillData(); m_FireTimer -= Time.deltaTime; m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector); if (m_TrackingEnemy != null && m_FireTimer < 0) { m_FireTimer = GetFireDuration(); if (fInEnergy > 0) m_FireTimer /= finalFireSpeed; towerLevel.FireSpeed = fInEnergy > 0 ? finalFireSpeed : 1f; if (towerPtr && towerPtr.bulletCtl != null) { int bnum = towerPtr.bulletCtl.GetCtlProgress(); if (bnum == 0) return; } if (towerPtr && towerPtr.FreezeBreathCtrl != null) { // 冷冻气息期间不攻击 if (inFreezeBreath > 0.0001f) return; } towerLevel.ChangeState(TowerActionState.Attack); } } /// /// Common logic when attacking /// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标 /// public virtual void FireProjectile() { // 不再处理多子弹攻击,确保只有一个弹道 isMultiAttack = false; m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector); GameObject go = damagerProjectile.gameObject; if (m_TrackingEnemy == null || fillBulletTime > 0) return; // 处理子弹充能相关的内容 if (towerPtr && (towerPtr.bulletCtl != null)) { int bnum = towerPtr.bulletCtl.decBullet(); // 暴击子弹的数量,如果获得相应buff可能会修改暴击子弹数量 int critBulletNum = towerPtr.bulletCtl.CritBulletNum; if (bnum < critBulletNum) { if (bnum == 0) fillBulletTime = 2.0f; //这里需要替换特效 var poolable = Core.Utilities.Poolable.TryGetPoolable(woodProjectile_SP); go = poolable.gameObject; Damager tmpDamager = go.GetComponent(); tmpDamager.damageMulti = 10.0f; tmpDamager.damage = damagerProjectile.damage; } } else { if (towerPtr) towerPtr.setTowerState(true); } if (isMultiAttack) { List enemies = towerTargetter.GetAllTargets(); if ((enemies != null) && (Targetter.bSearchTarget)) m_Launcher.Launch(enemies, projectile, projectilePoints, maxAttackNum); } else { if (Targetter.bSearchTarget) { m_Launcher.Launch(m_TrackingEnemy, go, projectilePoints); if (AudioSourceManager.Ins) AudioSourceManager.Ins.Play(audioEnum); } } 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(); }