using System;
|
using System.Collections.Generic;
|
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;
|
|
namespace TowerDefense.Affectors
|
{
|
/// <summary>
|
/// 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
|
/// </summary>
|
[RequireComponent(typeof(ILauncher))]
|
public class AttackAffector : Affector, ITowerRadiusProvider
|
{
|
/// <summary>
|
/// The projectile used to attack
|
/// </summary>
|
public GameObject projectile;
|
|
//
|
protected GameObject projectile1;
|
protected GameObject projectile2;
|
|
/// <summary>
|
/// The list of points to launch the projectiles from
|
/// </summary>
|
public Transform[] projectilePoints;
|
|
/// <summary>
|
/// The reference to the center point where the tower will search from
|
/// </summary>
|
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>
|
public bool bWoodAffector = false;
|
|
/// <summary>
|
/// The audio source to play when firing
|
/// </summary>
|
public RandomAudioSource randomAudioSource;
|
|
/// <summary>
|
/// Gets the targetter
|
/// </summary>
|
public Targetter towerTargetter;
|
|
/// <summary>
|
/// Color of effect radius visualization
|
/// </summary>
|
public Color radiusEffectColor;
|
|
/// <summary>
|
/// Search condition
|
/// </summary>
|
public Filter searchCondition;
|
|
/// <summary>
|
/// Fire condition
|
/// </summary>
|
public Filter fireCondition;
|
|
/// <summary>
|
/// The reference to the attached launcher
|
/// </summary>
|
protected ILauncher m_Launcher;
|
|
/// <summary>
|
/// The time before firing is possible
|
/// </summary>
|
protected float m_FireTimer;
|
|
/// <summary>
|
/// Reference to the current tracked enemy
|
/// </summary>
|
protected Targetable m_TrackingEnemy;
|
|
/// <summary>
|
/// 处理装弹时间.
|
/// </summary>
|
protected float fillBulletTime = 0.0f;
|
|
/// <summary>
|
/// 充能时间
|
/// </summary>
|
protected float energyCalTime = 0;
|
protected float fInEnergy = 0;
|
protected float fBackupTimer = 0.0f;
|
/// <summary>
|
/// Gets the search rate from the targetter
|
/// </summary>
|
public float searchRate
|
{
|
get { return towerTargetter.searchRate; }
|
set { towerTargetter.searchRate = value; }
|
}
|
|
/// <summary>
|
/// Gets the targetable
|
/// </summary>
|
public Targetable trackingEnemy
|
{
|
get { return m_TrackingEnemy; }
|
}
|
|
/// <summary>
|
/// Gets or sets the attack radius
|
/// </summary>
|
public float effectRadius
|
{
|
get { return towerTargetter.effectRadius; }
|
}
|
|
public Color effectColor
|
{
|
get { return radiusEffectColor; }
|
}
|
|
public Targetter targetter
|
{
|
get { return towerTargetter; }
|
}
|
|
/// <summary>
|
/// Initializes the attack affector
|
/// </summary>
|
public override void Initialize(IAlignmentProvider affectorAlignment)
|
{
|
Initialize(affectorAlignment, -1);
|
}
|
|
/// <summary>
|
/// 返回可能存在的Targetter.
|
/// </summary>
|
/// <returns></returns>
|
public override TowerDefense.Targetting.Targetter GetTargetter()
|
{
|
return targetter;
|
}
|
|
/// <summary>
|
/// Initialises the attack affector with a layer mask
|
/// </summary>
|
public override void Initialize(IAlignmentProvider affectorAlignment, LayerMask mask)
|
{
|
base.Initialize(affectorAlignment, mask);
|
SetUpTimers();
|
|
towerTargetter.ResetTargetter();
|
towerTargetter.alignment = affectorAlignment;
|
towerTargetter.acquiredTarget += OnAcquiredTarget;
|
towerTargetter.lostTarget += OnLostTarget;
|
}
|
|
void OnDestroy()
|
{
|
towerTargetter.acquiredTarget -= OnAcquiredTarget;
|
towerTargetter.lostTarget -= OnLostTarget;
|
}
|
|
void OnLostTarget()
|
{
|
m_TrackingEnemy = null;
|
}
|
|
void OnAcquiredTarget(Targetable acquiredTarget)
|
{
|
m_TrackingEnemy = acquiredTarget;
|
}
|
|
public Damager damagerProjectile
|
{
|
get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
|
}
|
|
public Damager damagerProjectile1
|
{
|
get { return projectile == null ? null : projectile.GetComponent<Damager>(); }
|
}
|
|
public Damager damagerProjectile2
|
{
|
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>();
|
}
|
|
|
protected void updateTowerSkillData()
|
{
|
//
|
// 预留出来装填子弹的时间.
|
if (fillBulletTime > 0)
|
{
|
fillBulletTime -= Time.deltaTime;
|
if (fillBulletTime <= 0.3f)
|
{
|
if (towerPtr && towerPtr.bulletCtl)
|
towerPtr.bulletCtl.resetToMaxBullet();
|
}
|
|
if (fillBulletTime <= 0)
|
{
|
fillBulletTime = 0;
|
}
|
}
|
|
//
|
// 充能时间的处理
|
if( towerPtr && towerPtr.energyCtl)
|
{
|
if( this.fInEnergy <= 0)
|
{
|
this.energyCalTime += Time.deltaTime;
|
float process = energyCalTime % 11.0f;
|
int proint = (int)Math.Floor(process);
|
proint += towerPtr.uiProOffset;
|
towerPtr.energyCtl.SetEnergyProcessFloat( process );
|
if (proint == 10)
|
{
|
fInEnergy = 5.0f;
|
|
// 设置多倍攻击速度
|
fBackupTimer = m_FireTimer;
|
m_FireTimer = m_FireTimer / 3.0f;
|
|
towerPtr.uiProOffset = 0;
|
towerPtr.PlayEnergyEffect(true);
|
}
|
}
|
else
|
{
|
fInEnergy -= Time.deltaTime;
|
if( fInEnergy <= 0)
|
{
|
EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.FireTowerChargeEnd);
|
fInEnergy = 0.0f;
|
this.energyCalTime = 0.0f;
|
towerPtr.energyCtl.SetEnergyProgress(0);
|
|
// 恢复正常攻击速度
|
m_FireTimer = fBackupTimer;
|
|
towerPtr.PlayEnergyEffect(false);
|
|
}
|
}
|
|
}
|
}
|
|
/// <summary>
|
/// Update the timers
|
/// </summary>
|
protected virtual void Update()
|
{
|
// 处理当前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 / 3.0f;
|
}
|
}
|
|
/// <summary>
|
/// Fired at every poll of the fire rate timer
|
/// </summary>
|
protected virtual void OnFireTimer()
|
{
|
if (fireCondition != null)
|
{
|
if (!fireCondition())
|
{
|
return;
|
}
|
}
|
FireProjectile();
|
}
|
|
/// <summary>
|
/// Common logic when attacking
|
/// 调用攻击的核心函数,由这个函数发起真正的攻击,多目标或者单目标
|
/// </summary>
|
protected 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);
|
}
|
|
//
|
// 处理子弹充能相关的内容
|
if( towerPtr && (towerPtr.bulletCtl != null))
|
{
|
int bnum = towerPtr.bulletCtl.decBullet();
|
//
|
if (bnum == 0)
|
{
|
damagerProjectile.damageMulti = 2.0f;
|
fillBulletTime = 2.0f;
|
}
|
}
|
|
if (isMultiAttack)
|
{
|
List<Targetable> enemies = towerTargetter.GetAllTargets();
|
if( (enemies != null)&&(Targetter.bSearchTarget) )
|
m_Launcher.Launch(enemies, projectile, projectilePoints,this.maxAttackNum);
|
}
|
else
|
{
|
if(Targetter.bSearchTarget )
|
m_Launcher.Launch(m_TrackingEnemy, damagerProjectile.gameObject, projectilePoints);
|
}
|
if (randomAudioSource != null)
|
{
|
if( Targetter.bSearchTarget )
|
randomAudioSource.PlayRandomClip();
|
}
|
}
|
|
/// <summary>
|
/// A delegate to compare distances of components
|
/// </summary>
|
/// <param name="first"></param>
|
/// <param name="second"></param>
|
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
|
/// <summary>
|
/// Draws the search area
|
/// </summary>
|
void OnDrawGizmosSelected()
|
{
|
Gizmos.DrawWireSphere(epicenter.position, towerTargetter.effectRadius);
|
}
|
#endif
|
}
|
|
/// <summary>
|
/// A delegate for boolean calculation logic
|
/// </summary>
|
public delegate bool Filter();
|
}
|