using ActionGameFramework.Health; using Core.Utilities; using System; using TowerDefense.Agents; using TowerDefense.UI.HUD; using UnityEngine; namespace TowerDefense.Towers.Projectiles { /// /// Implementation of hitscan projectile /// The principle behind this weapon is that it instantly attacks enemies /// [RequireComponent(typeof(Damager))] public class HitscanAttack : MonoBehaviour { /// /// The amount of time to delay /// public float delay; /// /// 攻击敌人后,重设敌人到开始位置的概率,默认为零,不需要重设。 /// public float resetStartPosRate = 0; /// /// 链式攻击的概率,目前只有一个链式攻击的模式,暂时不需要处理细节,先测试起来 /// public float chainAttackRate = 0; /// /// 当前攻击塔位对应的属性ID /// public int attributeId = 0; /// /// The delay timer /// protected Timer m_Timer; /// /// The enemy this projectile will attack /// protected Targetable m_Enemy; /// /// The Damager attached to the object /// protected Damager m_Damager; /// /// The towers projectile position /// protected Vector3 m_Origin; /// /// Configuration for pausing the timer delay timer /// without setting Time.timeScale to 0 /// protected bool m_PauseTimer; protected int mLiveID = 0; /// /// 随机数数据 /// protected System.Random mRand; /// /// 攻击增加. /// public float attackRise { get; set; } /// /// The delay configuration for the attacking /// /// /// The point the attack will be fired from /// /// /// The enemy to attack /// public void AttackEnemy(Vector3 origin, Targetable enemy, float delayTime = 0) { m_Enemy = enemy; m_Origin = origin; // 更快的击中目标: if (delayTime > 0) m_Timer.SetTime(delayTime / 4.0f); m_Timer.Reset(); m_PauseTimer = false; mLiveID = enemy.liveID; } /// /// 处理塔位的属性攻击 /// /// /// protected void ProcessTowerAttributeAttack(Targetable enemy, float damage, int attid) { int id = (int)Math.Floor(attid / 10000.0f); switch (id) { case 2: // 减速. (enemy as Agent).addSpeedSlowRate(0.15f); break; case 3: // 中毒 (enemy as Agent).poisonAgent(damage, attid); break; } return; } /// /// The actual attack of the hitscan attack. /// Early returns from the method if the there is no enemy to attack. /// protected void DealDamage() { Poolable.TryPool(gameObject); if (m_Enemy == null) { return; } // 攻击目标已经经历过了Pool了,不能再攻击了。 if (mLiveID != m_Enemy.liveID) return; float finalDamage = m_Damager.finalDamage; bool crit = m_Damager.isCrit; if (crit) { finalDamage += finalDamage; } // 处理光塔对应的攻击增加: if (attackRise > 0) finalDamage += (finalDamage * attackRise); // 提前处理非当前Enemy的爆炸攻击: if (chainAttackRate > 0) AgentInsManager.instance.StartExplodeAttack(m_Enemy as Agent, finalDamage); int tid = m_Enemy.liveID; Vector3 backPos = m_Enemy.position; m_Enemy.TakeDamage(finalDamage, m_Enemy.position, m_Damager.alignmentProvider, attributeId); // 处理塔位的技能攻击: ProcessTowerAttributeAttack(m_Enemy, finalDamage, attributeId); if (!m_Enemy.opponentAgent) GameUI.instance.generateBloodText(backPos, finalDamage, crit); // 播放受击动画: if ((!m_Enemy.isDead) && (m_Enemy.liveID == tid)) (m_Enemy as Agent).PlayOnHit(); m_PauseTimer = true; } /// /// Cache the damager component attached to this object /// protected virtual void Awake() { m_Damager = GetComponent(); float fdelay = delay - 0.05f; if (fdelay < 0) fdelay = 0.0f; m_Timer = new Timer(fdelay, DealDamage); if ((resetStartPosRate > 0) || (chainAttackRate > 0)) mRand = new System.Random(); attackRise = 0.0f; } /// /// Update the m_Timer if it is available /// protected virtual void Update() { if (!m_PauseTimer) { m_Timer.Tick(Time.deltaTime); } } } }