chenxin
2020-11-14 62b2779db75575bebd80ffac74fc3f25b5b994fa
Assets/Scripts/TowerDefense/Towers/TowerLevel.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using ActionGameFramework.Health;
using Core.Health;
using KTGMGemClient;
using TowerDefense.Affectors;
using TowerDefense.Towers.Data;
using TowerDefense.UI.HUD;
@@ -8,253 +9,480 @@
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>
    /// 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>
        /// Build effect gameObject to instantiate on start
        /// </summary>
        //public GameObject buildEffectPrefab;
        /// <summary>
        /// 升级特效
        /// </summary>
        public GameObject UpgradeEffectPrefab;
      /// <summary>
      /// 当前的Level对应的DamagerData.
      /// </summary>
      public Damager levelDamager;
        /// <summary>
        /// 当前的Level对应的DamagerData.
        /// </summary>
        public Damager levelDamager;
      /// <summary>
      /// Reference to scriptable object with level data on it
      /// </summary>
      public  TowerLevelData levelData;
        /// <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 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>
        /// The list of effects attached to the tower
        /// </summary>
        Affector[] m_Affectors;
      /// <summary>
      /// TEST CODE: 是否已经缩放.
      /// </summary>
      protected bool bScaleForCombat = false;
        /// <summary>
        /// TEST CODE: 是否已经缩放.
        /// </summary>
        protected bool bScaleForCombat = false;
      /// <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>
        /// 未上阵的形象
        /// </summary>
        public GameObject Body;
      /// <summary>
      /// The physics layer mask that the tower searches on
      /// </summary>
      public LayerMask mask { get; protected set; }
        /// <summary>
        /// 上阵形象
        /// </summary>
        public GameObject AttackBody;
      /// <summary>
      /// Gets the cost value
      /// </summary>
      public int cost
      {
         get { return levelData.cost; }
      }
        /// <summary>
        /// 精灵塔动作状态
        /// </summary>
        public TowerActionState ActionState { get; protected set; }
      /// <summary>
      /// Gets the sell value
      /// </summary>
      public int sell
      {
         get { return levelData.sell; }
      }
        private string paramName = "ActionState";
      /// <summary>
      /// Gets the max health
      /// </summary>
      public int maxHealth
      {
         get { return levelData.maxHealth; }
      }
        /// <summary>
        /// 动作动画器
        /// </summary>
        public Animator ActionAnimator;
      /// <summary>
      /// Gets the starting health
      /// </summary>
      public int startingHealth
      {
         get { return levelData.startingHealth; }
      }
        /// <summary>
        /// 发射子弹速率
        /// </summary>
        protected float fireRate;
      /// <summary>
      /// Gets the tower description
      /// </summary>
      public string description
      {
         get { return levelData.description; }
      }
        /// <summary>
        /// 初始攻击速率
        /// </summary>
        private float attackSpeed = 1f;
      /// <summary>
      /// Gets the tower description
      /// </summary>
      public string upgradeDescription
      {
         get { return levelData.upgradeDescription; }
      }
        /// <summary>
        /// 多倍速攻击速度,基准速度的 N 倍速
        /// </summary>
        private float fireSpeed = 1f;
      /// <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;
         }
         m_ParentTower = tower;
      }
      /// <summary>
      /// 当前的TowerLevel设置为对应怪物的材质显示
      /// </summary>
      /// <param name="mat"></param>
      public void SetTowerMonsterMat( Material mat)
        /// <summary>
        /// 发射倍速,如果设置多倍速攻击,直接修改此属性,恢复之前的攻速直接设置为 1
        /// </summary>
        /// <value></value>
        public float FireSpeed
        {
         if (mat == null) return;
         // 查找子结点:
         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;
               }
            }
         }
      }
            get { return fireSpeed; }
            set
            {
                if (value < 0) value = 0;
      /// <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;
            }
         }
      }
                fireSpeed = value;
                if (ActionState == TowerActionState.Attack)
                    ActionAnimator.speed = attackSpeed * fireSpeed;
            }
        }
      /// <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>
        /// 各个动作的基准播放时长(播放一遍用的时间)
        /// </summary>
        protected float[] actionTimeArr;
      /// <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>
      /// Insntiate the build particle effect object
      /// </summary>
      void Start()
      {
         if (buildEffectPrefab != null)
         {
            Instantiate(buildEffectPrefab, transform);
         }
      }
      /// <summary>
      /// 播放升级特效
      /// </summary>
      public void PlayUpGradeEffect()
        public void ChangeState(TowerActionState state)
        {
         if (buildEffectPrefab != null)
         {
            Instantiate(buildEffectPrefab, transform);
         }
      }
   }
            if (state == ActionState) return;
            ActionState = state;
            if (state == TowerActionState.Attack)
                ActionAnimator.speed = attackSpeed * FireSpeed;
            else if (state == TowerActionState.Standing)
                ActionAnimator.speed = 1f;
            ActionAnimator.SetInteger(paramName, (int)state);
        }
        /// <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;
            }
            m_ParentTower = tower;
        }
        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);
            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);
        }
        private void LateUpdate()
        {
            if (ActionAnimator.isActiveAndEnabled)
            {
                AnimatorStateInfo stateInfo = ActionAnimator.GetCurrentAnimatorStateInfo(0);
                if (ActionState == TowerActionState.Attack && stateInfo.normalizedTime >= 1f)
                    ChangeState(TowerActionState.Standing);
            }
        }
        /// <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)
        {
            Body.SetActive(!isAttackMode);
            AttackBody.SetActive(isAttackMode);
            ActionAnimator.enabled = isAttackMode;
        }
        /// <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);
            }
        }
    }
}