using ActionGameFramework.Health;
|
using Core.Utilities;
|
using System;
|
using TowerDefense.Agents;
|
using TowerDefense.UI.HUD;
|
using UnityEngine;
|
|
namespace TowerDefense.Towers.Projectiles
|
{
|
/// <summary>
|
/// Implementation of hitscan projectile
|
/// The principle behind this weapon is that it instantly attacks enemies
|
/// </summary>
|
[RequireComponent(typeof(Damager))]
|
public class HitscanAttack : MonoBehaviour
|
{
|
/// <summary>
|
/// The amount of time to delay
|
/// </summary>
|
public float delay;
|
|
/// <summary>
|
/// 攻击敌人后,重设敌人到开始位置的概率,默认为零,不需要重设。
|
/// </summary>
|
public float resetStartPosRate = 0;
|
|
/// <summary>
|
/// 链式攻击的概率,目前只有一个链式攻击的模式,暂时不需要处理细节,先测试起来
|
/// </summary>
|
public float chainAttackRate = 0;
|
|
/// <summary>
|
/// 当前攻击塔位对应的属性ID
|
/// </summary>
|
public int attributeId = 0;
|
|
/// <summary>
|
/// The delay timer
|
/// </summary>
|
protected Timer m_Timer;
|
|
/// <summary>
|
/// The enemy this projectile will attack
|
/// </summary>
|
protected Targetable m_Enemy;
|
|
/// <summary>
|
/// The Damager attached to the object
|
/// </summary>
|
protected Damager m_Damager;
|
|
/// <summary>
|
/// The towers projectile position
|
/// </summary>
|
protected Vector3 m_Origin;
|
|
/// <summary>
|
/// Configuration for pausing the timer delay timer
|
/// without setting Time.timeScale to 0
|
/// </summary>
|
protected bool m_PauseTimer;
|
|
protected int mLiveID = 0;
|
|
/// <summary>
|
/// 随机数数据
|
/// </summary>
|
protected System.Random mRand;
|
|
|
/// <summary>
|
/// 攻击增加.
|
/// </summary>
|
public float attackRise { get; set; }
|
|
/// <summary>
|
/// The delay configuration for the attacking
|
/// </summary>
|
/// <param name="origin">
|
/// The point the attack will be fired from
|
/// </param>
|
/// <param name="enemy">
|
/// The enemy to attack
|
/// </param>
|
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;
|
}
|
|
/// <summary>
|
/// 处理塔位的属性攻击
|
/// </summary>
|
/// <param name="enemy"></param>
|
/// <param name="attid"></param>
|
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;
|
}
|
|
/// <summary>
|
/// The actual attack of the hitscan attack.
|
/// Early returns from the method if the there is no enemy to attack.
|
/// </summary>
|
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;
|
}
|
|
/// <summary>
|
/// Cache the damager component attached to this object
|
/// </summary>
|
protected virtual void Awake()
|
{
|
m_Damager = GetComponent<Damager>();
|
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;
|
}
|
|
/// <summary>
|
/// Update the m_Timer if it is available
|
/// </summary>
|
protected virtual void Update()
|
{
|
if (!m_PauseTimer)
|
{
|
m_Timer.Tick(Time.deltaTime);
|
}
|
}
|
}
|
}
|