| | |
| | | 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; |
| | | using TowerDefense.Agents; |
| | | using TowerDefense.Level; |
| | | |
| | | namespace TowerDefense.Affectors |
| | | { |
| | |
| | | /// 木塔最后一击是特殊攻击,需要替换projectile |
| | | /// </summary> |
| | | public GameObject woodProjectile_SP; |
| | | // |
| | | protected GameObject projectile1; |
| | | protected GameObject projectile2; |
| | | |
| | | /// <summary> |
| | | /// The list of points to launch the projectiles from |
| | |
| | | public Transform epicenter; |
| | | |
| | | /// <summary> |
| | | /// Configuration for when the tower does splash damage |
| | | /// </summary> |
| | | public bool isMultiAttack; |
| | | |
| | | /// <summary> |
| | | /// 如果是多目标攻击,最多攻击目标 |
| | | /// </summary> |
| | | public int maxAttackNum = 1; |
| | | |
| | | |
| | | /// <summary> |
| | | /// The fire rate in fires-per-second |
| | | /// </summary> |
| | | public float fireRate; |
| | | |
| | | |
| | | /// <summary> |
| | | /// 是否木属性数据 |
| | |
| | | /// </summary> |
| | | protected float m_FireTimer; |
| | | |
| | | protected float freezeBreathTimer; |
| | | |
| | | /// <summary> |
| | | /// Reference to the current tracked enemy |
| | | /// </summary> |
| | | protected Targetable m_TrackingEnemy; |
| | | |
| | | public TowerLevel towerLevel; |
| | | |
| | | /// <summary> |
| | | /// 处理装弹时间. |
| | |
| | | protected float fillBulletTime = 0.0f; |
| | | |
| | | /// <summary> |
| | | /// 充能时间 |
| | | /// 火精灵充能时间 |
| | | /// </summary> |
| | | protected float energyCalTime = 0; |
| | | |
| | | protected float fInEnergy = 0; |
| | | |
| | | protected float fBackupTimer = 0.0f; |
| | | |
| | | /// <summary> |
| | | /// 水精灵的充能时间 |
| | | /// </summary> |
| | | protected float freezeBreathCallTime = 0; |
| | | |
| | | protected float inFreezeBreath; |
| | | |
| | | protected float freezeBreathBackTimer = 0; |
| | | |
| | | private int towerAttributeId; |
| | | |
| | | /// <summary> |
| | | /// 火精灵技能固定攻击倍速 |
| | | /// </summary> |
| | | /// <value></value> |
| | | protected float fireSpeed { get; set; } = 5f; |
| | | |
| | | /// <summary> |
| | | /// 木属性精灵蓄力时间 |
| | | /// </summary> |
| | | protected float woodChargeTime { get; set; } = 1.5f; |
| | | |
| | | protected float woodRemainChargeTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 蓄力特效时间 |
| | | /// </summary> |
| | | protected float woodChargeEffectTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 木属性精灵蓄力特效 |
| | | /// </summary> |
| | | public ParticleSystem WoodChargeEffect; |
| | | |
| | | public Transform WoodChargeTransform; |
| | | |
| | | /// <summary> |
| | | /// 木属性正在瞄准的Agent |
| | | /// </summary> |
| | | protected Agent woodAimAgent; |
| | | |
| | | /// <summary> |
| | | /// 火精灵攻击最终攻击倍速,里面计算了buff增加的倍速 |
| | | /// </summary> |
| | | /// <value></value> |
| | | public float finalFireSpeed |
| | | { |
| | | get |
| | | { |
| | | FireRateAdd fireRateAdd = (FireRateAdd)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.FireRateAdd); |
| | | float rateAdd = 0; |
| | | |
| | | if (fireRateAdd != null) |
| | | rateAdd = fireRateAdd.GetFireSpeedAdd(towerPtr.ElfId); |
| | | return rateAdd > 1 ? rateAdd : fireSpeed; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Gets the search rate from the targetter |
| | | /// </summary> |
| | |
| | | towerTargetter.alignment = affectorAlignment; |
| | | towerTargetter.acquiredTarget += OnAcquiredTarget; |
| | | // towerTargetter.lostTarget += OnLostTarget; |
| | | GetAudioEnum(); |
| | | |
| | | myTower = transform.parent.GetComponent<TowerLevel>(); |
| | | GetAudioEnum(); |
| | | |
| | | } |
| | | private AudioEnum audioEnum;//当前音乐的种类 |
| | | bool isWoodAudio; |
| | | |
| | | void GetAudioEnum() |
| | | { |
| | | if (transform.parent.name.StartsWith("GrowUpTower")) |
| | | //小怪身上也有这个脚本,塔的名字做了更改,所以判断条件需要变成transform.parent.parent |
| | | if (transform.parent.parent != null) |
| | | { |
| | | //火元素 |
| | | audioEnum = AudioEnum.FireTAttack; |
| | | if (transform.parent.parent.name.StartsWith("GrowUpTower")) |
| | | { |
| | | //火元素 |
| | | audioEnum = AudioEnum.FireTAttack; |
| | | } |
| | | else if (transform.parent.parent.name.StartsWith("BlinkTower")) |
| | | { |
| | | //木元素 |
| | | audioEnum = AudioEnum.WoodTAttack; |
| | | } |
| | | else if (transform.parent.parent.name.StartsWith("CopyCatTower")) |
| | | { |
| | | //水元素 |
| | | audioEnum = AudioEnum.WaterTAttack; |
| | | } |
| | | } |
| | | 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.acquiredTarget -= OnAcquiredTarget; |
| | | // towerTargetter.lostTarget -= OnLostTarget; |
| | | } |
| | | |
| | |
| | | get { return projectile == null ? null : projectile.GetComponent<Damager>(); } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// Returns the total projectile damage |
| | | /// </summary> |
| | | public float GetProjectileDamage() |
| | | { |
| | | var splash = projectile.GetComponent<SplashDamager>(); |
| | | float splashDamage = splash != null ? splash.damage : 0; |
| | | return damagerProjectile.finalDamage + splashDamage; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Initialise the RepeatingTimer |
| | | /// </summary> |
| | | protected virtual void SetUpTimers() |
| | | { |
| | | m_FireTimer = 1 / fireRate; |
| | | m_Launcher = GetComponent<ILauncher>(); |
| | | } |
| | | |
| | |
| | | bool fireState = false; |
| | | protected void updateTowerSkillData() |
| | | { |
| | | // |
| | | if (towerLevel != null && towerLevel.ParentTower != null && towerLevel.ParentTower.ElfId == 301) |
| | | HandleBullet(); |
| | | if (towerLevel != null && towerLevel.ParentTower != null && towerLevel.ParentTower.ElfId == 101) |
| | | HandleEnergy(); |
| | | if (towerLevel != null && towerLevel.ParentTower != null && towerLevel.ParentTower.ElfId == 201) |
| | | HandleFreezeBreath(); |
| | | } |
| | | |
| | | // 处理木精灵装填子弹 |
| | | private void HandleBullet() |
| | | { |
| | | if (woodRemainChargeTime > 0f) |
| | | woodRemainChargeTime -= Time.deltaTime; |
| | | |
| | | if (woodChargeEffectTime > 0f) |
| | | { |
| | | woodChargeEffectTime -= Time.deltaTime; |
| | | UpdateWoodAim(); |
| | | |
| | | if (woodChargeEffectTime <= 0) |
| | | { |
| | | towerPtr.IsWoodCharge = false; |
| | | CancelWoodAim(); |
| | | WoodChargeEffect.Stop(); |
| | | } |
| | | } |
| | | |
| | | // 预留出来装填子弹的时间. |
| | | if (fillBulletTime > 0) |
| | | { |
| | |
| | | if (fillBulletTime <= 0.3f) |
| | | { |
| | | if (towerPtr && towerPtr.bulletCtl) |
| | | towerPtr.bulletCtl.resetToMaxBullet(); |
| | | towerPtr.bulletCtl.ResetToMaxBullet(); |
| | | } |
| | | |
| | | if (fillBulletTime <= 0) |
| | |
| | | fillBulletTime = 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // |
| | | /// <summary> |
| | | /// 更新木属性瞄准 |
| | | /// </summary> |
| | | private void UpdateWoodAim() |
| | | { |
| | | // 离得最近的 Agent |
| | | Agent agent = AgentInsManager.instance.GetMinDisAgent(waveLineID, false); |
| | | |
| | | if (agent != null) |
| | | { |
| | | // 还没有瞄准目标,直接分配 |
| | | if (woodAimAgent == null) |
| | | { |
| | | woodAimAgent = agent; |
| | | towerPtr.WoodAimAgent = agent; |
| | | |
| | | if (agent.WoodAimCount == 0) |
| | | agent.PlayWoodAimEffect(); |
| | | |
| | | ++agent.WoodAimCount; |
| | | } |
| | | // 有小怪走到之前瞄准目标的前面 或者 之前瞄准的目标死亡,切换瞄准目标 |
| | | else if (woodAimAgent.Id != agent.Id) |
| | | { |
| | | if (woodAimAgent.WoodAimCount > 0) |
| | | { |
| | | --woodAimAgent.WoodAimCount; |
| | | |
| | | if (woodAimAgent.WoodAimCount == 0) |
| | | woodAimAgent.StopWoodAimEffect(); |
| | | } |
| | | |
| | | woodAimAgent = agent; |
| | | towerPtr.WoodAimAgent = agent; |
| | | |
| | | if (agent.WoodAimCount == 0) |
| | | agent.PlayWoodAimEffect(); |
| | | |
| | | ++agent.WoodAimCount; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 取消木属性瞄准 |
| | | /// </summary> |
| | | private void CancelWoodAim() |
| | | { |
| | | if (woodAimAgent != null) |
| | | { |
| | | if (woodAimAgent.WoodAimCount > 0) |
| | | { |
| | | --woodAimAgent.WoodAimCount; |
| | | |
| | | if (woodAimAgent.WoodAimCount == 0) |
| | | woodAimAgent.StopWoodAimEffect(); |
| | | } |
| | | } |
| | | |
| | | woodAimAgent = null; |
| | | } |
| | | |
| | | // 处理火精灵充能 |
| | | private void HandleEnergy() |
| | | { |
| | | // 充能时间的处理 |
| | | if (towerPtr && towerPtr.energyCtl) |
| | | { |
| | | if (this.fInEnergy <= 0) |
| | | if (fInEnergy <= 0) |
| | | { |
| | | this.energyCalTime += Time.deltaTime; |
| | | energyCalTime += Time.deltaTime; |
| | | float process = energyCalTime % 11.0f; |
| | | int proint = (int)Math.Floor(process); |
| | | proint += towerPtr.uiProOffset; |
| | |
| | | if (proint == 10) |
| | | { |
| | | fireState = true; |
| | | fInEnergy = 5.0f; |
| | | myTower.SetFireMatSpeed(true);//设置了火宝石快速攻击 |
| | | fInEnergy = finalFireSpeed; |
| | | // 设置多倍攻击速度 |
| | | fBackupTimer = m_FireTimer; |
| | | m_FireTimer = m_FireTimer / 3.0f; |
| | | m_FireTimer = m_FireTimer / finalFireSpeed; |
| | | |
| | | towerPtr.uiProOffset = 0; |
| | | towerPtr.PlayEnergyEffect(true); |
| | |
| | | fInEnergy -= Time.deltaTime; |
| | | if (fInEnergy <= 0) |
| | | { |
| | | myTower.SetFireMatSpeed(false);//恢复了火宝石攻击速度 |
| | | |
| | | fireState = false; |
| | | EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd); |
| | | //EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd); |
| | | fInEnergy = 0.0f; |
| | | this.energyCalTime = 0.0f; |
| | | energyCalTime = 0.0f; |
| | | towerPtr.energyCtl.SetEnergyProgress(0); |
| | | |
| | | // 恢复正常攻击速度 |
| | |
| | | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 处理水精灵的充能 |
| | | private void HandleFreezeBreath() |
| | | { |
| | | if (towerPtr && towerPtr.FreezeBreathCtrl) |
| | | { |
| | | Damager damager = projectile.gameObject.GetComponent<Damager>(); |
| | | |
| | | 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 = towerPtr.FreezeBreathCtrl.SkillTime; |
| | | towerPtr.FreezeBreathProgressOffset = 0; |
| | | towerPtr.PlayFreezeBreathEffect(true); |
| | | towerPtr.FreezeBreathCtrl.ReleaseCount = 1; |
| | | towerPtr.FreezeBreathCtrl.PlayFreezeEffect(waveLineID); |
| | | towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, towerPtr, damager.alignmentProvider); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | inFreezeBreath -= Time.deltaTime; |
| | | int time = Mathf.FloorToInt(towerPtr.FreezeBreathCtrl.EffectTime / (towerPtr.FreezeBreathCtrl.DamageCount - 1) * 10); |
| | | int interval = Mathf.FloorToInt(inFreezeBreath * 10); |
| | | int offset = Mathf.FloorToInt(towerPtr.FreezeBreathCtrl.SkillTime * 10) - Mathf.FloorToInt(towerPtr.FreezeBreathCtrl.EffectTime * 10); |
| | | |
| | | if (interval == time * (towerPtr.FreezeBreathCtrl.DamageCount - towerPtr.FreezeBreathCtrl.ReleaseCount - 1) + offset && towerPtr.FreezeBreathCtrl.ReleaseCount < towerPtr.FreezeBreathCtrl.DamageCount) |
| | | { |
| | | ++towerPtr.FreezeBreathCtrl.ReleaseCount; |
| | | towerPtr.FreezeBreathCtrl.ReleaseFreeze(waveLineID, towerPtr, damager.alignmentProvider); |
| | | } |
| | | |
| | | if (inFreezeBreath <= 0) |
| | | { |
| | | inFreezeBreath = 0; |
| | | freezeBreathCallTime = 0; |
| | | towerPtr.FreezeBreathCtrl.SetProgress(0); |
| | | towerPtr.PlayFreezeBreathEffect(false); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | if (fireState) |
| | | { |
| | | myTower.SetFireMatSpeed(true);//设置了火宝石快速攻击 |
| | | |
| | | towerPtr.PlayEnergyEffect(true); |
| | | } |
| | | } |
| | | |
| | | // 如果在木属性蓄力期间,让瞄准动画播放 |
| | | if (towerPtr && towerPtr.IsWoodCharge && woodAimAgent != null) |
| | | woodAimAgent.PlayWoodAimEffect(); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | { |
| | | towerPtr.PlayEnergyEffect(false, false); |
| | | } |
| | | |
| | | if (towerPtr && towerPtr.FreezeBreathCtrl) |
| | | towerPtr.PlayFreezeBreathEffect(false, false); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | protected virtual void Update() |
| | | { |
| | | if (m_Launcher == null) return; |
| | | if (m_Launcher == null || towerPtr != null && !towerPtr.CanAttack) return; |
| | | |
| | | // 处理当前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 / 5.0f; |
| | | } |
| | | } |
| | | m_TrackingEnemy = targetter.GetTarget(waveLineID, bWoodAffector); |
| | | |
| | | /// <summary> |
| | | /// Fired at every poll of the fire rate timer |
| | | /// </summary> |
| | | protected virtual void OnFireTimer() |
| | | { |
| | | if (fireCondition != null) |
| | | if (m_TrackingEnemy != null && m_FireTimer < 0) |
| | | { |
| | | if (!fireCondition()) |
| | | m_FireTimer = towerLevel.GetFireRate(); |
| | | |
| | | if (fInEnergy > 0) |
| | | m_FireTimer /= finalFireSpeed; |
| | | |
| | | towerLevel.FireSpeed = fInEnergy > 0 ? finalFireSpeed : 1f; |
| | | |
| | | if (towerPtr && towerPtr.bulletCtl != null) |
| | | { |
| | | return; |
| | | int bnum = towerPtr.bulletCtl.GetCtlProgress(); |
| | | |
| | | // 蓄力时间内不攻击 |
| | | if (bnum == 0 || woodRemainChargeTime > 0f) return; |
| | | } |
| | | |
| | | if (towerPtr && towerPtr.FreezeBreathCtrl != null) |
| | | { |
| | | // 冷冻气息期间不攻击 |
| | | if (inFreezeBreath > 0.0001f) return; |
| | | } |
| | | |
| | | towerLevel.ChangeState(TowerActionState.Attack); |
| | | } |
| | | FireProjectile(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Common logic when attacking |
| | | /// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标 |
| | | /// </summary> |
| | | protected virtual void FireProjectile() |
| | | public 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); |
| | | } |
| | | |
| | | GameObject go = damagerProjectile.gameObject; |
| | | GameObject go = projectile; |
| | | |
| | | if (m_TrackingEnemy == null || fillBulletTime > 0) return; |
| | | |
| | | Damager goDamager = go.GetComponent<Damager>(); |
| | | goDamager.IsEnhancedBullet = false; |
| | | goDamager.TowerPtr = towerPtr; |
| | | |
| | | // 处理子弹充能相关的内容 |
| | | if (towerPtr && (towerPtr.bulletCtl != null)) |
| | | if (towerPtr && towerPtr.bulletCtl != null) |
| | | { |
| | | int bnum = towerPtr.bulletCtl.decBullet(); |
| | | // |
| | | if (bnum == 0) |
| | | // 暴击子弹的数量,如果获得相应buff可能会修改暴击子弹数量 |
| | | int critBulletNum = towerPtr.bulletCtl.CritBulletNum; |
| | | |
| | | if (bnum < critBulletNum) |
| | | { |
| | | //damagerProjectile.damageMulti = 10.0f; |
| | | fillBulletTime = 2.0f; |
| | | if (bnum == 0) |
| | | // 不需要装填时间 |
| | | fillBulletTime = 0.1f; |
| | | |
| | | //这里需要替换特效 |
| | | var poolable = Core.Utilities.Poolable.TryGetPoolable<Core.Utilities.Poolable>(woodProjectile_SP); |
| | | go = poolable.gameObject; |
| | | //go = Instantiate(woodProjectile_SP); |
| | | Damager tmpDamager = go.GetComponent<Damager>(); |
| | | tmpDamager.damageMulti = 10.0f; |
| | | tmpDamager.damage = damagerProjectile.damage; |
| | | tmpDamager.IsEnhancedBullet = true; |
| | | tmpDamager.TowerPtr = towerPtr; |
| | | isWoodAudio = true; |
| | | } |
| | | |
| | | } |
| | | else |
| | | { |
| | | if (this.towerPtr) |
| | | towerPtr.setTowerState(true); |
| | | } |
| | | |
| | | if (isMultiAttack) |
| | | { |
| | | List<Targetable> enemies = towerTargetter.GetAllTargets(); |
| | | if ((enemies != null) && (Targetter.bSearchTarget)) |
| | | m_Launcher.Launch(enemies, projectile, projectilePoints, this.maxAttackNum); |
| | | } |
| | | else |
| | | { |
| | | if (Targetter.bSearchTarget) |
| | | // 下一颗子弹是强化子弹,然后直接蓄力 |
| | | if (bnum - 1 >= 0 && bnum - 1 < critBulletNum) |
| | | { |
| | | m_Launcher.Launch(m_TrackingEnemy, go, projectilePoints); |
| | | if (AudioSourceManager.Ins) |
| | | AudioSourceManager.Ins.Play(audioEnum); |
| | | woodRemainChargeTime = woodChargeTime; |
| | | towerPtr.IsWoodCharge = true; |
| | | DecreaseWoodChargeTime decreaseWoodChargeTime = (DecreaseWoodChargeTime)EndlessBuffManager.instance.GetBuffInstanceByType(EndlessBuffEffectType.DecreaseWoodChargeTime); |
| | | |
| | | if (decreaseWoodChargeTime != null) |
| | | woodRemainChargeTime = decreaseWoodChargeTime.GetWoodChargeTime(woodChargeTime); |
| | | |
| | | woodChargeEffectTime = woodRemainChargeTime + 0.5f / towerLevel.ActionAnimator.speed; |
| | | WoodChargeEffect.Play(); |
| | | } |
| | | } |
| | | if (randomAudioSource != null) |
| | | |
| | | if (Targetter.bSearchTarget) |
| | | { |
| | | if (Targetter.bSearchTarget) |
| | | randomAudioSource.PlayRandomClip(); |
| | | m_Launcher.Launch(m_TrackingEnemy, go, projectilePoints); |
| | | if (AudioSourceManager.Ins) |
| | | { |
| | | if (isWoodAudio) |
| | | { |
| | | isWoodAudio = false; |
| | | AudioSourceManager.Ins.Play(AudioEnum.WoodSkill); |
| | | } |
| | | else |
| | | { |
| | | AudioSourceManager.Ins.Play(audioEnum); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |