using KTGMGemClient; using System; using ActionGameFramework.Health; using Core.Utilities; using TowerDefense.Level; using TowerDefense.Targetting; using TowerDefense.Towers.Placement; using TowerDefense.UI.HUD; using UnityEngine; using TowerDefense.Agents; using System.Collections; using System.Collections.Generic; namespace TowerDefense.Towers { public enum EFeatureTower { NULL, GrowUp, CopyCat, LightTower, Skill_Fire, Skill_Bomb, END } public enum ETowerFuntion { NULL, BULLET, // 子弹塔 ENERGY, // 能量充能. FREEZE, // 水精灵充能 END } /// /// Common functionality for all types of towers /// public class Tower : Targetable { /// /// A generalised name common to a levels /// public string towerName; /// /// The size of the tower's footprint /// public IntVector2 dimensions; /// /// 是否是特色骰子,如果是,则选择一个Enum类型。 /// public EFeatureTower towerFeature = EFeatureTower.NULL; /// /// 塔防对应的充能状态. /// public ETowerFuntion eTowerFuntion = ETowerFuntion.NULL; [HideInInspector] public BulletUICtl bulletCtl = null; [HideInInspector] public EnergyUICtl energyCtl = null; [HideInInspector] public FreezeBreath FreezeBreathCtrl = null; /// /// The tower levels associated with this tower /// [SerializeField] private TowerLevel towerLevel; public TowerLevel CurrentTowerLevel { get; private set; } /// /// 精灵id,一一对应 elf_info表中的id,唯一的区分每一种精灵塔 /// public int ElfId; /// /// The physics mask the tower searches on /// public LayerMask enemyLayerMask; /// /// The current level of the tower /// public int currentLevel { get; set; } protected bool m_bInAttackMode = false; /// /// 攻击增加 /// public float attackRise { get; set; } /// /// 用于界面部分的数据位移 /// protected int progressOffset = 0; public int FreezeBreathProgressOffset { get; set; } public bool PlayWaveLineFlash { get; set; } = true; private bool isBondage; /// /// 是否是泡泡禁锢状态 /// /// public bool IsBondage { get { return isBondage; } set { isBondage = value; CanAttack = !value; } } /// /// 禁锢时间 /// public float BondageTime { get; set; } /// /// 禁锢警告时间 /// /// public float BondageWarningTime { get; set; } /// /// 泡泡禁锢期间,点击一次减少的时间 /// public float BondageClickDecreaseTime { get; set; } = 1f; /// /// 是否是木属性蓄力状态 /// public bool IsWoodCharge { get; set; } /// /// 木属性蓄力瞄准的目标 /// public Agent WoodAimAgent; public int uiProOffset { get { return progressOffset; } set { progressOffset = value; } } /// /// Gets whether the tower can level up anymore /// public bool IsMaxLevel { get { return currentLevel == ElfUpgradeData.MaxTowerLevel - 1; } } /// /// 是否可以攻击 /// public bool CanAttack = true; /// /// 是否是对手塔防 /// public bool opponentSide { get; set; } /// /// 禁锢警告 /// protected GameObject bondageWarningObj; /// /// 禁锢泡泡 /// protected GameObject bondageObj; private GameObject tapObj; /// /// 精灵被禁锢时点击次数 /// public int BondageTapCount { get; private set; } /// /// 泡泡上升高度 /// private float yAdd = 10f; /// /// 原始y值 /// private float originY; /// /// 是否开始禁锢 /// public bool IsStartBondage { get; set; } private float bombDuration = 0.7f; private float bombTime; /// /// 爆炸是否结束 /// private bool isBombCompleted; private void Start() { originY = transform.position.y; promptDic = new Dictionary(); } private void Update() { HandleBondageBubble(); } private static Dictionary promptDic; /// /// 处理禁锢泡泡技能 /// private void HandleBondageBubble() { if (IsStartBondage) { if (isBondage) { if (transform.position.y < yAdd + originY && bondageObj != null) { // 上升状态 Vector3 pos = transform.position; pos.y += 28f * Time.deltaTime; transform.position = pos; pos = bondageObj.transform.position; pos.y += 28f * Time.deltaTime; bondageObj.transform.position = pos; } } else { if (!isBombCompleted) { bombTime += Time.deltaTime; if (bombTime > bombDuration) { // 爆炸结束开始下降 isBombCompleted = true; } } else { if (transform.position.y > originY) { // 下降状态 Vector3 pos = transform.position; pos.y -= 55f * Time.deltaTime; transform.position = pos; } else { // 下降结束 IsStartBondage = false; } } } } if (!IsBondage) return; if (BondageWarningTime > 0) { BondageWarningTime -= Time.deltaTime; if (BondageWarningTime <= 0) { DestroyBondageWarningObj(); StartBondage(); ShowTapPrompt(); } } else { BondageTime -= Time.deltaTime; if (BondageTime <= 0) { DestroyBondageWarningObj(); HideTapPrompt(); IsBondage = false; Destroy(bondageObj); bondageObj = null; BondageBubbleBomb(); } } } private void DestroyBondageWarningObj() { if (bondageWarningObj == null) return; ParticleSystem ps = bondageWarningObj.transform.GetChild(0).GetComponent(); ps.Stop(); ps.Clear(); Destroy(bondageWarningObj); bondageWarningObj = null; } /// /// 展示连续点击提示 /// private void ShowTapPrompt() { string key = $"{gridPosition.x}"; if (promptDic.ContainsKey(key)) return; promptDic.Add(key, true); GameObject prefab = Resources.Load("Prefabs/Endless/BondageBubbleTap"); tapObj = Instantiate(prefab); tapObj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false); Vector3 worldPos = TowerPlacementGridEndless.instance.GetGridWorldPos(gridPosition.x, 3); ParticleSystem ps = tapObj.transform.GetChild(0).GetComponent(); tapObj.transform.position = worldPos; Vector3 pos = tapObj.transform.position; pos.x += 5.8f; pos.z += 3f; pos.y = 20f; tapObj.transform.position = pos; ps?.Play(); } private void HideTapPrompt() { if (tapObj != null) { ParticleSystem ps = tapObj.transform.GetChild(0).GetComponent(); ps?.Stop(); Destroy(tapObj); tapObj = null; string key = $"{gridPosition.x}"; if (promptDic.ContainsKey(key)) promptDic.Remove(key); } } public void OnPressed() { if (!IsStartBondage || BondageWarningTime > 0) return; ++BondageTapCount; if (BondageTapCount >= 3) HideTapPrompt(); BondageTime -= BondageClickDecreaseTime; } /// /// 禁锢泡泡爆炸 /// private void BondageBubbleBomb() { GameObject prefab = Resources.Load("Prefabs/Endless/BondageBubbleBomb"); GameObject obj = Instantiate(prefab); obj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false); obj.transform.position = transform.position; obj.transform.GetChild(0).GetComponent().Play(); Destroy(obj, 1.2f); AudioSourceManager.Ins.StopBossWaterSkill(); } /// /// 开始泡泡禁锢 /// private void StartBondage() { bombTime = 0; BondageTapCount = 0; isBombCompleted = false; GameObject prefab = Resources.Load("Prefabs/Endless/BondageBubble"); bondageObj = Instantiate(prefab); bondageObj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false); bondageObj.transform.position = transform.position; Vector3 pos = bondageObj.transform.position; pos.y += gridPosition.y == 3 ? 2f : 1f; bondageObj.transform.position = pos; bondageObj.transform.GetChild(0).GetComponent().Play(); AudioSourceManager.Ins.Play(AudioEnum.BossWaterSkill); } /// /// 禁锢警告 /// /// public void BondageWarning() { GameObject prefab = Resources.Load("Prefabs/Endless/BondageBubbleWarning"); bondageWarningObj = Instantiate(prefab); bondageWarningObj.transform.SetParent(TowerPlacementGridEndless.instance.GridContainer.transform, false); bondageWarningObj.transform.position = TowerPlacementGridEndless.instance.GetGridWorldPos(gridPosition.x, gridPosition.y); bondageWarningObj.transform.GetChild(0).GetComponent().Play(); } /// /// 播放充能状态特效. /// /// public void PlayEnergyEffect(bool play, bool isClose = true) { if (energyCtl && isClose) energyCtl.gameObject.SetActive(!play); else if (!isClose) { } if (!opponentSide) { if (GameUI.instanceExists) ((TowerPlacementGrid)GameUI.instance.selfTowerPlaceArea).PlayEnergyEffect(gridPosition.x, play); else if (EndlessGameUI.instanceExists) ((TowerPlacementGridEndless)EndlessGameUI.instance.selfTowerPlaceArea).PlayEnergyEffect(gridPosition.x, gridPosition.y, play); } else ((TowerPlacementGrid)OpponentMgr.instance.m_CurrentArea).PlayEnergyEffect(gridPosition.x, play); } /// /// 播放水精灵充能满了特效 /// /// /// public void PlayFreezeBreathEffect(bool play, bool isClose = true) { if (FreezeBreathCtrl && isClose) FreezeBreathCtrl.gameObject.SetActive(!play); if (!opponentSide) { if (EndlessGameUI.instanceExists) ((TowerPlacementGridEndless)EndlessGameUI.instance.selfTowerPlaceArea).PlayFreezeBreathEffect(gridPosition.x, gridPosition.y, play); } } /// /// 当前是否处于攻击模式 /// public bool bInAttackMode { get { return m_bInAttackMode; } // 设置是否处于攻击状态: set { m_bInAttackMode = value; CurrentTowerLevel.SetAffectorState(m_bInAttackMode, gridPosition.x); CurrentTowerLevel.SetAttackState(value); if (value) { if (opponentSide) { OpponentMgr.instance.SetTowerAttID(gridPosition.x, ElfId, currentLevel); } else { if (LevelManager.instanceExists) { LevelManager.instance.SetTowerAttID(gridPosition.x, ElfId, currentLevel); WaveLineSelMgr.instance.attackTowerFixed(gridPosition.x); } else if (EndlessLevelManager.instanceExists) { EndlessLevelManager.instance.SetTowerAttID(gridPosition.x, ElfId, currentLevel); EndlessWaveLineManager.instance.AttackTowerFixed(gridPosition.x, PlayWaveLineFlash); } } // 处理塔位边上的界面. OnTowerUICtrl(); } } } /// /// 去掉当前Tower对应的界面数据. /// public void DisableTowerUICtrl() { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) { buc.gameObject.SetActive(false); bulletCtl = null; } EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) { // 设置数据 euc.gameObject.SetActive(false); energyCtl = null; } FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y); if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null) { ctrl.gameObject.SetActive(false); ctrl = null; } } public int GetTowerUICtrlProgress() { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) return buc.GetCtlProgress(); EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) return euc.GetCtlProgress(); FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y); if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null) return ctrl.CurrentProgress; return 0; } public void SetTowerUICtlProcess(int pro) { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) { buc.SetCtlProcess(pro); progressOffset = pro; return; } EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) { euc.SetCtlProcess(pro); progressOffset = pro; if (progressOffset == 10) progressOffset = 0; return; } FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y); if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null) { ctrl.SetCtrlProgress(pro); FreezeBreathProgressOffset = pro; if (FreezeBreathProgressOffset == 10) FreezeBreathProgressOffset = 0; } } /// /// 充能技能相关的代码开关。包括子弹充能和时间充能 /// protected void OnTowerUICtrl() { HandleBulletUICtrl(); HandleEnergyUICtrl(); HandleFreezeBreathCtrl(); } private void HandleBulletUICtrl() { // 根据是否是子弹塔防来决定是否显示相应的界面 BulletUICtl buc = placementArea.GetBulletUICtl(gridPosition.x, gridPosition.y); if (buc == null) return; if ((eTowerFuntion == ETowerFuntion.BULLET) && (buc != null)) { // 设置数据 buc.gameObject.SetActive(true); bulletCtl = buc; buc.ResetToMaxBullet(); } else { // 清空数据 buc.gameObject.SetActive(false); bulletCtl = null; } } private void HandleEnergyUICtrl() { // 根据是否是能量充能来决定是否显示相应的界面. EnergyUICtl euc = placementArea.GetEnergyUICtl(gridPosition.x, gridPosition.y); if ((eTowerFuntion == ETowerFuntion.ENERGY) && (euc != null)) { // 设置数据 euc.gameObject.SetActive(true); energyCtl = euc; euc.SetEnergyProgress(0); } else { // 清空数据 euc.gameObject.SetActive(false); energyCtl = null; } } private void HandleFreezeBreathCtrl() { FreezeBreath ctrl = placementArea.GetFreezeBreath(gridPosition.x, gridPosition.y); if (eTowerFuntion == ETowerFuntion.FREEZE && ctrl != null) { ctrl.gameObject.SetActive(true); FreezeBreathCtrl = ctrl; ctrl.SetProgress(0); } else { ctrl.gameObject.SetActive(false); FreezeBreathCtrl = null; } } public void CheckCtrl() { if (bulletCtl != null) { bulletCtl.gameObject.SetActive(true); } if (energyCtl != null) { energyCtl.gameObject.SetActive(true); } if (FreezeBreathCtrl != null) FreezeBreathCtrl.gameObject.SetActive(true); } /// /// This function is called when the behaviour becomes disabled or inactive. /// void OnDisable() { if (bulletCtl != null) { bulletCtl.gameObject.SetActive(false); } if (energyCtl != null) { energyCtl.gameObject.SetActive(false); } if (FreezeBreathCtrl != null) FreezeBreathCtrl.gameObject.SetActive(false); } /// /// 升级当前塔防的局内等级,需要播放相关的特效 /// public void upGradeInSceneTL() { Debug.Log("Upgrade Tower name is:" + name); // 播放相关的特效 CurrentTowerLevel.PlayUpGradeEffect(); } /// /// Gets the first level tower ghost prefab /// public TowerPlacementGhost towerGhostPrefab { get { return towerLevel.towerGhostPrefab; } } /// /// Gets the grid position for this tower on the /// public IntVector2 gridPosition { get; private set; } /// /// The placement area we've been built on /// public IPlacementArea placementArea { get; private set; } /// /// The event that fires off when a player deletes a tower /// public Action towerDeleted; /// /// The event that fires off when a tower has been destroyed /// public Action towerDestroyed; /// /// Provide the tower with data to initialize with /// /// The placement area configuration /// The destination position public virtual void Initialize(IPlacementArea targetArea, IntVector2 destination, int lvl = 0) { placementArea = targetArea; gridPosition = destination; if (targetArea != null) { transform.position = placementArea.GridToWorld(destination, dimensions); transform.rotation = placementArea.transform.rotation; targetArea.Occupy(destination, dimensions); } SetLevel(lvl); if (LevelManager.instanceExists) LevelManager.instance.levelStateChanged += OnLevelStateChanged; else if (EndlessLevelManager.instanceExists) EndlessLevelManager.instance.LevelStateChanged += OnLevelStateChanged; // 查找Targetter: Targetter target = GetComponentInChildren(); if (target) target.bOpponent = opponentSide; else Debug.Log("在当前的Tower中找不到Targetter."); } /// /// 当前的Tower是显示还是隐藏,用于减少游戏内Tower创建和删除对应的一系列数据操作 /// /// public void showTower(bool vis) { if (vis) { gameObject.SetActive(true); } else { gameObject.SetActive(false); } } /// /// Kills this tower /// public void KillTower() { // Invoke base kill method Kill(); } /// /// Used to (try to) upgrade the tower data /// public virtual bool UpgradeTower() { if (IsMaxLevel) { return false; } SetLevel(currentLevel + 1); return true; } /// /// A method for downgrading tower /// /// /// false if tower is at lowest level /// public virtual bool DowngradeTower() { if (currentLevel == 0) { return false; } SetLevel(currentLevel - 1); return true; } /// /// Used to set the tower to any valid level /// /// /// The level to upgrade the tower to /// /// /// True if successful /// public virtual bool UpgradeTowerToLevel(int level) { if (level < 0 || IsMaxLevel || level >= ElfUpgradeData.MaxTowerLevel) return false; SetLevel(level); return true; } public void Sell() { Remove(); } /// /// Removes tower from placement area and destroys it /// public override void Remove() { base.Remove(); attackRise = 0.0f; placementArea.Clear(gridPosition, dimensions); Destroy(gameObject); } /// /// unsubsribe when necessary /// protected virtual void OnDestroy() { if (LevelManager.instanceExists) { LevelManager.instance.levelStateChanged += OnLevelStateChanged; } else if (EndlessLevelManager.instanceExists) EndlessLevelManager.instance.LevelStateChanged += OnLevelStateChanged; } /// /// Cache and update oftenly used data /// protected void SetLevel(int level) { if (level < 0 || level >= ElfUpgradeData.MaxTowerLevel) return; currentLevel = level; if (CurrentTowerLevel != null) Destroy(CurrentTowerLevel.gameObject); CurrentTowerLevel = Instantiate(towerLevel, transform); CurrentTowerLevel.Initialize(this, enemyLayerMask, configuration.alignmentProvider); CurrentTowerLevel.SetShowLevel(level + 1); //if(gridPosition.y>=2) { //Debug.Log("上阵状态,设置缩放"); CurrentTowerLevel.SetScale(level + 1); } // disable affectors LevelState levelState = LevelState.Intro; if (LevelManager.instanceExists) levelState = LevelManager.instance.levelState; else if (EndlessLevelManager.instanceExists) levelState = EndlessLevelManager.instance.EndlessLeveltate; bool initialise = levelState == LevelState.AllEnemiesSpawned || levelState == LevelState.SpawningEnemies; initialise = false; CurrentTowerLevel.SetAffectorState(initialise, gridPosition.x); } /// /// Intiailises affectors based on the level state /// protected virtual void OnLevelStateChanged(LevelState previous, LevelState current) { bool initialise = current == LevelState.AllEnemiesSpawned || current == LevelState.SpawningEnemies; initialise = false; CurrentTowerLevel.SetAffectorState(bInAttackMode, gridPosition.x); } } }