using ActionGameFramework.Health; using Core.Utilities; using DG.Tweening; using System; using System.Net.Http.Headers; using TowerDefense.Agents; using TowerDefense.UI.HUD; using UnityEngine; using System.Collections; 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.addSpeedSlowRate(0.25f); enemy.SetTargetableMatColor(Color.blue); break; case 3: // 中毒 enemy.poisonAgent(damage, attid); enemy.SetTargetableMatColor(Color.green); break; case 5: // 破甲 enemy.bShieldBreak = true; 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; // effects // ParticleSystem pfxPrefab = m_Damager.collisionParticles; // var attackEffect = Poolable.TryGetPoolable(pfxPrefab.gameObject); // attackEffect.transform.position = m_Enemy.position; // attackEffect.Play(); // GameObject hitObj = Poolable.TryGetPoolable(m_Damager.collisionObj); // ParticleSystem ps = hitObj.GetComponent(); // if (ps == null) // ps = hitObj.transform.GetChild(0).GetComponent(); // ps.Play(); // // StartCoroutine(RecycleParticle(hitObj, ps.main.duration)); // var hitVFX = Instantiate(m_Damager.collisionObj, m_Enemy.position, Quaternion.identity); // var ps = hitVFX.GetComponent(); // if (ps == null) // { // var psChild = hitVFX.transform.GetChild(0).GetComponent(); // psChild.Play(); // Destroy(hitVFX, psChild.main.duration); // } // else // { // ps.Play(); // Destroy(hitVFX, ps.main.duration); // } float finalDamage = m_Damager.finalDamage; bool crit = m_Damager.isCrit; if (crit) { finalDamage += finalDamage; // 暂时去掉这个ShakePosition的功能: //m_Enemy.transform.DOShakePosition(0.5f); } // 精英怪和Boss双倍攻击. bool doubleHit = m_Damager.doubleHit && m_Enemy.bElit; if (doubleHit) { finalDamage *= 2; } // // 处理光塔对应的攻击增加: if (attackRise > 0) finalDamage += (finalDamage * attackRise); // 破甲状态 if (m_Enemy.bShieldBreak) finalDamage += (finalDamage * 0.1f); // // 提前处理非当前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, doubleHit); // 播放受击动画: if ((!m_Enemy.isDead) && (m_Enemy.liveID == tid)) (m_Enemy as Agent).PlayOnHit(); // 重设到开始位置的处理. liveID必须要等于tid. /*if( (resetStartPosRate > 0)&&(!m_Enemy.isDead)&& (m_Enemy.liveID == tid)) { if (mRand.NextDouble() < resetStartPosRate) { Agent ag = m_Enemy as Agent; if( ag.bBoss) { // 如果是Boss,更低的概率重设位置. if (mRand.NextDouble() < resetStartPosRate / 20.0f) ag.execAgentPosResetAction(); } else ag.execAgentPosResetAction(); } }*/ /*// 链式攻击的测试处理: 需要确保是同一个敌人,ID相同. if( (chainAttackRate > 0)&& (!m_Enemy.isDead) && (m_Enemy.liveID == tid) ) { if (mRand.NextDouble() < chainAttackRate) AgentInsManager.instance.StartChainAttack(m_Enemy as Agent,m_Damager.alignmentProvider,(float)Math.Floor(finalDamage/2.0f )); }*/ 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); } } } }