using System.Collections.Generic;
|
using ActionGameFramework.Health;
|
using Core.Health;
|
using KTGMGemClient;
|
using TowerDefense.Affectors;
|
using TowerDefense.Towers.Data;
|
using TowerDefense.UI.HUD;
|
using UnityEngine;
|
|
namespace TowerDefense.Towers
|
{
|
/// <summary>
|
/// An individual level of a tower
|
/// </summary>
|
[DisallowMultipleComponent]
|
public class TowerLevel : MonoBehaviour, ISerializationCallbackReceiver
|
{
|
/// <summary>
|
/// The prefab for communicating placement in the scene
|
/// </summary>
|
public TowerPlacementGhost towerGhostPrefab;
|
|
/// <summary>
|
/// Build effect gameObject to instantiate on start
|
/// </summary>
|
//public GameObject buildEffectPrefab;
|
|
/// <summary>
|
/// 升级特效
|
/// </summary>
|
public GameObject UpgradeEffectPrefab;
|
|
/// <summary>
|
/// 当前的Level对应的DamagerData.
|
/// </summary>
|
public Damager levelDamager;
|
|
/// <summary>
|
/// Reference to scriptable object with level data on it
|
/// </summary>
|
public TowerLevelData levelData;
|
|
/// <summary>
|
/// The parent tower controller of this tower
|
/// </summary>
|
protected Tower m_ParentTower;
|
|
/// <summary>
|
/// The list of effects attached to the tower
|
/// </summary>
|
Affector[] m_Affectors;
|
|
/// <summary>
|
/// TEST CODE: 是否已经缩放.
|
/// </summary>
|
protected bool bScaleForCombat = false;
|
|
/// <summary>
|
/// 未上阵的形象
|
/// </summary>
|
public GameObject Body;
|
|
/// <summary>
|
/// 上阵形象
|
/// </summary>
|
public GameObject AttackBody;
|
|
/// <summary>
|
/// 精灵塔动作状态
|
/// </summary>
|
public TowerActionState ActionState { get; protected set; }
|
|
private string paramName = "ActionState";
|
|
/// <summary>
|
/// 动作动画器
|
/// </summary>
|
public Animator ActionAnimator;
|
|
/// <summary>
|
/// 发射子弹速率
|
/// </summary>
|
protected float fireRate;
|
|
/// <summary>
|
/// 初始攻击速率
|
/// </summary>
|
private float attackSpeed = 1f;
|
|
/// <summary>
|
/// 多倍速攻击速度,基准速度的 N 倍速
|
/// </summary>
|
private float fireSpeed = 1f;
|
|
/// <summary>
|
/// 发射倍速,如果设置多倍速攻击,直接修改此属性,恢复之前的攻速直接设置为 1
|
/// </summary>
|
/// <value></value>
|
public float FireSpeed
|
{
|
get { return fireSpeed; }
|
set
|
{
|
if (value < 0) value = 0;
|
|
fireSpeed = value;
|
|
if (ActionState == TowerActionState.Attack)
|
ActionAnimator.speed = attackSpeed * fireSpeed;
|
}
|
}
|
|
/// <summary>
|
/// 各个动作的基准播放时长(播放一遍用的时间)
|
/// </summary>
|
protected float[] actionTimeArr;
|
|
/// <summary>
|
/// Gets the list of effects attached to the tower
|
/// </summary>
|
protected Affector[] Affectors
|
{
|
get
|
{
|
if (m_Affectors == null)
|
{
|
m_Affectors = GetComponentsInChildren<Affector>();
|
}
|
return m_Affectors;
|
}
|
}
|
|
/// <summary>
|
/// The physics layer mask that the tower searches on
|
/// </summary>
|
public LayerMask mask { get; protected set; }
|
|
/// <summary>
|
/// Gets the cost value
|
/// </summary>
|
public int cost
|
{
|
get { return levelData.cost; }
|
}
|
|
/// <summary>
|
/// Gets the sell value
|
/// </summary>
|
public int sell
|
{
|
get { return levelData.sell; }
|
}
|
|
/// <summary>
|
/// Gets the max health
|
/// </summary>
|
public int maxHealth
|
{
|
get { return levelData.maxHealth; }
|
}
|
|
/// <summary>
|
/// Gets the starting health
|
/// </summary>
|
public int startingHealth
|
{
|
get { return levelData.startingHealth; }
|
}
|
|
/// <summary>
|
/// Gets the tower description
|
/// </summary>
|
public string description
|
{
|
get { return levelData.description; }
|
}
|
|
/// <summary>
|
/// Gets the tower description
|
/// </summary>
|
public string upgradeDescription
|
{
|
get { return levelData.upgradeDescription; }
|
}
|
|
|
/// <summary>
|
/// Initialises the Effects attached to this object
|
/// </summary>
|
public virtual void Initialize(Tower tower, LayerMask enemyMask, IAlignmentProvider alignment)
|
{
|
mask = enemyMask;
|
|
foreach (Affector effect in Affectors)
|
{
|
effect.Initialize(alignment, mask);
|
effect.towerPtr = tower;
|
AttackAffector attackAffector = effect.GetComponent<AttackAffector>();
|
|
if (attackAffector.projectile != null)
|
{
|
Damager damager = attackAffector.projectile.gameObject.GetComponent<Damager>();
|
damager.TowerAttributeId = tower.attributeId;
|
}
|
}
|
m_ParentTower = tower;
|
Transform starTs = transform.Find("Star");
|
starTs.localPosition = new Vector3(0, 0.2f, 0.6f);
|
starTs.localRotation = Quaternion.Euler(60, 180, 0);
|
}
|
|
private Transform mat;
|
private MeshRenderer myRender;
|
|
Vector3 normalScale;
|
|
private void Awake()
|
{
|
mat = transform.Find("Cube");
|
myRender = mat.GetComponent<MeshRenderer>();
|
normalScale = new Vector3(1.5f, 1.5f, 1.5f);
|
}
|
|
private void Start()
|
{
|
if (ActionAnimator != null)
|
{
|
AnimationClip[] clips = ActionAnimator.runtimeAnimatorController.animationClips;
|
actionTimeArr = new float[clips.Length];
|
|
for (int i = 0; i < clips.Length; ++i)
|
{
|
if (clips[i].name == "Standing")
|
actionTimeArr[0] = clips[i].length;
|
else if (clips[i].name == "Attack")
|
actionTimeArr[1] = clips[i].length;
|
}
|
|
GameObject affectorObj = transform.Find("Affector").gameObject;
|
AttackAffector attackAffector = affectorObj.GetComponent<AttackAffector>();
|
fireRate = attackAffector.FireRate;
|
|
if (actionTimeArr[1] > 1 / fireRate)
|
{
|
// 动画时间比攻击长
|
attackSpeed = actionTimeArr[1] * fireRate;
|
}
|
SetAttackState(false);
|
}
|
}
|
|
public void LateUpdate()
|
{
|
if (ActionAnimator == null || !ActionAnimator.isActiveAndEnabled) return;
|
|
AnimatorStateInfo stateInfo = ActionAnimator.GetCurrentAnimatorStateInfo(0);
|
|
if (ActionState == TowerActionState.Attack && stateInfo.normalizedTime >= 1f)
|
ChangeState(TowerActionState.Standing);
|
}
|
|
public void ChangeState(TowerActionState state)
|
{
|
if (ActionAnimator == null || !ActionAnimator.isActiveAndEnabled) return;
|
|
ActionState = state;
|
|
if (ActionState == TowerActionState.Attack && state == TowerActionState.Attack)
|
{
|
ActionAnimator.Update(0);
|
ActionAnimator.Play("Attack", 0, 0);
|
}
|
ActionAnimator.SetInteger(paramName, (int)state);
|
|
if (state == TowerActionState.Attack)
|
ActionAnimator.speed = attackSpeed * FireSpeed;
|
else if (state == TowerActionState.Standing)
|
ActionAnimator.speed = 1f;
|
}
|
|
/// <summary>
|
/// 未上阵塔缩放,固定缩放
|
/// </summary>
|
public void NormalScale()
|
{
|
mat.localScale = normalScale;
|
mat.localPosition = Vector3.zero;
|
}
|
|
private bool isAttack;
|
/// <summary>
|
/// 设置火宝石攻速
|
/// </summary>
|
/// <param name="isAttack"></param>
|
public void SetFireMatSpeed(bool isFast)
|
{
|
if (isFast && isAttack)
|
{
|
myRender.material.SetFloat("_Speed", 40);
|
}
|
else
|
{
|
//还原10
|
myRender.material.SetFloat("_Speed", 8);
|
}
|
}
|
/// <summary>
|
/// 上阵塔缩放
|
/// </summary>
|
public void ResetScale()
|
{
|
if (transform.name.StartsWith("GrowUpTower"))
|
{
|
//火元素
|
mat.localScale = GameConfig.fireScale;
|
mat.localPosition = GameConfig.fireOffectp;
|
}
|
else if (transform.name.StartsWith("BlinkTower"))
|
{
|
//木元素
|
mat.localScale = GameConfig.woodScale;
|
mat.localPosition = GameConfig.woodOffectp;
|
|
}
|
else if (transform.name.StartsWith("CopyCatTower"))
|
{
|
//水元素
|
//mat.localScale = woodScale;
|
|
Vector3 scale = mat.localScale;
|
|
if (!this.bScaleForCombat)
|
{
|
scale.z *= 1.267f;
|
mat.localScale = scale;
|
Vector3 pos = mat.localPosition;
|
pos.z -= 0.2f;
|
mat.localPosition = pos;
|
bScaleForCombat = true;
|
}
|
}
|
}
|
|
|
/// <summary>
|
/// 当前的TowerLevel设置为对应怪物的材质显示
|
/// </summary>
|
/// <param name="mat"></param>
|
public void SetTowerMonsterMat(Material material, bool isAttack)
|
{
|
if (material == null) return;
|
|
this.isAttack = isAttack;
|
myRender.material = material;
|
if (isAttack)
|
{
|
if (transform.name.StartsWith("GrowUpTower") || transform.name.StartsWith("BlinkTower"))
|
{
|
float t = Mathf.Floor(Time.time);
|
float offect = t % 8;
|
myRender.material.SetFloat("_ChangeTime", Mathf.Floor(Time.time - offect));
|
|
}
|
}
|
else
|
{
|
myRender.material.SetFloat("_ChangeTime", Mathf.Floor(Time.time));
|
}
|
|
//Debug.Log("当前时间Time.time:"+Time.time);
|
// if (transform.name.StartsWith("GrowUpTower") && mat.localPosition != fireOffectp)
|
// {
|
// mat.localPosition = fireOffectp;
|
// }
|
// else if (transform.name.StartsWith("BlinkTower") && mat.localPosition != woodOffectp)
|
// {
|
// //木元素
|
// mat.localPosition = woodOffectp;
|
// }
|
// // 查找子结点:
|
// foreach (Transform t in transform.GetComponentsInChildren<Transform>())
|
// {
|
// if (t.name == "Cube")
|
// {
|
// t.GetComponent<MeshRenderer>().material = mat;
|
// //Vector3 scale = t.localScale;
|
|
// // if (!this.bScaleForCombat)
|
// // {
|
// // scale.z *= 1.267f;
|
// // t.localScale = scale;
|
// // Vector3 pos = t.localPosition;
|
// // pos.z -= 0.2f;
|
// // t.localPosition = pos;
|
// // bScaleForCombat = true;
|
// // }
|
// }
|
// }
|
}
|
|
/// <summary>
|
/// A method for activating or deactivating the attached <see cref="Affectors"/>
|
/// </summary>
|
public void SetAffectorState(bool state, int waveline)
|
{
|
foreach (Affector affector in Affectors)
|
{
|
if (affector != null)
|
{
|
affector.enabled = state;
|
affector.waveLineID = waveline;
|
}
|
}
|
}
|
|
|
/// <summary>
|
/// Returns a list of affectors that implement ITowerRadiusVisualizer
|
/// </summary>
|
/// <returns>ITowerRadiusVisualizers of tower</returns>
|
public List<ITowerRadiusProvider> GetRadiusVisualizers()
|
{
|
List<ITowerRadiusProvider> visualizers = new List<ITowerRadiusProvider>();
|
foreach (Affector affector in Affectors)
|
{
|
var visualizer = affector as ITowerRadiusProvider;
|
if (visualizer != null)
|
{
|
visualizers.Add(visualizer);
|
}
|
}
|
return visualizers;
|
}
|
|
/// <summary>
|
/// Returns the dps of the tower
|
/// </summary>
|
/// <returns>The dps of the tower</returns>
|
public float GetTowerDps()
|
{
|
float dps = 0;
|
foreach (Affector affector in Affectors)
|
{
|
var attack = affector as AttackAffector;
|
if (attack != null && attack.damagerProjectile != null)
|
{
|
dps += attack.GetProjectileDamage() * attack.FireRate;
|
}
|
}
|
return dps;
|
}
|
|
public void Kill()
|
{
|
m_ParentTower.KillTower();
|
}
|
|
public void OnBeforeSerialize()
|
{
|
}
|
|
|
/// <summary>
|
/// 获取当前TowerLevel对应的AttackRise.
|
/// </summary>
|
public float attackRise { get { return m_ParentTower.attackRise; } }
|
|
public void OnAfterDeserialize()
|
{
|
// Setting this member to null is required because we are setting this value on a prefab which will
|
// persists post run in editor, so we null this member to ensure it is repopulated every run
|
m_Affectors = null;
|
}
|
|
/// <summary>
|
/// 设置上阵和非上阵状态下,塔的自身形象
|
/// </summary>
|
/// <param name="isAttackMode"></param>
|
public void SetAttackState(bool isAttackMode)
|
{
|
if (isAttackMode)
|
{
|
AttackBody.SetActive(isAttackMode);
|
Body.SetActive(!isAttackMode);
|
ChangeState(TowerActionState.Attack);
|
}
|
else
|
{
|
ChangeState(TowerActionState.Standing);
|
}
|
}
|
|
/// <summary>
|
/// 播放升级特效
|
/// </summary>
|
public void PlayUpGradeEffect()
|
{
|
if (UpgradeEffectPrefab != null)
|
{
|
GameObject obj = Instantiate(UpgradeEffectPrefab);
|
obj.transform.position = gameObject.transform.position;
|
ParticleSystem ps = obj.GetComponent<ParticleSystem>();
|
|
if (ps == null)
|
ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>();
|
|
Vector3 pos = obj.transform.position;
|
pos.y = 5f;
|
obj.transform.position = pos;
|
ps.Play();
|
Destroy(obj, ps.main.duration);
|
}
|
}
|
}
|
}
|